Python社区  »  docker

【学习笔记】学习Docker,看完这篇超详细的教程就足够了

Coder_Oldou • 1 月前 • 61 次点击  

本文为观看B站狂神的视频学习Docker时所整理的笔记,中间加了一些自己的理解,如果对大家有所帮助,还希望点赞支持一下,后续我会继续将自己遇到的Docker问题以及学习的新的知识全部整理添加到本文后面或者整理发布新的文章,如果感兴趣可以关注一波。

Docker的概述

在这里插入图片描述
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker的官网地址 https://www.docker.com/
文档地址 https://docs.docker.com/
仓库地址 https://hub.docker.com/

为什么需要Docker?

传统的开发问题

  • 环境(切换/配置)麻烦
    在开发一个产品的途中,时常会出现的问题就是:“在我的电脑上可以运行,而到了另外一个开发人员的电脑上就不能使用的问题”,或者是因为版本更新导致服务不可用等等,这对于运维人员来说,压力十分大,而环境配置是一个非常头疼的问题,每一个机器都需要部署环境(Redis集群、ES…)十分麻烦且费时费力,并且配置的环境不能跨平台,非常不方便。
  • 应用之间的冲突(隔离性)
    假如我们将开发的两个应用部署到同一个服务器上,如果一个应用出了问题,导致CPU出问题上升到了100%,那么第二个应用也会受到关联;并且如果两个应用分别使用不同的语言或者技术栈,当安装在同一个服务器上的时候可能就会造成 各种冲突/无法兼容 ,到时候调试就非常头疼。如下图所示:

Docker的出现解决以上问题

  • 关于环境问题解决方案
    Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。将环境构建打包成一个 镜像 发布到网上,想要用这个环境的时候就直接拉取一份就OK了。

  • 解决应用之间隔离问题
    Docker核心思想就是使用容器化技术, 打包装箱 ,每个箱子是互相隔离的。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。如下图所示:
    在这里插入图片描述

简述虚拟机和Docker容器的区别

这里引用知乎上大佬的说法: https://www.zhihu.com/question/48174633
服务器虚拟化解决的核心问题是资源调配,而容器解决的核心问题是应用开发、测试和部署。

  • 使用Docker容器和使用虚拟机在运行多个相互隔离的应用时对比,Docker要简洁很多;
  • Docker守护进程可以直接与主操作系统进行通信,为各个Docker容器分配资源;它还可以将容器与主操作系统隔离,并将各个容器互相隔离。
  • 虚拟机启动需要数分钟,而Docker容器可以在数毫秒内启动。由于没有臃肿的从操作系统,Docker可以节省大量的磁盘空间以及其他系统资源。
  • 虚拟机更擅长于彻底隔离整个运行环境。例如,云服务提供商通常采用虚拟机技术隔离不同的用户。而Docker通常用于隔离不同的应用,例如前端,后端以及数据库。
  • 传统的虚拟机,首先是虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件;
  • Docker容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻巧了很多;

Docker中的DevOps(开发、运维)

(1) 应用更快速的交付和部署

  • 传统:一堆的帮助文档和安装程序
  • Docker:打包镜像发布测试,一键运行

(2) 更快捷的升级和扩缩容

  • 使用了Docker以后我们部署应用就像搭积木一样;
  • 项目打包成一个镜像

(3) 更简单的系统运维

  • 在容器话之后我们的开发、测试环境都是高度一致的

(4) 更高效的计算资源利用

  • Docker是内核级别的虚拟化,可以再一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致。

Docker的基本组成

在这里插入图片描述

  • 镜像(image) :docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像—>run---->tomcat01容器(提供服务),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中运行的)。

  • 容器(container) :docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的,启动、停止、删除、基本命令,目前就可以把这个容器理解为就是一个简易的Linux系统。

  • 仓库(repository) :仓库就是存放镜像的地方,仓库分为公有仓库和私有仓库,Docker Hub(默认是国外的)、阿里云…都有容器服务器(配置镜像加速)

Docker的安装

前期准备(看看即可)

不一样的话也行,主要是看Centos的版本
运行环境 :阿里云服务器 Centos 7
连接工具 :XShell 5
需要掌握 Linux的基本命令
由于这里的运行环境是Centos 7,与Centos 6的命令还是有一些区别的,但是区别不大,后面我会将命令详细的介绍。

查看环境

  • 系统内核是3.10以上的
[root@oldou ~]#  uname -r
3.10.0-957.21.3.el7.x86_64
  • 1
  • 2
  • 1
  • 2
  • 查看系统的版本:
    cat /etc/os-release
    在这里插入图片描述

开始安装

这里可以参考官网的帮助文档进行安装
在这里插入图片描述
在这里插入图片描述
地址: https://docs.docker.com/engine/install/centos/

