1. docker简介

docker镜像:由各种文件和元数据(环境变量、端口映射…)组成

docker容器:是镜像的运行实例,可以在基础镜像上做增删改查等

docker分层:每一次对原始镜像的修改都会形成新的一层,一层层的叠加,多个不同的容器实例可以共享原始镜像,并在磁盘记录新的修改,即采用写时复制的技术,可以节省磁盘空间

docker基本架构如下图

2. docker hub

docker hub是docker官方维护的一个公共仓库

把本地镜像上传到docker hub,比如我想把本地的centos镜像上传到docker hub

首先在本地登录docker hub,可以用命令docker login,看到Login Succeeded表示登录成功,可以使用docker logout退出登录

MacBook-Pro-2 ~ % docker login -u 564445  # 564445是我的docker id
Password: 
Login Succeeded

Logging in with your password grants your terminal complete access to your account. 
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/

然后用docker tag给要上传的镜像打标签,先用命令docker images查看centos镜像

MacBook-Pro-2 ~ % docker images
REPOSITORY               TAG       IMAGE ID       CREATED        SIZE
nginx                           v1         6952426e983e   7 days ago     142MB
nginx                           latest    0e901e68141f     2 weeks ago    142MB
debian                         latest    4eacea30377a   2 weeks ago    124MB
registry                        2          773dbf02e42e   2 weeks ago    24.1MB
centos                         latest    5d0da3dc9764   9 months ago   231MB
MacBook-Pro-2 ~ %

然后用命令docker tag 5d0da3dc9764 564445/centos:v1,564445是docker id,v1是自定义的版本号,再查看镜像会多出一个564445/centos

MacBook-Pro-2 ~ % docker images
REPOSITORY               TAG       IMAGE ID       CREATED        SIZE
nginx                           v1         6952426e983e   7 days ago     142MB
nginx                           latest    0e901e68141f     2 weeks ago    142MB
debian                         latest    4eacea30377a   2 weeks ago    124MB
registry                        2          773dbf02e42e   2 weeks ago    24.1MB
564445/centos             v1        5d0da3dc9764   9 months ago   231MB
centos                         latest    5d0da3dc9764   9 months ago   231MB
MacBook-Pro-2 ~ %

然后用docker push命令上传到docker hub

MacBook-Pro-2 ~ % docker push 564445/centos:v1 
The push refers to repository [docker.io/564445/centos]
74ddd0ec08fa: Mounted from library/centos 
v1: digest: sha256:a1801b843b1bfaf77c501e7a6d3f709401a1e0c83863037fa3aab063a7fdb9dc size: 529
MacBook-Pro-2 ~ %

然后在docker hub就可以看到刚刚上传的镜像了

上面讲的是如何把本地镜像上传到docker hub,那如果我想把本地容器上传到docker hub呢,其实可以用命令docker commit先把容器变成镜像,例如:docker commit ed9a5c9859b5 image_centos,然后把镜像上传到docker hub的步骤和上面是一样的

若要从自己的docker hub拉取镜像,可以用命令docker pull 564445/centos:v1

3. docker volume

docker数据管理的方式有两种,一种叫做数据卷,即将宿主机文件或者目录直接映射进容器中,可供一个或多个容器使用。另一种叫做数据卷容器,数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其他容器挂载。

数据卷是一个特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount操作,它可以在不同容器之间共享和重用,而且对某容器内数据卷的修改,在其关联的容器会同时生效,但是对数据卷的修改并不会影响镜像。

如果容器被删除,宿主机的数据卷内容并不会被删除,因为数据卷是从外界挂载到容器内部中的,所以可以脱离容器的生命周期而独立存在,数据卷的生命周期会一直持续到没有容器使用它为止,需要用命令删除:docker volume rm myvolume,或docker volume prune,后一条命令主要清除无主的数据卷。

创建一个数据卷docker volume create my_volume

查看本机的所有数据卷docker volume ls

MacBook-Pro-2 ~ % docker volume ls
DRIVER    VOLUME NAME
local        2dbf6d4ac779a3d23c3c395787f104898d72f4776d00f1cafafcb4bafc24b13f
local        my_volume

