Docker简介

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器或Windows 机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
相对于传统的虚拟机省去了虚拟化和虚拟操作系统,极大的节约了资源。它会共享宿主机的操作系统。
而且虚拟机必须要kvm的支持才可以启用。

一个完整的Docker有以下几个部分组成:

  • DockerClient客户端
  • Docker Daemon守护进程
  • Docker Image镜像
  • DockerContainer容器 [2]

docker的体积非常小,最多不超过几百M,相对于十几个G的虚拟机来说太小了,一台主机可以同时存在上千个docker,而且他们是彼此安全隔离的互不影响,他们就相当于在系统中运行的程序。

局限
Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点:

  • Docker是基于Linux 64bit的,无法在32bit的linux/Windows/unix环境下使用
  • LXC是基于cgroup等linux kernel功能的,因此container的guest系统只能是linux base的
  • 隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库
  • 网络管理相对简单,主要是基于namespace隔离
  • cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)
  • Docker对disk的管理比较有限
  • container随着用户进程的停止而销毁,container中的log等用户数据不便收集

安装

[root@server1 docker]# yum install docker-ce-18.09.6-3.el7.x86_64.rpm \
 docker-ce-cli-18.09.6-3.el7.x86_64.rpm  \
 containerd.io-1.2.5-3.1.el7.x86_64.rpm  \
 container-selinux-2.21-1.el7.noarch.rpm  -y
[root@server1 docker]# systemctl enable --now docker

配置

我们现在导入一个景象:

[root@server1 docker]# docker load -i game2048.tar          # 导入
011b303988d2: Loading layer [==================================================>]   5.05MB/5.05MB
36e9226e74f8: Loading layer [==================================================>]  51.46MB/51.46MB
192e9fad2abc: Loading layer [==================================================>]  3.584kB/3.584kB
6d7504772167: Loading layer [==================================================>]  4.608kB/4.608kB
88fca8ae768a: Loading layer [==================================================>]  629.8kB/629.8kB
Loaded image: game2048:latest
[root@server1 docker]# docker run -d --name game1 -p 80:80 game2048     	##运行容器
7775c61ecf1a06832c67b70bf7a6b011dbf839ad6c730a1c1403f45f10059895
## 运行, -d后台运行,--name容器名  -p端口映射,由于安全隔离的原因,先访问物理机80端口,在访问server1的80端口