第一步:卸载旧版本(运行以下代码即可)

 yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述
第二步:安装yum工具包
命令: yum install -y yum-utils

第三步:设置镜像仓库

yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo   
    # 这里默认是国外的,十分的慢,我们用以下阿里云的地址
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo   
    # 这是阿里云的docker镜像地址,建议使用这个 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述
更新一下yum索引:
命令: yum makecache fast
在这里插入图片描述
第四步:安装Docker
docker-ce:社区版 ee:企业版
命令: yum install docker-ce docker-ce-cli containerd.io
在这里插入图片描述
注意 :以上是安装Docker最新的版本,如果想要安装指定的版本,就需要进行以下命令:
yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
这里的 <VERSION_STRING> 表示版本。
在这里插入图片描述
第五步:启动Docker
命令: systemctl start docker
注意 :Centos6使用的是 service ,而Centos7使用的都变成了 systemctl

第六步:查看Docker是否安装成功
命令: docker version
在这里插入图片描述
查看Docker的状态: systemctl status docker
在这里插入图片描述
第七步:测试hello-word
命令: docker run hello-world
在这里插入图片描述
第八步:查看一下刚刚下载的hello-word的这个镜像
命令: docker images
在这里插入图片描述

如何卸载Docker(了解即可)

官网中有介绍,下面我给出来:
第一步:卸载依赖
命令: yum remove docker-ce docker-ce-cli containerd.io

第二步:删除资源 安装的资源都在/var/lib/docker目录下
命令: rm -rf /var/lib/docker

这样就OK了。

配置阿里云镜像加速

由于我们拉取镜像的时候,使用国外的下载太慢了,当然我们这里是使用国内阿里云的,所以肯定比国外的访问和下载快,这个时候再配个加速器就美滋滋。

第一步:登录我们的阿里云控制台,然后找到容器镜像服务
在这里插入图片描述
第二步:找到镜像加速器---->镜像加速地址
在这里插入图片描述
第三步:配置使用(直接复制命令运行即可)

(1) 在服务器中创建一个目录 sudo mkdir -p /etc/docker

(2) 编辑配置文件

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://7ih0bv9h.mirror.aliyuncs.com"]
}
EOF
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
(3) 将服务重启: sudo systemctl daemon-reload

(4) 启动docker: sudo systemctl restart docker

这样就配置完成了。

Run的流程以及Docker原理

回顾hello-word的流程
在这里插入图片描述
就拿我们运行hello-word来说,一开始我们运行hello-word的时候,Docker会在本机中寻找镜像,而本机中没有这个镜像,所以就回去我们配置的Hub上去下载镜像,如果找到了就将镜像下载到本地运行,如果没有就返回错误。如下所示:
在这里插入图片描述
底层原理

(1)Docker是怎么工作的?

  • Docker是一个Client-Server结构的系统,Docker的守护进程运行在本机上(运行在后台,和mysql一样),通过Socket从客户端访问。
  • DockerServer接收到Docker-Client的指令,就会执行这个命令。
    在这里插入图片描述
    (2)Docker为什么比虚拟机(VM)快?
    在这里插入图片描述
  • Docker利用的是宿主机的内核,VM需要的是Guest OS
    所以说,新建一个容器的时候,Docker不需要像虚拟机那样重新加载一个操作系统内核,避免引导,虚拟机是加载Guest OS,是分钟级别的,而Docker利用的是宿主机的操作系统,省略了这个复杂的过程。
    在这里插入图片描述

Docker的常用命令

官方帮助文档: https://docs.docker.com/engine/reference/run/

查看信息和帮助命令

命令: docker version # 查看docker的版本信息
在这里插入图片描述
命令: docker info # 显示Docker的系统信息,包括镜像和容器的数量

命令: docker xxx --help #帮助命令,可以显示docker的所有命令

镜像命令

查看镜像
命令: docker images # 查看所有本地的主机上的镜像
在这里插入图片描述

REPOSITORY  :镜像的仓库源
TAG					 :镜像的标签
IMAGE ID		 :镜像的ID
CERATED		 :镜像的创建时间
SIZE				 :镜像的大小

docker  images  [可选项]
-a    , --all        # 列出所有镜像
-q	   , --quiet    # 只显示镜像的ID
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

搜索镜像
命令: docker search 镜像名 # 搜索镜像

可选项,通过搜过过滤
 --filter-STARS=3000   #搜索出来的镜像修饰STARS大于3000的
  • 1
  • 2
  • 1
  • 2

在这里插入图片描述
下载镜像
命令: docker pull 镜像名 [:tag] # 下载镜像,默认是下载最新版 latest 。
在这里插入图片描述
如果是下载指定版本的镜像,那么就需要指定 :版本号 ,如下所示:
docker pull mysql:5.7 # 指定版本下载 下载mysql5.7

删除镜像

