docker 入门1

Author:chenj_x12@foxmail.com

安装

docker的安装教程可以看菜鸟的:Docker 教程 | 菜鸟教程 (runoob.com)

测试是否安装成功

# 运行:docker run hello-world,出现如下文字说明安装成功

Hello from Docker !
This message shous that your installation appears to be uorking correctly.To generate this message,Docker took the follouing steps:1. The Docker client contacted the Docker daemon.,
2. The Docker daemon pulled the "hello-uorld" image from the Docker Hub.( amd64)
3. The Docker daemon created a new container from that image uhich runs theexecutable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client,uhich sent it
to your terminal.

配置镜像加速

安装好docker后,需要给它配置镜像加速,毕竟直接访问太慢了

步骤如下:

cd /etc/docker
touch daemon.json

vim daemon.json

{
"registry-mirrors": [
        "https://docker.m.daocloud.io",
        "https://docker.1panel.live",
        "https://registry.docker-cn.com",
        "https://mirrors.docker.ustc.edu.cn",
        "https://hub-mirror.c.163.com",
        "https://mirror.baidubce.com"
        
        # 还有多的镜像站可以接着放,只要这里面有一个能用就行 
]
}

如果有一定能力的话可以去阿里云、华为云找容器镜像加速服务,具体步骤网上找

docker客户端

基于终端命令行的docker客户端非常简单,可以直接输入 docker命令查看指令:

docker command help

一样的,可以使用 docker COMMAND –help,查看对应指令的详细用法

容器使用

启动容器

docker run

使用  docker run (参数)images [COMMAND]  启动一个容器
eg:docker run -it ubuntu /bin/bash

root@chenjx12:~/dc# docker run -it ubuntu /bin/bash
root@e88f80e041c2:/# 

发现了什么,root后面的东西变了对不对
这说明我们顺利的启动了容器,并且进入到了容器里面
现在就可以在容器里进行操作了

e88f80e041c2就是这个容器的ID,唯一的那种
如果我们选择后台运行 -d 参数,容器id会回显在终端

参数说明:
-i  使用交互式操作
-t  开启终端
-d/--detach  后台运行
--name <new_name>  容器命名
-rm  退出容器时自动删除
--restart=always  挂了就自动重启
-v/--volume  挂载卷
-e/--env  设置环境变量

# 容器连接相关(后面会讲)
-p  端口映射
-P  端口随机映射

/bin/bash  指明启动这个容器进入之后要执行什么命令

那docker run里的images是什么呢,它就是另一个重点,镜像

docker run -it ubuntu /bin/bash

docker会先在本地查找是否有ubuntu(:latest)的镜像

如果有,就基于它创建一个容器

如果没有,它就自动执行 docker pull ubuntu:latest 拉取一个镜像下来再创建容器

停止/运行的容器

首先需要查看容器的状态,使用命令如下
docker ps (参数)
= 
无参数运行该命令会列出所有 “正在” 运行的容器,包括它们的容器 ID、镜像、命令、创建时间、状态、端口和名称

参数说明:
-a/--all 列出所有的容器(包括已经挂掉的)
-q/--quiet  只显示容器id
--format  自定义输出格式
	docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}" 
    这将按照指定的格式列出容器的 ID、名称和使用的镜像
-l/--latest  列出最近创建的容器
-n numb  后接数字列出最后创建的 numb 个容器
-f/--filter  过滤输出

一般直接使用  docker ps -a

停止容器:docker stop <容器id>

启动/重新启动容器:docker start/restart <容器id>

进入容器

在使用 -d 参数时,容器启动后会进入后台

此时想要进入容器,有两个指令可以实现:

  • docker attach <容器id>

    使用该命令进入容器,再退出容器后容器会被停止

  • docker exec -it <容器id> /bin/bash

    使用该命令退出后不会停止,推荐使用

注意:

想要再次进入容器的前提是容器还在运行,可以使用docker ps的status查看容器是否还在运行

docker作为一种节约资源的进程,会在当前容器没有任务执行的时候把它挂掉

也就是说,如果你的容器挂掉了,它里面就没有任务了,也就进不去了

同样的,正在后台运行的容器被docker stop停止了,也进不去,只是它不会被挂掉

退出容器

直接在容器的终端输入 exit就可以退出容器回到宿主机

容器导出/导出

docker export/import

docker export 命令用于将容器的文件系统导出为一个 tarball 文件。这不会包括容器的元数据或历史记录