查看数据卷的信息docker inspect my_volume

MacBook-Pro-2 ~ % docker inspect my_volume
[
    {
        "CreatedAt": "2022-06-13T10:40:55Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my_volume/_data",
        "Name": "my_volume",
        "Options": {},
        "Scope": "local"
    }
]

3.1 数据卷

3.1.1 匿名目录挂载

匿名目录挂载只需要写容器内目录或者文件即可,而宿主机对应的目录会自动在/var/lib/docker/volumes路径下生成对应的文件夹

docker run [OPTIONS] -v 容器目录路径1 [-v 容器目录路径2 ...] -p 主机端口:容器端口 --name=容器名称 镜像ID/镜像名称[:版本号]

例如

MacBook-Pro-2 manu_serv % docker images -a
REPOSITORY                      TAG       IMAGE ID       CREATED        SIZE
image_centos                      latest    8634275bd70f   5 hours ago    231MB

MacBook-Pro-2 manu_serv % docker run -itd -v /centosVolume --name im_centos_vol image_centos #以匿名挂载方式启动
9499039595d236f036d5f15c8d64b20360678717742e3407929850884a504970

MacBook-Pro-2 manu_serv % docker ps
CONTAINER ID   IMAGE          COMMAND   CREATED          STATUS          PORTS     NAMES
9499039595d2   image_centos   "bash"    29 seconds ago   Up 27 seconds             im_centos_vol #容器名
ed9a5c9859b5   centos              "bash"     5 days ago         Up 5 hours                  centosbox1

MacBook-Pro-2 manu_serv % docker exec -it im_centos_vol bash
[root@9499039595d2 /]# ls	 #可见容器内多了一个centosVolume文件夹
bin  centosVolume  dev	etc  home  lib	lib64  lost+found  media  mnt  opt  proc  root	run  sbin  srv	sys  tmp  usr  var

MacBook-Pro-2 manu_serv % docker volume ls
DRIVER    VOLUME NAME
local     16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028

MacBook-Pro-2 manu_serv % docker inspect  16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028
[
    {
        "CreatedAt": "2022-06-13T15:17:40Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028/_data",
        "Name": "16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028",
        "Options": null,
        "Scope": "local"
    }
]

现在检查一下本机的/var/lib/docker/volumes是否有生成卷,因为我的是mac电脑,一般会自动隐藏这个文件路径,需要运行这条命令进去看:

docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

MacBook-Pro-2 manu_serv % docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
/ # ls
bin          containers   etc          home         lib          mnt          proc         run          srv          tmp          var
boot         dev          grpcfuse.ko  init         media        opt          root         sbin         sys          usr
/ # cd var/lib/docker/volumes/
/var/lib/docker/volumes # ls -l
total 22
drwx-----x    3 root     root     4096 Jun 13 14:59 16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028
/var/lib/docker/volumes # 

可见有卷 16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028,现在卷目录内增加两个文件

/var/lib/docker/volumes # cd 16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028/_data/
/var/lib/docker/volumes/16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028/_data # touch aa.md
/var/lib/docker/volumes/16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028/_data # touch bb.txt
/var/lib/docker/volumes/16b118bcac601d4ae72145d671299571818627b38d0757d866b43d346e1a8028/_data # ls
aa.md   bb.txt

然后进到容器的卷目录可以发现文件已经同步过来了

MacBook-Pro-2 omc % docker exec -it 9499039595d2 bash                                              
[root@9499039595d2 /]# ls
bin  centosVolume  dev	etc  home  lib	lib64  lost+found  media  mnt  opt  proc  root	run  sbin  srv	sys  tmp  usr  var
[root@9499039595d2 /]# cd centosVolume/
[root@9499039595d2 centosVolume]# ls
aa.md  bb.txt
3.1.2 具名目录挂载

具名挂载就是给宿主机的数据卷自定义名称,对应的目录还是在 /var/lib/docker/volume/ 下生成

docker run [OPTIONS] -v 宿主机数据卷名称1:容器目录路径1 [-v 宿主机数据卷名称2:容器目录路径2 ...] -p 主机端口:容器端口 --name=容器名称 镜像ID/镜像名称[:版本号]

例如