[root@server1 docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
game2048            latest              19299002fdbe        3 years ago         55.5MB
[root@server1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
7775c61ecf1a        game2048            "/bin/sh -c 'sed -i …"   12 seconds ago      Up 11 seconds       0.0.0.0:80->80/tcp, 443/tcp   game1
# 就运行起来了
容器退出后可以用docker ps -a 查看。

我们现在在浏览器访问
在这里插入图片描述
就可以访问了,这个2048的游戏镜像就打包到容器中去了。

[root@server1 docker]# du -sh game2048.tar 
55M	game2048.tar		##它只有55M的大小

[root@server1 docker]# docker info           查看docker信息
Containers: 1
 Running: 1
 Paused: 0
 Stopped: 0
Images: 1
Server Version: 18.09.6
...
Swarm: inactive                 ## swarm是docker的管理引擎,目前k8s比较流行
Runtimes: runc
...
Docker Root Dir: /var/lib/docker       ## 工作目录
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine

WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
## 这里有两个警告,我们处理一下
[root@server1 docker]# vim /etc/sysctl.d/docker.conf
[root@server1 docker]# sysctl --system        让其生效

在这里插入图片描述
在这里插入图片描述
最后的警告就没有了。

docker的数据都存放在 /var/lib/docker 下

[root@server1 docker]# ll
total 4
drwx------  2 root root   24 May 23 09:58 builder
drwx------  4 root root   92 May 23 09:58 buildkit
drwx------  3 root root   78 May 23 10:01 containers	容器
drwx------  3 root root   22 May 23 09:58 image			镜像
drwxr-x---  3 root root   19 May 23 09:58 network
drwx------ 10 root root 4096 May 23 10:01 overlay2		引擎
drwx------  4 root root   32 May 23 09:58 plugins		插件
drwx------  2 root root    6 May 23 09:58 runtimes
drwx------  2 root root    6 May 23 09:58 swarm
drwx------  2 root root    6 May 23 10:00 tmp
drwx------  2 root root    6 May 23 09:58 trust
drwx------  2 root root   25 May 23 09:58 volumes          数据存放目录

我们在运行一个容器:
运行一个ubuntu的系统镜像。

[root@server1 docker]# docker load  -i ubuntu.tar 
56abdd66ba31: Loading layer [==================================================>]  196.8MB/196.8MB
9468150a390c: Loading layer [==================================================>]  208.9kB/208.9kB
11083b444c90: Loading layer [==================================================>]  4.608kB/4.608kB
5f70bf18a086: Loading layer [==================================================>]  1.024kB/1.024kB
Loaded image: ubuntu:latest
[root@server1 docker]# du -sh ubuntu.tar 
188M	ubuntu.tar
[root@server1 docker]# docker run -it --name vm1 ubuntu    ## -it以交互的方式访问容器
root@6c10eb92f7a4:/# 
root@6c10eb92f7a4:/# 			这里我们就得到了ubuntu的系统
root@6c10eb92f7a4:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@6c10eb92f7a4:/# uname -r
3.10.0-957.el7.x86_64
它的内核版本和server1的内核一样,说明它是寄宿于server1的系统之上的


root@6c10eb92f7a4:/# touch file1
root@6c10eb92f7a4:/# touch file2  ## 创建两个文件,之后退出
root@6c10eb92f7a4:/# exit
exit
[root@server1 docker]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
7775c61ecf1a        game2048            "/bin/sh -c 'sed -i …"   41 minutes ago      Up 41 minutes       0.0.0.0:80->80/tcp, 443/tcp   game1
[root@server1 docker]# docker ps -a 				加上-a参数可以看到退出的同期
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                         NAMES
6c10eb92f7a4        ubuntu              "/bin/bash"              4 minutes ago       Exited (0) 18 seconds ago                                 vm1
7775c61ecf1a        game2048            "/bin/sh -c 'sed -i …"   41 minutes ago      Up 41 minutes               0.0.0.0:80->80/tcp, 443/tcp   game1

[root@server1 docker]# docker rm vm1
vm1
[root@server1 docker]# docker run -it --name vm1 ubuntu      
root@b1908317d127:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
重新运行之后发现之前创建的文件不见了。

这就证明容器就类似于我们的快照,可以随时还原,但是每一次退出都不能保存我们的操作的话,容器就失去了意义.
docker创建容器和创建快照都使用的是qcow的机制。

  • q --> qemu-kvm 虚拟化
  • cow --> copy on write 写时复制
[root@server1 docker]# docker history game2048:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
19299002fdbe        3 years ago         /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "sed …   0B                  
<missing>           3 years ago         /bin/sh -c #(nop)  EXPOSE 80/tcp                0B                  
<missing>           3 years ago         /bin/sh -c #(nop) COPY dir:cb74e9c037a3d501c…   600kB               
<missing>           3 years ago         /bin/sh -c #(nop)  MAINTAINER Golfen Guo <go…   0B                  
<missing>           3 years ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
<missing>           3 years ago         /bin/sh -c #(nop)  EXPOSE 443/tcp 80/tcp        0B                  
<missing>           3 years ago         /bin/sh -c #(nop) COPY file:d15ceb73c6ea776c…   1.1kB               
<missing>           3 years ago         /bin/sh -c #(nop) COPY file:af94db45bb7e4b8f…   643B                
<missing>           3 years ago         /bin/sh -c GPG_KEYS=B0F4253373F8F6F510D42178…   50.1MB              
<missing>           3 years ago         /bin/sh -c #(nop)  ENV NGINX_VERSION=1.11.7     0B                  
<missing>           3 years ago         /bin/sh -c #(nop)  MAINTAINER NGINX Docker M…   0B                  
<missing>           3 years ago         /bin/sh -c #(nop) ADD file:7afbc23fda8b0b387…   4.8MB      
  • 这里我们可以看到的是镜像层,记录了这个镜像生产的全过程,这个部分是封装好, 是不可以在进行改动的,如果我们想要保存我们的更改,就要使用 cow 的机制,对容器层进行更改
  • 就是我们更改完成后将其保存成一个新的容器,这样的话才可以保存我们的更改。而不能保存在本层中。因为本层是只读的,就像系统快照,它只有几百k,但是我们我可以看到系统的全部内容,它就是把新的更改和能看到的内容打包到一个容器里面,这就是cow的机制。

新镜像的构建

[root@server1 docker]# docker rm -f vm1 
vm1
[root@server1 docker]# docker rm -f game1 
game1				

镜像的构建有两种方式,第一种是:

dicker commit

我们获取一个busybox的镜像,它是一个linux基础的文件系统,它只有一些基础的命令和文件。

containerd.io-1.2.5-3.1.el7.x86_64.rpm  distroless.tar                           docker-ce-cli-18.09.6-3.el7.x86_64.rpm  nginx.tar     ubuntu.tar
[root@server1 docker]# docker load -i busybox.tar             ## 加载
8a788232037e: Loading layer [==================================================>]   1.37MB/1.37MB
Loaded image: busybox:latest
[root@server1 docker]# du -sh busybox.tar 
1.4M	busybox.tar
[root@server1 docker]# docker run -it --name vm1 busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var			## 只有一些基础的目录
/ # vi testfile   ## 编辑一个文件

在这里插入图片描述
直接exit的话就直接关闭容器了,那么我们想退出容器,并暂时保留运行状态的话,按 CTRL + P + Q

/ # vi testfile
/ # [root@server1 docker]# docker ps		## 可以看出 vm1 还在运行
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
47c17a5d6d5a        busybox             "sh"                4 minutes ago       Up 4 minutes                            vm1
[root@server1 docker]# docker attach vm1			# 使用这个命令重新连接
/ # ls
bin       dev       etc       home      proc      root      sys       testfile  tmp       usr       var
/ # read escape sequence
[root@server1 docker]# 

那末这时我们如果想要保存这份更改的话,就要打包成一个新的镜像才可以:

[root@server1 docker]# docker commit vm1 test:v1		# 提交,test是镜像名,v1是标签
sha256:ccbb07c70420075c8e33dd47859616658344cfd0fd91cae92adff74d209985df
[root@server1 docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                v1                  ccbb07c70420        5 seconds ago       1.15MB		这就是新生成的镜像
busybox             latest              59788edf1f3e        19 months ago       1.15MB
game2048            latest              19299002fdbe        3 years ago         55.5MB
ubuntu              latest              07c86167cdc4        4 years ago         188MB     
[root@server1 docker]# docker history busybox:latest 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
59788edf1f3e        19 months ago       /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           19 months ago       /bin/sh -c #(nop) ADD file:63eebd629a5f7558c…   1.15MB   
[root@server1 docker]# docker history test:v1 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
ccbb07c70420        47 seconds ago      sh       ## 这里                                 29B                 
59788edf1f3e        19 months ago       /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           19 months ago       /bin/sh -c #(nop) ADD file:63eebd629a5f7558c…   1.15MB
         
对比busybox来看它多了一行,多的一行就是更改的内容,而且他们有共同的镜像层,说明这一部分他们是共享的,只保留了一份在本机中,
但是,这里我们可以看到,我们刚才的操作只记录了一个sh,如果是一些恶意操作的话,也只会显示 **sh**,在镜像安全审计的时候是不能过审的

所以,一般不建议使用,值是高速大家有这个方法。
现在我们测试一下刚才新建的镜像:

[root@server1 docker]# docker rm -f vm1    #  删除 vm1 容器
vm1
[root@server1 docker]# docker run -it --name vm1 test:v1
/ # ls
bin       dev       etc       home      proc      root      sys       testfile  tmp       usr       var
可以看见testfile 确实保存了下来。

Dockerfile

  • 和 ansible 里面的 playbook
    比较相似,把我们想要进行的操作写到这个文件里,根据这个文件构建镜像,这样的操作是透明的,大家才会放心使用。
[root@server1 ~]# mkdir docker 			## 建立一个目录,将dockerfile都放到这里面
[root@server1 ~]# cd docker/
[root@server1 docker]# vim Dockerfile
内容是:
FROM busybox					## 表示基于busybox镜像
RUN echo testfile > file1		## RUN 指运行那个命令
RUN echo testfile > file2

[root@server1 docker]# docker build -t test:v2 .
## 使用docker bulid 命令,。表示使用当前目录的dockerfile
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM busybox					## 分成三步进行
 ---> 59788edf1f3e					# 生成镜像,对应下面busybox的id
Step 2/3 : RUN echo testfile > file1
 ---> Running in d47cec1fa1b3			# 使用临时容器,加进去我们的命令
Removing intermediate container d47cec1fa1b3
 ---> baa70e1993eb		# 然后放到这个容器
Step 3/3 : RUN echo testfile > file2
 ---> Running in 030861184a16			#在使用临时容器,加我们第二条命令
Removing intermediate container 030861184a16
 ---> 69602c6919b2		## 最后生成这个镜像,就是下面我们用docker images 可以查看的镜像
Successfully built 69602c6919b2
Successfully tagged test:v2
[root@server1 docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                v2                  69602c6919b2        46 seconds ago      1.15MB		#就出现了
test                v1                  ccbb07c70420        17 minutes ago      1.15MB
busybox             latest              59788edf1f3e        19 months ago       1.15MB
game2048            latest              19299002fdbe        3 years ago         55.5MB
ubuntu              latest              07c86167cdc4        4 years ago         188MB
[root@server1 docker]# docker history test:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
69602c6919b2        3 minutes ago       /bin/sh -c echo testfile > file2                9B                  
baa70e1993eb        3 minutes ago       /bin/sh -c echo testfile > file1                9B                  
59788edf1f3e        19 months ago       /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           19 months ago       /bin/sh -c #(nop) ADD file:63eebd629a5f7558c…   1.15MB
后两行就是从FROM 的镜像中来的,前两行就是我们 RUN 的命令

我们在看上面创建的过程中的三布,它时根据我们的dockefile进行的,它时一行一行进行的。这就是cow的机制。

我们在加一条命令进去

[root@server1 docker]# vim Dockerfile
FROM busybox
RUN echo testfile > file1
RUN echo testfile > file2
RUN echo testfile > file3			#多了一个file3

[root@server1 docker]# docker build -t test:v3 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM busybox
 ---> 59788edf1f3e
Step 2/4 : RUN echo testfile > file1
 ---> Using cache		#使用缓存
 ---> baa70e1993eb
Step 3/4 : RUN echo testfile > file2
 ---> Using cache		#使用缓存
 ---> 69602c6919b2
Step 4/4 : RUN echo testfile > file3
 ---> Running in 12f9d6d2be84
Removing intermediate container 12f9d6d2be84
 ---> 0ba22520cbea
Successfully built 0ba22520cbea
Successfully tagged test:v3

## 这次构建是非常快的,因为前两次的更改我们已经做过了,所以再次创建,如果有相同的镜像层的话,它会直接从缓存中读去,不会去创建临时容器了。

## 修改镜像名称
docker tag 【镜像ID】【镜像名称】:【tag版本信息】 

docker tag 8ef375298394 mysql:v5.7

dockerfile的具体写法

USER

USER指令用于指定容器执行程序的用户身份,默认是 root用户。

在docker run 中可以通过 -u 选项来覆盖USER指令的设置。
在这里插入图片描述

举例:docker run -i -t -u mysql newmysqldb /bin/bash

COPY

[root@server1 docker]# docker rmi test:v1
Untagged: test:v1
Deleted: sha256:ccbb07c70420075c8e33dd47859616658344cfd0fd91cae92adff74d209985df
Deleted: sha256:2e111e5c875c6ac9867ca03157acb0a1b96dfcbc4c21d2d170dda3536ea40905
[root@server1 docker]# docker rmi test:v2
Untagged: test:v2
[root@server1 docker]# docker rmi test:v3
# 先删除之前的几个新镜像。


[root@server1 docker]# echo helloworld > testfile				创建testfile文件
[root@server1 docker]# vim Dockerfile 

FROM busybox
COPY testfile /tmp			将testfile 复制到/tmp 目录下去

[root@server1 docker]# docker build -t test:v1 .			# 构建
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM busybox
 ---> 59788edf1f3e
Step 2/2 : COPY testfile /tmp
 ---> e56af2cf81bd
Successfully built e56af2cf81bd
Successfully tagged test:v1
[root@server1 docker]# docker history test:v1 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
e56af2cf81bd        10 seconds ago      /bin/sh -c #(nop) COPY file:b365b01e2b088c0a…   11B            # 这时我们新加的命令
59788edf1f3e        19 months ago       /bin/sh -c #(nop)  CMD ["sh"]                   0B                  
<missing>           19 months ago       /bin/sh -c #(nop) ADD file:63eebd629a5f7558c…   1.15MB              
[root@server1 docker]# docker run -it --name vm1 test:v1 	# 运行
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # cd /tmp/
/tmp # ls
testfile
/tmp # cat testfile 
helloworld				#这就是我们copy的文件
/tmp # 

这就是copy的用法,可以把本机的文件在构建中拷贝到容器中去,方便了我们的部署,比如部署apache时
或nginx,在创建的同时就可以把默认发布页面发布过去

ADD

ADD相比与COPY 只多了一个功能,就是在拷贝的过程中解压文件。
现在当前目录获取一个nginx压缩包:
在这里插入图片描述

[root@server1 docker]# vim Dockerfile 

FROM busybox
COPY testfile /tmp
ADD nginx-1.18.0.tar.gz /tmp


[root@server1 docker]# docker build -t test:v2 .				# 建立
Sending build context to Docker daemon  1.043MB
Step 1/3 : FROM busybox
 ---> 59788edf1f3e
Step 2/3 : COPY testfile /tmp
 ---> Using cache
 ---> e56af2cf81bd
Step 3/3 : ADD nginx-1.18.0.tar.gz /tmp
 ---> a66cd7e60132
Successfully built a66cd7e60132
Successfully tagged test:v2
[root@server1 docker]# docker run -it --name vm1 test:v2		# 运行
docker: Error response from daemon: Conflict. The container name "/vm1" is already in use by container "9ba3b48b4f2ae493979ad9d871634c28c3b11a9b67920c87b66cc407389866ce". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.			# 这里起冲突了,vm1这个名字用了
[root@server1 docker]# docker rm -f vm1
vm1
[root@server1 docker]# docker run -it --name vm1 test:v2
/ # cd tmp/
/tmp # ls
nginx-1.18.0  testfile
/tmp # cd nginx-1.18.0/
/tmp/nginx-1.18.0 # ls
CHANGES     CHANGES.ru  LICENSE     README      auto        conf        configure   contrib     html        man         src

可以看出在复制的时候将压缩包解压好了。

数据卷VOLUME

[root@server1 docker]# vim Dockerfile 
FROM busybox
COPY testfile /tmp
ADD nginx-1.18.0.tar.gz /tmp
VOLUME ["/data"]			表示创建 /data 这个目录

[root@server1 docker]# docker build -t test:v3 .

[root@server1 docker]# docker run -it --name vm2 test:v3
/ # ls
bin   data  dev   etc   home  proc  root  sys   tmp   usr   var
# 就出现了data 目录,这个目录其实和我们的真实主机是相关联的

我们进行查看:

[root@server1 docker]# docker inspect

在这里插入图片描述
这里我们可以看到,这个数据卷存放在我们真实主机的这个目录中,它是数据卷的挂载,它会在宿主机上生成目录,并且和容器中的目录关联。在主机上创建的东西,在容器中就可以看到。

我们创建一个文件:

[root@server1 docker]# cd /var/lib/docker/volumes/91f0897dbeda40ac75f20603dccb0459920191144c77eea663cccde1307b7f1d/_data	
[root@server1 _data]# touch file1 file2
[root@server1 _data]# docker attach vm2
You cannot attach to a stopped container, start it first
[root@server1 _data]# docker start vm2
vm2
[root@server1 _data]# docker attach vm2
/ # ls
bin   data  dev   etc   home  proc  root  sys   tmp   usr   var
/ # cd data/
/data # ls
file1  file2

## 果然可以看到,两边的操作是对应的,

我们还可以将其挂载到我们想要的位置,因为现在的这个挂载点的名字太长了。

[root@server1 _data]# docker run -it --name vm3 -v /opt/data:/data test:v3
/ # ls										# -v指定挂载点  ,:前面为宿主机目录,会自动创建,后面为容器的目录 
bin   data  dev   etc   home  proc  root  sys   tmp   usr   var
/ # cd data/
/data # ls
/data # ls			# 看不到了,因为对应关系变了,所以看不到之前那个目录创建的文件了
/data # touch westos
/data # [root@server1 _data]# ls /opt/data				# 按 CTRL + p + q可保存状态退出,用attach在连接。
westos
## 就可以看到了

WORKDIR

工作目录,这个参数是用来为ADD RUN COPY 这几个命令设置在镜像中的工作目录的,不存在会自动新建,相当于cd命令。比如在拷贝的过程中我们要进入到目录执行命令,我们是不能用cd命令的,这个workdir就可以帮助我们进去,再执行我们的命令。

CMD 和 ENTRYPOINT 和 RUN

cmd和entrypoint的区别

RUN:执行命令并创建新的Image Layer

CMD:设置容器启动后默认执行的命令和参数
如果docker run指定了其他命令,CMD命令被忽略
如果定义了多个CMD, 只有最后一个会执行

ENTRYPOINT:设置容器启动时运行的命令
让容器以应用程序或者服务的形式运行
不会被忽略,一定会执行
dockerfile中只能指定一个 ENTRTPOINT ,否则只会执行最后一个

  1. CMD 和 RUN 的区别
    两者都是用于执行命令,区别在于执行命令的时机不同,RUN命令适用于在 docker build 构建docker镜像时执行的命令,而CMD命令是在 docker run 执行docker镜像构建容器时使用,可以动态的覆盖CMD执行的命令。

  2. CMD 和 ENTRYPOINT的区别
    首先,CMD命令是用于默认执行的,且如果写了多条CMD命令,则只会执行最后一条,如果后续存在ENTRYPOINT命令,则CMD命令或被充当参数或者覆盖,而且Dockerfile中的CMD命令最终可以被在执行 docker run命令时添加的命令所覆盖。而ENTRYPOINT命令则是一定会执行的,一般用于执行脚本

dockerfiler的俩种格式

shell 格式

一般会有以下两种书写格式:
Shell格式:
在shell写法中,如果存在 ENTRYPOINT命令,则不管是在Dockerfile中存在CMD命令也好,还是在 docker run执行的后面添加的命令也好,都不会被执行。如果不存在 ENTRYPOINT命令,则可以被 docker run后面设置的命令覆盖,实现动态执行命令操作。

RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"

Exec格式:

RUN ["apt-get","install","-y","vim"]
CMD ["/bin/echo","hello docker"]
ENTRYPOINT ["/bin/echo","hello docker"]
ENTRYPOINT ["/bin/echo","hello $name"]
这样的写法只会打印出 “hello $name”,原因是它只是在执行echo命令,并不是执行shell。
意思是说,我们不是在shell里执行echo,只是单纯的执行echo,所以不会替换变量。想要改成可执行的shell,需要改写成以下形式:

FROM centos
ENV name Docker
ENTRYPOINT ["/bin/bash","-c","echo hello $name"]
[root@server1 docker]# vim Dockerfile 
FROM busybox
ENV name world			# 设置一个环境变量
ENTRYPOINT echo "hello, $name"			# 应该输出hello,world

[root@server1 docker]# docker build -t test:v4 .
Sending build context to Docker daemon  1.043MB
Step 1/3 : FROM busybox
 ---> 59788edf1f3e
Step 2/3 : ENV name world
 ---> Running in 6342b3e9af3a
Removing intermediate container 6342b3e9af3a
 ---> d84029daefc2
Step 3/3 : ENTRYPOINT echo "hello, $name"
 ---> Running in c53c110b2859
Removing intermediate container c53c110b2859
 ---> a7804adb5af4
Successfully built a7804adb5af4
Successfully tagged test:v4
[root@server1 docker]# docker run --rm test:v4				--rm 表示一次性容器,运行完后删除
hello, world
[root@server1 docker]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
290b4854763f        test:v3             "sh"                20 minutes ago      Exited (0) 8 minutes ago                        vm3
c6fb50481e50        test:v3             "sh"                31 minutes ago      Exited (0) 22 minutes ago                       vm2
75b9b11dd8bb        test:v2             "sh"                36 minutes ago      Exited (0) 35 minutes ago                       vm1
## 删除了

exec 格式

[root@server1 docker]# vim Dockerfile 
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh","-c","echo hello,$name"]

[root@server1 docker]# docker build -t test:v6 .

Successfully built 9ddd8e36cd7b
Successfully tagged test:v6
[root@server1 docker]# docker run --rm test:v6
hello,world
[root@server1 docker]# cat Dockerfile 
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]
[root@server1 docker]# docker build -t test:v7 .

Successfully built 1e98b0485f36
Successfully tagged test:v7
[root@server1 docker]# docker run --rm test:v7 
hello world
[root@server1 docker]# docker run --rm test:v7 westos
hello westos

## 可以看出,当run 后面不接参数时,就使用CMD的参数,接时就会替换掉CMD的参数

exec格式时比较推荐使用的,比较整齐。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