docker export -o mycontainer.tar mycontainer

如果你不指定 -o 选项,则导出的 tarball 将会输出到标准输出(stdout)

这时就可以直接重定向

docker export mycontainer > mycontainer.tar

docker import 命令用于从 tarball 文件中创建一个新的 Docker 镜像。这个 tarball 文件通常是由 docker export 命令创建的

cat mycontainer.tar | docker import - mynewimage

如果有一个tarball文件:

docker import mycontainer.tar mynewimage

这将创建一个新的镜像 mynewimage,其内容来自 mycontainer.tar 文件。

docker import 还可以指定一个url或者某个目录进行导入,如:

docker import http://example.com/example_contain.tgz example/imagerepo

注意:

  • docker export 导出的 tarball 不包含容器的元数据,例如标签、环境变量等。它只包含容器文件系统的内容。
  • docker import 创建的新镜像会丢失所有历史记录和层信息,只有一个单独的层。

删除容器

docker rm

# 删除一个停止的容器
docker rm <容器id/名称>

# 强行删除一个正在运行的容器
docker rm -f <容器id/名称>

# 删除所有停止的容器(结合shell)
docker rm $(docker ps -aq)

# 删除所有容器
docker rm -f $(docker ps -aq)

镜像使用

获取镜像:

docker pull

使用 docker pull <image_name:tag> 从 “仓库” 中获取镜像

# tag为空的话默认为 latest
比如 docker pull ubuntu,默认拉取的镜像版本为 ubuntu:latest

root@chenjx12:~/dc# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
eda6120e237e: Pull complete 
Digest: sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

这里就是从仓库中拉取到了官方的镜像 ubuntu:latest

# 批量拉取 docker pull -a/--all-tags ubuntu
批量拉取会拉取所有标签的ubuntu

# 怎么拉取别人的镜像
docker pull user/repo:tag
拉取用户名为user标签为tag的repo镜像

那么要怎么知道我们拉取的镜像仓库里有没有我们要的那个版本的镜像呢

docker search

使用  docker search images  可以在仓库中搜索名为images的镜像

常用的一些选项:
-f/--filter 添加条件搜索
--limit 限制搜索出的结果数量,默认为25条
--no-trunc 不截断输出,显示完整的镜像描述

eg:
docker search --limit 5 ubuntu  只显示前5个搜索结果

docker search -f "is-offical=true" ubuntu  只显示官方镜像
docker search --filter "is-automated=true" ubuntu 只显示自动化构建的镜像
docker search -f "stars=100" ubuntu  只显示拥有超过100星标的镜像

使用docker search得到搜寻结果之后就能够知道哪些镜像有,哪些没有

一般推荐下载星标最多的官方镜像,因为你也不知道别人上传的乱七八糟的镜像里有什么东西

列出镜像

可以在终端输入 docker images 来列出本地的镜像

root@chenjx12:~/dc# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
ubuntu        latest    61b2756d6fa9   2 weeks ago     78.1MB
nginx         latest    9527c0f683c3   6 weeks ago     188MB
ubuntu        20.04     9df6d6105df2   7 weeks ago     72.8MB
hello-world   latest    d2c94e258dcb   17 months ago   13.3kB
ubuntu        15.10     9b9cb95443b5   8 years ago     137MB

# 各项属性说明
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小

用镜像跑个容器

见容器使用–启动容器

镜像导入/导出

docker save/load

docker save 命令用于将一个或多个镜像保存为一个 tarball 文件。与 docker export 不同的是,docker save 保存的是镜像而不是容器,并且会保存镜像的所有历史记录和层信息

docker save -o myimage.tar myimage 保存单个镜像

docker save -o myimages.tar myimage1 myimage2 将 myimage 或 myimage1 和 myimage2 镜像保存到 myimage.tar 文件中

docker load 命令用于从 tarball 文件中加载一个或多个镜像。与 docker import 不同的是,docker load 会恢复镜像的所有历史记录和层信息

docker load < myimage.tar

docker load -i myimage.tar

注意:

  • docker save 和 docker load 保存和加载的是镜像,包括所有层和历史信息。
  • docker export 和 docker import 保存和加载的是容器快照,不包括历史信息,只有一个压缩的文件系统。

因此,如果你需要保存一个镜像及其所有层,以便在其他 Docker 主机上使用,你应该使用 docker save 和 docker load。如果你只是需要从一个容器创建一个新的镜像,而不需要保存层信息,那么可以使用 docker export 和 docker import