docker run -itd -v my-local-volume:/centosVolume --name im_centos_vol image_centos
3.1.3 指定目录挂载

指定目录挂载可以自定义宿主机数据卷的路径

docker run [OPTIONS] -v 宿主机目录路径1:容器目录路径1 [-v 宿主机目录路径2:容器目录路径2 ...] -p 主机端口:容器端口 --name=容器名称 镜像ID/镜像名称[:版本号]

例如

docker run -itd -v /centosVolume --name im_centos_vol image_centos

3.2 数据卷容器

操作命令

docker run [OPTIONS]  -p 主机端口:容器端口 --name=容器名称 --volumes-from 数据卷容器ID/名称 生成数据卷容器的镜像ID/名称[:版本号]

4. Dockerfile

Dockerfile是一个文本文件,其中包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建

4.2 dockerfile常用命令

Dockerfile官方参考文档,以下内容皆为官方文档的翻译,另一个推荐的文档:Dockerfile 指令详解

# FROM

FROM [--platform=<platform>] <image> [AS <name>]

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

# FROM指令初始化一个新的构建阶段并为后续指令设置基本映像

# FROM必须是第一条指令,ARG是唯一可以在FROM前面的指令

# FROM可以在单个中出现多次以创建多个镜像或使用一个构建阶段作为另一个构建阶段的依赖项,
# FROM只需在每条新指令之前记下提交输出的最后一个图像 ID 。每条FROM指令都会清除先前指令创建的任何状态。

# 可以通过添加AS name到FROM指令中为新的构建阶段命名。该名称可以在后续FROM和 COPY --from=<name> 说明中使用,以引用此阶段构建的镜像。

# tag或digest值是可选的,如果省略其中任何一个,则构建器默认采用latest标签。如果无法找到该tag值,构建器将返回错误。

# 例:
ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras
# LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...

# LABEL指令为镜像添加标签,当前镜像会继承父镜像的标签,如果与父标签重复,会覆盖之前的标签

# 例:
LABEL multi.label1="value1" multi.label2="value2" other="value3"

LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"
# RUN

# RUN 有两种形式:
RUN <command>(shell形式,命令在 shell 中运行,默认/bin/sh -c在 Linux 或cmd /S /C在Windows 上)

RUN ["executable", "param1", "param2"](执行形式)

# 例:(下面三条指令是等价的)
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

RUN ["/bin/bash", "-c", "echo hello"]
# CMD

#CMD指令有三种形式:
CMD ["executable","param1","param2"](执行形式,这是首选形式)

CMD ["param1","param2"](作为 ENTRYPOINT 的默认参数)

CMD command param1 param2(shell形式)

# Dockerfile中只能有一条CMD指令,如果列出多个CMD,则只有最后一个CMD会生效

# 例:
FROM ubuntu
CMD echo "This is a test." | wc - # shell形式的CMD

FROM ubuntu
CMD ["/usr/bin/wc","--help"] # 如果想在没有shell的情况下运行命令,则必须将命令表示为JSON数组并提供可执行文件的完整路径
# EXPOSE

EXPOSE <port> [<port>/<protocol>...]

# EXPOSE指令通知 Docker 容器在运行时侦听指定的网络端口。可以指定端口监听 TCP 还是 UDP,如果不指定协议,则默认为 TCP

# 如果要同时在 TCP 和 UDP 上公开,在Dockerfile中可以这样写
EXPOSE 80/tcp
EXPOSE 80/udp

# 在终端可以这样运行容器
docker run -p 80:80/tcp -p 80:80/udp ...
# ENV

ENV <key>=<value> ... # 后面可以连续设置变量
ENV <key> <value> # 一次只能设置一个变量

# ENV命令类似于在执行docker run命令运行镜像时指定自动设置的环境变量
# docker run --env <key>=<value>

# 例:
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy

ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
    MY_CAT=fluffy
    
ENV MY_VAR my-value # 省略 =
# ADD

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

# ADD指令从 <src> 路径复制新文件、目录或远程文件 URL,并将它们添加到镜像的文件系统<dest>中。
# <src>可以指定多个资源,如果它们是文件或目录,它们的路径将被解释为相对于构建上下文的源。
# 每个都<src>可能包含通配符