# 删除镜像  -f就是全部删除,后面的条件是根据什么来删除,这里是根据容器的id进行删除
docker  rmi -f  容器id   

# 删除多个镜像
docker  rmi -f  容器id  容器id 容器id    

# 删除所有的镜像 
docker  rmi -f $(docker images -aq)  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

容器命令

说明 :我们有了镜像才可以去创建容器,Linux,下载一个centos镜像来进行学习。

下载centos镜像
命令: docker pull centos

新建容器并启动
命令: docker run [可选参数] image

参数说明:
--name="Name" : 容器名字 ,tomcat01、tomcat02,用来区分容器
-d :后台方式运行                                
-it:使用交互方式运行,进入容器查看内容
-p :指定容器的端口   -p  8080:8080  
        -p     ip:主机端口:容器端口                                
        -p     主机端口:容器端口(常用方式)
        -p     容器端口                                                     
        容器端口                                                             
-p: 随机指定端口     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

测试,启动并进入容器
命令: docker run -it centos /bin/bash #启动容器
命令: ls # 查看容器内的centos,基础版本,很多命令都是不完善的
命令: exit # 从容器中退回到主机

列出所有运行中的容器
命令: docker ps [可选参数] # 列出当前正在运行的程序

-a             #列出当前正在运行的容器+带出历史运行过的容器
-n=?      #显示最近创建的容器  
-p            #只显示容器的编号
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在这里插入图片描述

退出容器
命令:

exit                     # 直接停止容器并退出
Ctrl + P + Q             # 容器不停止退出
  • 1
  • 2
  • 1
  • 2

删除容器

docker rm  容器id        # 删除指定的容器,不能删除正在运行的容器
docker rm -f $(docker ps -aq)       # 删除所有的容器   
docker ps -a -q|xargs docker rm     # 删除所有的容器
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

启动和容器的操作

docker start 容器id                  # 启动容器
docker restart 容器id                # 重启容器
docker stop 容器id                   # 停止正在运行的容器
docker kill 容器id                   # 强制停止当前正在运行的容器 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

常用的其他命令

后台启动容器

命令: docker run -d 镜像名

docker run -d centos            # 后台启动centos
  • 1
  • 1
  • 问题:使用 docker ps 查看,发现 centos停止了

  • 常见的坑:docker容器使用后台运行的时候就必须要一个前台线程,不然docker发现没有应用就会自动停止

  • 例如:nginx容器启动后,发现自己没有提供服务就会立刻停止,就是没有程序了。

查看系统CPU状态

命令: docker stats [容器id]
在这里插入图片描述

查看日志

命令: docker logs -tf --tail 容器 ,没有日志

  • 编写一段shell脚本
docker run -d centos /bin/sh -c "while true; do echo oldouTest;sleep 1;done"
  • 1
  • 1
  • 使用 docker ps 去查看
  • 显示日志 : docker logs -tf --tail number 容器id
-tf                  #显示日志
--tail number        #要显示日志条数 

例如:docker logs -tf --tail 10 容器id
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

查看容器中进程信息

命令: docker top 容器id

查看镜像中的元数据

命令: docker inspect 容器id

进入当前正在运行的容器

我们的容器通常都是使用后台方式运行的,需要进入容器,修改一些配置
方式一:
命令: docker exec -it 容器id bashShell
例如:docker exec -it bb6ddb943ea5 /bin/bash
在这里插入图片描述
方式二:
命令: docker attach 容器id
在这里插入图片描述
两种方式的对比

  • docker exec : 进入容器后开启一个新的终端,可以在里面操作(常用)
  • docker attach :进入容器正在执行的终端,不会启动新的进程

从容器中拷贝文件到主机上

在这里插入图片描述

# 进入到容器内:
[root@oldou home]# docker exec -it bb6ddb943ea5 /bin/bash  
[root@bb6ddb943ea5 /]# cd home
[root@bb6ddb943ea5 home]# ls

# 创建一个java文件
[root@bb6ddb943ea5 home]# touch Test.java 
[root@bb6ddb943ea5 home]# ls
Test.java

# 退出容器回到主机
[root@bb6ddb943ea5 home]# exit
exit

#查看当前运行的容器
[root@oldou home]# docker ps

# 将容器内/home目录下的Test.java文件拷贝到主机的home目录下
[root@oldou home]# docker cp bb6ddb943ea5:/home/Test.java /home
[root@oldou home]# ls
Test.java
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

拷贝只是一个手动的过程,后面学习了 -v 卷的技术时,可以实现同步数据

常用命令小结

在这里插入图片描述