删除镜像

docker rmi

即 docker rm (image)

docker rmi [image_id]
docker rmi [image_name]:[tag]

# 强行删除,比如有容器正在使用该镜像
docker rmi -f [image_id]
# 删除所有未标记的镜像,有时候,你会有一些未标记或未使用的镜像,可以使用以下命令清理:
docker image prune
# 删除所有
docker rmi -f $(docker images -q)

容器连接

容器–网络

先前在**容器使用–启动容器** 中就讲了,docker run 后跟 -p和-P参数可以做到端口映射 和 端口随机映射

首先说明为什么要做端口映射:

容器构建了一个隔离于宿主机的环境,而外部网络只能访问到宿主机

要在宿主机外的网络仍能够访问到容器,就必须把容器内运行服务的端口映射到宿主机上

即,访问宿主机的这些端口等同于访问相应容器的端口

也就是为了容器能够被宿主机外的网络访问到,所以做了端口映射

比如运行nginx,mysql之类的服务的容器

接下来看看具体的指令该怎么用,就拿一个nginx容器做例子吧

# 端口映射
docker run -d -p 8080:80 --name test_p1 nginx

这个指令就是将容器的 80 端口映射给了宿主机的 8080 端口
这样访问宿主机的 8080 端口就可以访问到nginx服务


# 端口随机映射
docker run -d -P --name test_p2 nginx

Docker会自动选择宿主机的一个空闲端口(默认是32768到61000)来进行映射
该指令不需要指定端口,它会根据容器中暴露的端口对宿主机进行随机映射

那么问题来了,我怎么知道哪些端口可用哪些不能呢

# 可以查看存活的容器
docker ps
使用该指令查看存活容器的 PORT项,那些是它正在占用的端口
当然,你也可以给它加上个 -a 和 --format参数,列出所有容器

# 查看单个容器的端口映射
docker port [container_id/name]
回显与该容器相关的所有端口映射

# 查看容器详细信息
docker inspect [container_id/name]
在输出的JSON结果中,可以找到 NetworkSettings 部分,它包含了端口映射的详细信息

容器–容器

docker除了容器和镜像,还在本地提供了容器连接的桥梁

docker 桥接网络

当Docker安装完成后,它会自动创建一个名为 docker0 的Linux网桥。这个网桥允许容器与宿主机以及容器之间进行通信。Docker容器默认连接到这个桥接网络

通过它可以完成宿主机与容器间的通信

查看docker桥接网络

使用指令 ifconfig docker0 或者 brctl show

回显docker0网桥的详细信息,包括ip地址、子网掩码等

自定义docker桥接网络

# docker network create -d bridge test-bet
使用该指令创建一个名为 test-net 的桥接网络,类型是 bridge
参数 -d 指定docker网络类型,有bridge、overlay

# docker run -itd --name test1 --network test-net ubunut /bin/bash
# docker run -itd --name test2 --network test-net ubuntu /bin/bash
运行两个名为test1和test2的容器,并加入到名为test-net的docker网络中

# docker exec -it test1 /bin/bash
进入容器test1
# apt-get update
# apt install iputils-ping
更新下载ping
# ping test2
可以发现可以ping的通
这说明test1和test2在同一个容器网络中

配置DNS

自动配置

我们可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS:

{
  "dns" : [
    "114.114.114.114",
    "8.8.8.8"
  ]
}

设置后,启动容器的DNS会自动配置为114.114.114.114和8.8.8.8 配置完需要重启docker才能生效

systemctl restart docker

手动指定

如果只想在指定的容器设置DNS,可以使用如下指令:

docker run -it --rm -h host_ubuntu  --dns=114.114.114.114 --dns-search=test.com ubuntu

参数说明:
--rm:容器退出时自动清理容器内部的文件系统
-h HOSTNAME 或者 --hostname=HOSTNAME: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts
--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名
--dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com

如果在容器启动时没有指定 –dns 和 –dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS

Dockerfile

Dockerfile是啥

Dockerfile 是一个文本文件,其中包含了构建docker 镜像的所有指令

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明

通过定义一系列命令和参数,Dockerfile 指导 Docker 构建一个自定义的镜像

docker build

docker build 会根据Dockerfile中的指令,依次执行并构建镜像,指令如下:

docker build (参数) [image_name]:[tag] [Path]