# 例:
ADD hom* /mydir/
ADD hom?.txt /mydir/

# 将“test.txt”添加到<WORKDIR>/relativeDir/:
ADD test.txt relativeDir/

# 而本示例使用绝对路径,并将“test.txt”添加到/absoluteDir/
ADD test.txt /absoluteDir/

# 添加包含特殊字符(如[ and ])的文件或目录时,您需要按照 Golang 规则对这些路径进行转义,
# 以防止它们被视为匹配模式。例如,要添加一个名为 的文件arr[0].txt
ADD arr[[]0].txt /mydir/

# 所有新创建的文件和目录的UID和GID都为0,除非使用--chown指定UID/GID以及权限。
# -chown特性仅在用于构建Linux容器。
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
# COPY

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

# 该COPY指令从路径复制新文件或目录<src> 并将它们添加到容器的文件系统中<dest>。
# <src>可以指定多个资源,但文件和目录的路径将被解释为相对于构建上下文的源。
# 每个都<src>可能包含通配符

# COPY 指令和 ADD 指令的唯一区别在于:是否支持从远程URL获取资源。
# COPY 指令只能从执行 docker build 所在的主机上读取资源并复制到镜像中。
# 而 ADD 指令还支持通过 URL 从远程服务器读取资源并复制到镜像中。
# ENTRYPOINT

# ENTRYPOINT有两种形式:
# exec形式,这是首选形式:
ENTRYPOINT ["executable", "param1", "param2"]
# shell形式:
ENTRYPOINT command param1 param2

# ENTRYPOINT和CMD一样,都是在指定容器启动程序以及参数,cmd给出的是一个容器的默认的可执行体,
# 如果docker run没有指定任何的执行命令或dockerfile里也没有entrypoint,就会使用cmd指定的默认的执行命令执行
# 同时也说明了entrypoint的含义,它才是真正的容器启动以后要执行命令。
# 如果在docker run时指定了命令或者有entrypoint,那么cmd就会被覆盖。

# 关于ENTRYPOINT详解可以访问官网:
# https://docs.docker.com/engine/reference/builder/#entrypoint

# ENTRYPOINT和CMD的区别可以访问官网:
# https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact
# VOLUME

VOLUME ["/data"]

# VOLUME指令在容器创建一个具有指定名称的挂载数据卷,并将其标记为保存来自本机或其他容器的数据卷

# 例:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol    #表示目录myvol是数据卷在当前容器的位置,存放的是数据卷内共享的数据
# USER

USER <user>[:<group>]
USER <UID>[:<GID>]

# 指令USER设置运行映像时使用的用户名(或 UID)和可选的用户组(或 GID)
# 用于运行Dockerfile中接下来的RUN、CMD、ENTRYPOINT指令

# 例:
FROM microsoft/windowsservercore
# 在容器创建windows用户
RUN net user /add patrick
USER patrick
# WORKDIR

WORKDIR /path/to/workdir

# WORKDIR指令为Dockerfile中接下来的RUN、CMD、ENTRYPOINT、ADD、COPY指令设置工作目录。
# 如果WORKDIR不存在,及时它没有在后续Dockerfile指令中使用,它也会被创建。
# Dockerfile中可以多次使用WORKDIR,如果提供了相对路径,它将相对于前一条WORKDIR指令的路径。

# 最终 pwd 命令的输出是 /a/b/c
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

# WORKDIR 指令可以解析先前使用 ENV,例如:
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
# 最终 pwd 命令的输出是 /path/$DIRNAME。
# ONBUILD

ONBUILD <INSTRUCTION>

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

# 注意:ONBUILD指令不能触发FORM和MAINTAINER指令

# 例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

6. 参考链接

https://www.topgoer.cn/docs/docker/docker-1cbqgmmc4pf24

https://blog.csdn.net/lijingjingchn/article/details/118154601

https://blog.csdn.net/weixin_45880055/article/details/118051847

https://docs.docker.com/engine/reference/builder/

https://blog.csdn.net/weixin_38299159/article/details/120429294

https://blog.csdn.net/m0_46090675/article/details/121846718