命令 英文描述 中文意思
attach Attach to a running container 当前shell下attach连接指定运行镜像
build Build an image from a Dockerfile 通过Dockerfile定制镜像
commit Create a new image from a container changes 提交当前容器为新的境像
cp copy files/folders from the containers filesystem to the host path 从容器中拷贝指定文件或者目录到宿主机中
create Create a new container 创建一个新的容器,同run.但不启动容器
diff Inspect changes on a container’s filesystem 查看docker容器变化
events Get real time events from the server 从docker服务中获取容器实时事件
export Stream the contents of a container as a tar archive 导出容器的内容流作为一个 tar归档文件[对应import]
history Show the history of an image 展示一个境像形成历史
images List images 列出系统当前所有镜像
import Create a new filesystem image from the contents of a tarball 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information 显示系统相关信息
inspect Return low-level information on a container 查看容器详细信息
kill Kill a running container kill指定docker容器
load Load an image from a tar archive 从—个 tar包中加载一个镜像[对应save]
login Register or Login to the docker registry server 注册或者登陆一个docker源服务器
logout Log out from a Docker registry server 从当前Docker registry退出
logs Fetch the logs of a container 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT 查看映射端口对应的容器内部源端
pause Pause all processes within a container 暂停容器
ps List containers 列出容器列表
pull Pull an image or a repository from the docker registry server 从docker镜像服务器中拉取指定镜像或者库镜像
push push an image or a repository to the docker registry server 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container 重启运行的容器
rm Remove one or more containers 移除—个或者多个容器
rmi Remove one or more images 移除一个或多个境像[无容器使用该镜像才可删除,否则需删除相关容器才可能继续或者 -f 强制删除
run Run a command in a new container 创建—个新的容器并运行一个命令
save Save an image to a tar arehive 保存一个镜像为—个tar包「对应load]
search Search for an image on the Docker Hub 在docker hub中搜索镜像
start start a stopped containers 启动容器
stop stop a stopped containers 停止容器
tag Tag an image into a repository 给源中镜像打标签
top Lookup the running processes of a container 查看容器中运行的进程信息
unpause Unpause a paused container 取消暂停容器
version show the docker version information 查看docker版本号
wait Block until a container stops,then print its exit code 截取容器停止时的退出状态值

练习

练习一:使用Docker安装Nginx

官网: https://hub.docker.com/_/nginx

第一步:搜索镜像(这里建议去docker Hub上查找一下版本信息,上面还有帮助文档介绍)
命令: docker search nginx

第二步:下载镜像
命令: docker pull nginx

第三步:查看镜像并且启动
命令: docker images # 查看所有镜像

** 命令: docker run -d --name nginx01 -p 3344:80 nginx

-d 表示后台运行,--name 表示给容器起名字,而nginx01表示起的名字,
-p 宿主机端口 :容器内部端口

后面的3344表示主机开发的3344端口,80表示容器内部的端口,这里表示将80端口映射到外部的3344,
可以通过公网的3344访问到docker里面的80端口,后面的nginx表示的是镜像名字。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
第四步:查看容器并且运行测试
命令: docker ps #查看是否启动
命令: curl localhost:3344
在这里插入图片描述
关闭防火墙 systemctl stop firewalld

到这一步的时候我们就可以使用 公网ip:3344 在浏览器访问了
在这里插入图片描述
第五步:进入Nginx容器
命令: docker exec -it nginx01 /bin/bash #进入容器

命令: whereis nginx

命令: cd /etc/nginx

命令: ls查看

命令: exit #退出

命令: docker stop 容器id #停止Nginx容器
在这里插入图片描述
端口暴露的概念:
在这里插入图片描述
思考问题 :我们每次改动nginx配置文件,都需要进入容器内部?十分的麻烦,我要是可以在容器外部提供一个映射路径,达到在容器修改文件名,容器内部就可以自动修改?
使用 -v数据卷。

练习二:使用Docker部署Tomcat

官网: https://hub.docker.com/_/tomcat

方式一:

  • 官方给出的命令:
    docker run -it --rm tomcat:9.0 # 下载并启动
    上面介绍Nginx的启动都是后台启动,停止了容器以后,容器还是可以查到,并且占用着配置的端口。
    使用官方给出的 docker run -it --rm tomcat:9.0 ,一般用于测试,用完停止就删除

方式二:
还是使用之前的方式。

  • 第一步:搜索镜像(这里建议去docker Hub上查找一下版本信息,上面还有帮助文档介绍)
    命令: docker search tomcat

  • 第二步:下载镜像
    命令: docker pull tomcat # 这是下载最新版的tomcat
    命令: docker pull tomcat:7.0 # 指定版本号

  • 第三步:查看镜像并且启动
    命令: docker images # 查看所有镜像
    命令: docker run -d --name tomcat01 -p 3355:8080 tomcat:7.0

-d 表示后台运行,--name 表示给容器起名字,而tomcat01表示起的名字,
-p 宿主机端口 :容器内部端口