参数说明:
-f 指定Dockerfile的位置(如果不在当前目录下)
-t 设置镜像名称和可选的标签
--build-arg 设置构建时变量
--no-cache 不使用构建缓存

[Path]:Dockerfile 的位置,一般为 . ,表示在当前目录下寻找

注意:路径下有且仅能有一个Dockerfile文件
注意:以前是只能Dockerfile,现在dockerfile也可以了

dockerfile指令

Dockerfile 指令		说明

FROM				指定基础镜像,用于后续的指令构建。
MAINTAINER			指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令)
LABEL				添加镜像的元数据,使用键值对的形式。
RUN					在构建过程中在镜像中执行命令。
CMD					指定容器创建时的默认命令。(可以被覆盖)
ENTRYPOINT			设置容器创建时的主要命令。(不可被覆盖)
EXPOSE				声明容器运行时监听的特定网络端口。
ENV					在容器内部设置环境变量。
ADD					将文件、目录或远程URL复制到镜像中。
COPY				将文件或目录复制到镜像中。
VOLUME				为容器创建挂载点或声明卷。
WORKDIR				设置后续指令的工作目录。
USER				指定后续指令的用户上下文。
ARG					定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。
ONBUILD				当该镜像被用作另一个构建过程的基础时,添加触发器。
STOPSIGNAL			设置发送给容器以退出的系统调用信号。
HEALTHCHECK			定义周期性检查容器健康状态的命令。
SHELL				覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。

接下来,会稍微细致的讲一下常用的指令

FROM 指令:往往是Dockerfile 的第一条,指定base image

FROM ubuntu # 指定ubuntu:latest作为基础镜像

MAINTAINER chenjx12 # 指定该dockerfile的作者为chenjx12(更换为LABEL)

LABEL maintainer=“chenjx12@foxmail.com” # 指定作者chenjx12 LABEL =

RUN echo ‘这是一个本地构建的镜像’ > /tmp/1.txt

用于执行后面跟着的命令行命令,RUN 有两种格式:

  • shell格式

    RUN <终端命令行命令>

  • exec格式

    RUN [“可执行文件”, “参数1”, “参数2”]

    例如:

    RUN ["./test.php", “dev”, “offline”] 等价于 RUN ./test.php dev offline

注意:Dockerfile每次执行都会在docker镜像上新建一层,过多无意义的层会造成镜像膨胀过大

多个RUN指令可以 && 符号连接命令,这样执行后,只会创建 1 层镜像

CMD /bin/bash == CMD [“/bin/bash”]

即运行镜像时默认执行/bin/bash,但是可以更改

比如:docker run -it ubuntu:latest cat /tmp/1.txt

这条指令运行容器时就会执行 cat /tmp/1.txt

ENTRYPOINT 同理,但是有细微的区别,后面会讲

EXPOSE 80

声明容器运行暴露听的特定的网络 80 端口,这样就可以访问在 80 端口运行的服务

仅仅只是声明端口

作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

ENV NAME = “chenjx12”

指定环境变量NAME为chenjx12

ARG 同理,也有细微区别,后讲

ADD Path/file

将 Path路径下的file文件/目录复制到镜像中

也可以使用 url

COPY 同,细微区别,后讲

WORKDIR /opt

指定工作目录为 /opt

也就是进入容器后的目录为 /opt

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在

USER root

指定工作用户为root

也就是进入容器后的身份为root

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)

只能用于切换用户,如果需要添加用户还需要再RUN 一条指令添加用户

VOLUME /data

挂载容器内的/data文件夹,在容器运行时,该目录自动挂载为匿名卷,任何向该目录写入数据的操作都不会被容器记录

保证容器存储层的无状态理念

定义匿名数据卷,在启动容器时忘记挂载数据卷,会自动挂载到匿名卷

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的
  • 避免容器不断变大

ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

ONBUILD <其它指令>

CMD & ENTRYPOINT

首先这俩都可以使用shell格式和exec格式,都没差

主要区别在于,一个是默认执行(可以更改);一个是主要执行(不允许更改)

并且它们在传参上也有所不同

比如现在,我想运行一个ubuntu容器,让它帮我用curl命令查看一下本机的ip

先看看直接拉取一个ubuntu下来,怎么执行

# docker pull ubuntu:20.04
# docker run -it <id> /bin/bash

# apt-get update
# apt-get install -y curl

# curl -s http://ipinfo.io/ip
root@c20b356e8ec0:/# curl -s http://ipinfo.io/ip
47.120.34.132