后面的3355表示主机开发的3355端口,8080表示容器内部的端口,这里表示将8080端口映射到外部的3355,
可以通过公网的3355访问到docker里面的8080端口,后面的tomcat表示的是镜像名字。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们这个时候去浏览器访问发现,报了404异常,那我们进入到tomcat容器内部查看一下原因.

  • 第四步:进入容器查看原因
    命令: docker exec -it tomcat01 /bin/bash
    当我们使用 ll 命令时竟然不能使用,只能使用 ls 命令查看,同时进入到webapps目录下发现这个目录竟然是空的。

发现问题:
1、Linux的命令少了;
2、webapps目录下没有文件;

原因:
阿里云的镜像默认是最小的镜像,它把所有不必要的都剔除掉了。保证最小可运行的环境。

解决办法:
在tomcat目录下有一个 webapps.dist 目录,这个目录下有我们所需要的文件,也就是webapps目录所需要的文件,我们将这个文件中的内容全部拷贝到webapps下。

  • 第五步:拷贝资源
    命令: cp -r webapps.dist/* webapps

这样我们再去浏览器中去访问就可以访问到了。

思考问题 :我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,webapps ,我们在外部放置项目,就自动同步到内部就好了!

练习三:使用Docker部署Elasticsearch、Kibana

由于暂时没有学过Elasticsearch,所以暂时没有做这个部分的笔记,只是暂时看了一遍,后续补上…

【2020.10.06 02:52更新】

Docker镜像原理

镜像是什么?

镜像是一种轻量级的、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的所有内容,包括代码、运行时、库、环境变量和配置文件等等。

如何得到镜像?

  • 从远程仓库下载镜像
  • 从朋友那里拷贝镜像
  • 自己制作一个镜像

Docker镜像加载原理

(1)UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以讲不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。 Union文件系统是Docker镜像的基础 。镜像可以通过分层来进行集成,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

(2) Docker镜像加载原理

  • docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统叫做 UnionFS .

  • bootfs(boot file system) 主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

  • rootfs (root file system) ,在bootfs之上。包含的就是典型Linux系统中的/dev,/proc, /bin,letc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。|
    在这里插入图片描述
    提问 :平时我们安装虚拟机的Centos都是好几个G的,为什么Docker里面的Centos镜像只有200M左右呢?
    在这里插入图片描述
    回答 :对于一个精简的OS, rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别,因此不同的发行版可以公用bootfs.

虚拟机是分钟级别的,而容器是秒级别的,区别就是因为以上解释。

镜像原理之分层理解

(1)分层的镜像
当我们去下载一个镜像的时候,注意观察下载的日志输出,可以看到的是镜像是一层一层的下载的,如下所示:
在这里插入图片描述
思考 :为什么Docker镜像要采用这种分层的结构呢?

  • 最大的好处就是资源共享,例如多个镜像都是从相同的Base镜像构建而来的,那么 宿主机只需要在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务卡,而且每一层都可以被共享 。就像上图中的第一项,就是base镜像,说明已经存在该镜像了,所以就不需要下载了。

而查看镜像分层的方式我们可以通过 docker image inspect 命令去查看

理解:
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在这里插入图片描述
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
在这里插入图片描述
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
在这里插入图片描述

  • 这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

  • Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

  • Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

  • Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1]。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
在这里插入图片描述

特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部,这一次就是我们通常说的容器层,容器之下的都叫镜像层。
在这里插入图片描述

Commit镜像(如何提交一个自己的镜像)

命令: docker commit #提交一个新的副本
命令和git原理类似
格式为: docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG版本号]

练习 :封装一个Tomcat镜像

# 1、启动一个默认的tomcat;
# 2、发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认webapps下面是没有文件的;
# 3、我自己拷贝进去了基本的文件;

注意:前面三步不熟悉的话可以看上面的tomcat练习。

# 4、将我们操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像
命令:docker commit -a="oldou" -m="add webapps app" 容器的ID tomcat02:版本号
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述
如果想要保存当前容器的状态,那么就可以通过 commit 来进行提交,获取一个镜像,这就好比VM的快照。

注意

学到这里的时候,才算入门Docker,接下来想要对Docker了解更深,就继续往后学吧。


Docker容器数据卷的使用

什么是容器数据卷?

Docker的理念回顾 :将应用和环境打包成一个镜像,如果数据都在容器中,那么当我们容器被删除的时候,数据就会丢失。【 需求:数据可以持久化 】。假如MYSQL数据库,如果容器被删除了,那么数据库内的数据就会丢失,因此我们希望: MySQL数据库中的数据可以存储在本地

容器之间可以有一个数据共享的技术,Docker容器中产生的数据可以同步到本地。这就是卷技术,目录的挂载:就是将容器内的目录挂载到Linux上面。
在这里插入图片描述
总结:容器的持久化和同步操作,容器间也是数据共享的。


如何使用数据卷?

方式一:直接使用命令来挂载 -v
命令格式: docker run -it -v 主机目录 : 容器内目录

测试

  • 第一步:我们使用以下命令连接容器,并且将Linux的/home/ceshi目录和容器内的/home目录连接起来,如果没有ceshi目录就会自动创建一个。
    命令: docker run -it -v /home/ceshi:/home centos /bin/bash
    在这里插入图片描述
    做完以上的操作,这个时候我们在容器内对 /home 目录下的操作会被同步到Linux的 /home/ceshi 目录下

  • 第二步:当容器启动起来的时候,我们在Linux的操作命令窗口处通过 docker inspect 容器id 去查看卷的挂载信息
    命令: docker inspect centos容器的id
    在这里插入图片描述
    以上两个目录的数据会进行同步,例如我在主机内的ceshi目录下做一些操作【增、删、改等等】会同步到docker容器内的home目录下。

注意 :如果没有上图中的这个挂载项,就说明挂载失败了,重新再挂载一下。下面我们进行数据同步测试。

测试文件同步

1、测试容器中的数据会不会同步到主机中
在这里插入图片描述
测试内容 :我们在容器内的home目录下创建一个test.java文件,然后我们在主机内的/home/ceshi目录下查看是否有这个文件。
在这里插入图片描述
结果证明 ,我们在容器中做了一个添加test.java文件的操作,数据会被同步到主机的对应目录下,这就是双向绑定。

2、测试主机中的数据会不会同步到容器中

  • 我们先停止容器
    在这里插入图片描述
  • 在主机上修改test.java文件内容【vim test.java】
    在这里插入图片描述
  • 启动容器
    在这里插入图片描述
    结果证明了,容器内的数据依旧是同步的。

好处:我们以后修改只需要在本地修改即可,容器内会自动同步!【2020.10.07 15:54更新】

实战:MySQL同步数据

我们来实现一下将MySQL容器中的数据同步到我们的Linux中,同时实现用Windows电脑上的Navicat连接上Linux上的MySQL容器。

官网: https://hub.docker.com/_/mysql

思考:Mysql的数据持久化的问题

  • 第一步:获取镜像,这里以mysql5.7为例
    命令: docker pull mysql:5.7
    在这里插入图片描述
    然后开两个窗口:
    在这里插入图片描述

  • 第二步:运行容器,需要做数据挂载,同时安装MySQL需要配置密码
    官方给出的测试代码: docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag 【参考】

运行命令: docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

 -d           表示后台运行
 -p           表示端口映射
 -v           表示卷挂载
 -e           表示环境配置
 --name       表示容器名字
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
另开一个窗口进行查看
在这里插入图片描述

  • 第三步:启动成功以后我们在本地使用Navicat连接测试一下
    【注意:Navicat —> 连接到服务器的3310 ----> 3310 和 容器内的3306映射 ---- > 这个时候就连接成功了】
    在这里插入图片描述
    【注意】如果连接失败,记得去查看一下是不是防火墙没关【systemctl stop firewalld】或者是服务器的安全组3310端口没配置。

  • 第四步:在本地创建一个数据库进行测试,查看一下我们映射的路径是否OK。
    原先的主机数据库目录:
    在这里插入图片描述
    然后我在Navicat上创建了这个数据库
    在这里插入图片描述
    再次查看:
    在这里插入图片描述
    发现数据已经挂载到本地了,测试OK。

  • 第五步:假如我们将mysql干掉会怎么样?数据还能不能同步?
    在这里插入图片描述
    我们再去另外一个窗口看看我们的数据
    在这里插入图片描述
    我们发现挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能!

具名挂载和匿名挂载

匿名挂载

通过【 -v 容器内路径 】 而没有指定卷名或者指定主机路径的挂载方式
运行以下命令【注意:需要将本机已下载的nginx镜像删除】
命令: docker run -d -P --name nginx02 -v /etc/nginx nginx

同时通过docker volume --help查看一下卷的帮助文档
在这里插入图片描述
分别是:创建卷、查看卷、查看所有的卷、移除卷、移除卷

我们使用以下命令查看一下所有本地的volume【卷】信息:
命令: docker volume ls
在这里插入图片描述
通过以上我们发现,我们刚刚创建的匿名卷挂载,就是没有给它起名字,这是因为我们在运行的时候只指定了容器内的路径而没有指定容器外的路径和卷名,这里发现,这种就是匿名挂载,我们在-v只写了容器内的路径,没有写容器外的路径!

具名挂载

通过【 -v 卷名:容器内路径 】 而没有指定主机路径的挂载方式
运行以下命令
命令: docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx nginx

我们使用以下命令查看一下所有本地的volume【卷】信息:
命令: docker volume ls
在这里插入图片描述
我们通过【 docker volume inspect juming-nginx 】命令查看一下这个卷的详细信息
在这里插入图片描述
我们发现所有的docker容器内的卷,在没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data

通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的 具名挂载

 # 如何锁定是具名挂载还是匿名挂载,还是指定路径挂载

 -v  容器内路径                    # 匿名挂载
 -v  卷名:容器内路径                # 具名挂载
 -v  /宿主机路径:容器内路径          #指定路径挂载
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

扩展

# 通过 -v 容器内路径:ro    rw   改变读写权限
ro      readonly         # 只读
rw     readwrite        # 可读可写

# 一旦设置了容器权限,容器对我们挂载出咯哎的内容就会有限定了
docker run -d  -p --name  nginx02  -v  juming-nginx:/etc/nginx:ro  nginx
docker run -d  -p --name  nginx02  -v  juming-nginx:/etc/nginx:rw  nginx 

# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

数据卷之初识Dockerfile(方式二)

Dockerfile就是用来创建docker镜像的构建文件,是一个命令脚本,下面我们来初步体验一下Dockerfile。

通过这个脚本可以生成镜像,镜像是一层一层的,脚本也是一个一个的命令,每个命令都是一层。

  • 第一步:在home目录下创建一个docker-test-volume目录用于存放脚本测试文件
命令:mkdir docker-test-volume     # 创建一个目录
命令:cd docker-test-volume          # 进入该目录

# 创建一个dockerfile文件,名字可以随意,建议Dockerfile
命令:vim Dockerfile01                   # 编写脚本 

# 文件中的内容,指令需要大写
FROM  centos                       # 用什么作为基础

VOLUME  ["volume01","volume02"]    # 挂载卷的目录,这里没有指定

CMD echo "-------end-------"       # 生成完之后发一段消息

CMD /bin/bash                      # 生成完之后默认是走的控制台

# 这里的每个命令就是镜像的一层
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

查看一下文件的内容:【 cat dockerfile01
在这里插入图片描述

  • 第二步:构建脚本生成镜像
    命令: docker build -f /home/docker-test-volume/dockerfile01 -t oldou/centos:1.0 .
-f   通过什么文件来构建,后面接构建文件的地址
-t   生成文件的版本
  • 1
  • 2
  • 1
  • 2

在这里插入图片描述

  • 第三步:启动自己的容器
    命令: docker run -it db89686baa5c /bin/bash
    命令: ls -l
    在这里插入图片描述
    我们在编写脚本时什么都没写,所以挂载方式为匿名挂载,而这个卷和外部有一个同步的目录,我们去查看一下。
    我们现在容器内创建一个文件:
    在这里插入图片描述
    然后进行后续操作。

  • 第四步:查看一下卷挂载的路径
    命令: docker ps # 先查看一下启动的id
    命令: docker inspect 7a9c7b088444 # 根据容器启动的ID查看信息
    在这里插入图片描述

  • 第五步:进入这个路径查看一下卷信息
    命令: cd /var/lib/docker/volumes/642be56674ca60230a61455cdb8b06e8968ea7dd11236129a906c1cafaa7fe73/_data
    在这里插入图片描述
    刚刚在容器内创建的文件已经在主机中同步了。测试OK。

结论 Dockerfile这种方式的使用非常多见 ,因为我们通常会构建自己的镜像。假如我们构建镜像的时候没有挂载卷,这个时候就需要手动镜像挂载,就需要使用【 -v 卷名:容器内路径

数据卷容器

在这里插入图片描述
这里的 centos02 --volumes-from centos01 就相当于 son extends father

这里的笔记正在完善中,请稍等…

结论 :

  • 容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
  • 一旦你持久化到了本地,这个时候,本地的数据是不会删除的!

DockerFile的学习

Dockerfile的介绍

Dockerfile是用来构建dokcer镜像的文件,是一个命令参数脚本。
构建步骤∶

  • 1、编写一个dockerfile文件
  • 2、docker build构建成为一个镜像
  • 3、docker run运行镜像
  • 4、docker push发布镜像(DockerHub、阿里云镜像仓库)

例如Centos 7的镜像就是一个 GitHub地址
在这里插入图片描述
很多官方的镜像都是基础包,很多功能都没有,我们通常会自己搭建自己的镜像。
官方既然可以制作镜像,那么我们也可以去构建自己的镜像。

DockerFile 的构建过程

所需知识:

  • 每个保留关键字(指令)都必须是大写字母;
  • 执行顺序是从上往下依次执行;
  • # 表示注释;
  • 每一个指令都会创建提交一个新的镜像层,并提交。
    在这里插入图片描述

Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockfile文件,这个文件十分简单。
Docker镜像逐渐成为企业交付的标准,因此必须要掌握。

步骤:开发、部署、运维…缺一不可

  • Dockerfile :构建文件,定义了一切步骤,源代码;
  • DockerImages :通过Dockerfile构建生成的镜像,最终发布和运行的产品;
  • Docker容器:容器就是镜像运行起来提供服务器。

Dockfile的指令

  • FROM :指定基础镜像,一切都是从这里开始构建
  • MAINTAINER :指定维护者信息【镜像是谁写的,姓名+邮箱】
  • RUN :镜像构建的时候需要运行的命令【你想要镜像做一些什么】
  • ADD :步骤,添加内容
  • WORKDIR :镜像的工作目录
  • VOLUME :挂载的目录
  • EXPOSE :保留端口配置
  • CMD :指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  • ENTRYPOINT :指定这个容器启动的时候要运行的命令,可以追加命令
  • ONBUILD :当构建一个被继承,DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令
  • COPY :类似ADD,将我们文件拷贝到镜像中
  • ENY :构建的时候设置环境变量

以前的话我们都是用的别人的镜像,现在我们知道了这些指令以后就开始自己来制作一个镜像。

实战:构建自己的Centos

Docker Hub中99%镜像都是从这个基础镜像过来的【FROM scratch】,然后配置需要的软件和配置来进行的构建。
在这里插入图片描述
创建一个自己的centos
官方给出的centos中是没有pwd、ifconfig、vim这些命令的,下面我们在官方给出的centos镜像中添加这三个功能。
在这里插入图片描述
第一步:在home目录下创建一个dockerfile,然后进入这个目录,后面我们就在这个目录下进行文件的书写
在这里插入图片描述
第二步:书写mydockfile-centos,这里我们是以官网中的centos为基础,再自己追加一些功能

命令:vim mydockerfile-centos

# 书写内容

FROM centos                # 基于本地的centos,如果没有就会去下载
MAINTAINER oldou<itoldou@foxmail.com>   # 写作者,邮件

ENV MYPATH /usr/local        # 设置环境变量
WORKDIR $MYPATH           # 配置登录进行的路径,引用上面配置的

RUN yum -y install vim            # 安装vim
RUN yum -y install net-tools    # 安装网络工具

EXPOSE 80                              # 暴露80端口

# 打印信息
CMD echo $MYPATH
CMD echo "--------END---------"

# 使用bash
CMD /bin/bash
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

第三步:通过文件构建镜像,命令格式:【 docker build -f dockerfile文件路径 -t 镜像名:[tag]

命令: docker build -f mydockerfile-centos -t mycentos:0.1 .
在这里插入图片描述
第四步:测试运行

  • 先使用 docker images 查看一下
    在这里插入图片描述
  • 命令: docker run -it mycentos:0.1
    在这里插入图片描述
    对比之前的,我们添加了扩展以后ifconfig、pwd还有vim都可以使用了。

第五步:列出本地进行的变更历史
命令格式: docker history 镜像id
注意 】这里的镜像id是使用 docker images 命令查看出来的
在这里插入图片描述
我们还可以通过【docker history 镜像id】这个命令去查看官方的镜像的信息,例如mysql
在这里插入图片描述
上面有别人设置的指令信息。

CMD 和 ENTRYPOINT区别【了解】

  • CMD: 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  • ENTRYPOINT: 指定这个容器启动的时候要运行的命令,可以追加命令

测试CMD
我们创建一个dockerfile-cmd-test文件
命令: vim dockerfile-cmd-test
【内容】

FROM centos
CMD ["ls","-a"]    # 增加一个命令 ls -a
  • 1
  • 2
  • 1
  • 2

构建命令: docker build -f dockerfile-cmd-test -t cmdtest .
运行命令: docker run 6365965c094f
在这里插入图片描述
run运行,我们发现【 ls -a 】命令生效

【测试】我们追加一个命令参数 -l 相当于 ls -al

[root@oldou dockerfile]# docker run 6365965c094f -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: 
starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

【结论】cmd的情况下,-l 替换了 CMD [“ls”,"-a"] 命令,而-l不是命令所以报错。

测试ENTRYPOINT

我们创建一个dockerfile-cmd-entrypoint文件
命令:vim dockerfile-cmd-entrypoint

【内容】

FROM centos
ENTRYPOINT ["ls","-a"]    # 增加一个命令 ls -a

构建文件:
docker build -f dockerfile-cmd-entrypoint -t entoryponit-test  .

运行命令
docker run 2efebf4ae1c6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述
【测试】我们追加一个命令参数-l相当于ls -al
在这里插入图片描述
结论 :通过以上两个测试,发现CMD后面只有最后一个命令会生效,如果生成镜像后往后面添加命令就会被替代,而ENTRYPOINT就是直接追加,不会被替代。

Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果。

【更新时间:2020.10.08 01:18】

后续笔记待更新中…

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/74171
 
61 次点击  
分享到微博