这里就会回显你的ip地址,如果我加上 -i 参数,则会输出HTTP响应头的详细信息

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# curl -s http://ipinfo.io/ip -i
HTTP/1.1 200 OK
date: Thu, 03 Oct 2024 09:59:20 GMT
content-type: text/plain; charset=utf-8
Content-Length: 13
access-control-allow-origin: *
via: 1.1 google
strict-transport-security: max-age=2592000; includeSubDomains

那么我们自行构建镜像呢

# 咱接着来看看 ENTRYPOINT 版的,dockerfile_1
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y curl
ENTRYPOINT ["curl", "-s", "http://ipinfo.io/ip"]

这样就行了,build一下运行容器试试

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker build -t curl_ip:test .
[+] Building 0.1s (6/6) FINISHED                                                                                                      docker:default
 => [internal] load build definition from dockerfile                                                                                            0.0s
 => => transferring dockerfile: 142B                                                                                                            0.0s
 => [internal] load metadata for docker.io/library/ubuntu:20.04                                                                                 0.0s
 => [internal] load .dockerignore                                                                                                               0.0s
 => => transferring context: 2B                                                                                                                 0.0s
 => [1/2] FROM docker.io/library/ubuntu:20.04                                                                                                   0.0s
 => CACHED [2/2] RUN apt update && apt install curl -y                                                                                          0.0s
 => exporting to image                                                                                                                          0.0s
 => => exporting layers                                                                                                                         0.0s
 => => writing image sha256:050f1c97507ca5e73b95c5659b4c9f23e249289e71bdad2bf101b2593e6116ba                                                    0.0s
 => => naming to docker.io/library/curl_ip:test                                                                                                 0.0s
[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker images
REPOSITORY    TAG        IMAGE ID       CREATED        SIZE
flask_web     latest     69ce5c1bb4e0   20 hours ago   866MB
curl_ip       test       050f1c97507c   30 hours ago   143MB
test_blog     latest     4deac4dd6f5b   41 hours ago   141MB
nginx         latest     605c77e624dd   2 years ago    141MB
ubuntu        20.04      ba6acccedd29   2 years ago    72.8MB
hello-world   latest     feb5d9fea6a5   3 years ago    13.3kB
centos        7.8.2003   afb6fca791e0   4 years ago    203MB

# 那个curl_ip就是构建出来的了,接着使用容器运行它

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker run -it 050
47.120.34.132

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker run curl_ip:test -i
HTTP/1.1 200 OK
date: Thu, 03 Oct 2024 10:09:24 GMT
content-type: text/plain; charset=utf-8
Content-Length: 13
access-control-allow-origin: *
via: 1.1 google
strict-transport-security: max-age=2592000; includeSubDomains

47.120.34.132

# 可以发现两个都可以

那么CMD呢,把dockerfile改一下就好了

FROM ubuntu:20.04
RUN apt update && apt install curl -y
CMD ["curl", "-s", "http://ipinfo.io/ip"]

接着构建,运行

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker run -it f28 
47.120.34.132

# 显然直接运行出一个容器是没问题的

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker run curl_ip:test -i
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-i": executable file not found in $PATH: unknown.

# 加上 -i 参数,发现报错了

[root@iZf8z1f6vdo3jdz69xilspZ curl_ip]# docker run curl_ip:test curl -s http://ipinfo.io/ip -i
HTTP/1.1 200 OK
date: Fri, 04 Oct 2024 00:27:08 GMT
content-type: text/plain; charset=utf-8
Content-Length: 13
access-control-allow-origin: *
via: 1.1 google
strict-transport-security: max-age=2592000; includeSubDomains

# 当你自己在后面把完整的命令输入之后才行

这就是为什么说,CMD 指令可以被覆盖,是默认执行的命令

当你运行时的 COMMAND 有了其他指令,docker 就会优先处理其他指令,而CMD 就被覆盖了

而 ENTRYPOINT 指令不可被覆盖,是主要执行的命令

这时就不需要在运行容器时加其他指令,但是可以加参数

下面是来自[菜鸟教程的原文](Docker Dockerfile | 菜鸟教程 (runoob.com))

CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD 在docker run 时运行。
  • RUN 是在 docker build。

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参 

1、不传参运行

docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf

2、传参运行

docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

ADD & COPY

ADD

ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。

ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]

[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/
COPY hom?.txt /mydir/

ENV & ARG

ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

ARG

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。

格式:

ARG <参数名>[=<默认值>]