Docker 是一个开源的应用容器引擎,基于 Go 语言 开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,容器性能开销极低。Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)。

基本概念

在使用Docker前,首先要先知道Docker中这几个常用的概念:

  • 镜像(image):镜像是文件,只读的,提供了运行完整软硬件应用程序的集装箱。
  • 容器(container):镜像的实例,由Docker负责创建,容器之间彼此隔离,容器可以被创建,删除,停止。
  • 仓库(hub):用来保存镜像,可以理解为代码控制中的代码仓库,Docker官方仓库名字是Docker Hub

更多内容,通过访问Docker官方网站获取:https://www.docker.com/

安装

Docker支持的平台和操作系统很广泛,支持Linux/Windows/Mac系统,下面基于Ubuntu 20.04LTS进行安装。
如果已经安装过旧版本的Docker,需要先移除相关依赖

  1. sudo apt-get remove docker docker-engine docker.io containerd runc

安装网络相关依赖包,用于通过HTTPS来获取仓库

  1. sudo apt-get install \apt-transport-https
  2. \ca-certificates
  3. \curl
  4. \gnupg-agent
  5. \software-properties-common

添加 Docker 的官方 GPG 密钥

  1. curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

添加仓库安装源

  1. sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

更新软件包源并安装Docker

  1. sudo apt update && sudo apt install -y docker-ce

安装完成后Docker会自动启动,执行命令查看Docker状态

  1. starsray@starsray:~/IdeaProjects$ systemctl status docker
  2. docker.service - Docker Application Container Engine
  3. Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
  4. Active: active (running) since Sat 2022-03-26 17:03:00 CST; 1 day 6h ago
  5. Docs: https://docs.docker.com
  6. Main PID: 2269 (dockerd)
  7. Tasks: 55
  8. Memory: 235.1M
  9. CGroup: /system.slice/docker.service
  10. ├─ 2269 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
  11. ├─ 2754 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3306 -container-ip 172.18.0.2 -container-port 330
  12. ├─29543 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 9200 -container-ip 192.168.112.2 -container-port
  13. ├─30233 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 12800 -container-ip 192.168.112.3 -container-port
  14. ├─30247 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 11800 -container-ip 192.168.112.3 -container-port
  15. └─30360 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 39043 -container-ip 192.168.128.3 -container-port
  16. Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.

如果提示没有权限

  1. starslight@starslight:/etc/apt/sources.list.d$ docker search elasticGot permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/search?limit=25&term=elastic: dial unix /var/run/docker.sock: connect: permission denied

新建一个docker用户组,并将登陆用户添加到docker用户组

  1. sudo groupadd docker #添加docker用户组
  2. sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中
  3. newgrp docker #更新用户组

如果在下载过程中出现下载过慢的情况,可以配置阿里云镜像加速来提升下载速度,登录阿里云控制台,搜索容器镜像服务,此步骤为非必要步骤,对速度无要求可以忽略。
Docker入门应用 - 图1
执行下面命令:

  1. sudo mkdir -p /etc/docker
  2. sudo tee /etc/docker/daemon.json <<-'EOF'
  3. {
  4. "registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]
  5. }
  6. EOF
  7. sudo systemctl daemon-reload
  8. sudo systemctl restart docker

创建配置文件,重启Docker服务就可以使用阿里云帮我们提供的Docker镜像加速服务了。
或者使用以下国内镜像服务进行加速。

  1. {
  2. "registry-mirrors": [
  3. "https://registry.docker-cn.com",
  4. "http://hub-mirror.c.163.com",
  5. "https://docker.mirrors.ustc.edu.cn"
  6. ]
  7. }

基本架构

  1. 基本结构

Docker使用客户端-服务器(C/S)架构模式,通过下面这个图可以简单清晰看出Server/Client通信,容器和镜像、数据之间的关系系,用户无法直接和Docker Server进行交互。
Docker入门应用 - 图2
Docker是提供应用打包,部署与运行应用的容器化平台,Docker整体可以大致分为三部分:

  • 内层:Server,可以是本地的也可以时远程的,接收并分发Client端发起的请求。
  • 中间层:REST API,使用HTTP协议简历Client与Server之间的通信。
  • 外层:Client 通过中间层向Docker Server发起请求,执行命令。
  1. Docker服务执行流程

Docker整个执行流程参与的角色可以分为三个部分,客户端(Client)、服务端(Daemon)、仓库(Registry),
其中客户端与服务端通过REST API完成交互,通过docker命令完成镜像、容器、仓库构建、打包等操作。
image.png

  • Docker Client:是用户与 Docker 交互的主要方式。 当使用 docker run 等命令时,客户端会将这些命令发送给 守护进程,守护进程会执行这些命令。docker命令执行使用的是Docker API,Docker 客户端可以与多个守护进程通过REST API进行通信。
  • Docker Daemon:监听 Docker API 请求并管理 Docker 对象,例如镜像、容器、网络和卷。 守护进程还可以与其他守护进程通信以管理 Docker 服务。
  • Docker Registry:仓库中心存储 Docker 镜像, Docker 默认配置为在 Docker Hub 上查找镜像。 也可以搭建仓库私服。当使用 docker pull 或 docker run 命令时,将从配置的注册表中提取所需的镜像。 当使用 docker push 命令时,您的图像会被推送到您配置的仓库中。
  1. 容器生命周期

执行docker命令会导致容器的生命周期进行变化,生命周期与命令的对应关系如下图所示:
Docker入门应用 - 图4

  • docker run 命令包含 docker create 和 docker start两个状态
  • docker create 单执行,则会进入停止状态
    • 执行docker start 进入开始状态
    • docker destroy 删除容器
  • docker kill 或者 docker stop 都置die状态,紧接着进入stop状态
    • docker kill 后进行docker start 创建新进程
    • docker stop 后进行docker start 进入恢复
  • docker restart 可以重启
  • docker pause 进行暂停状态

内存溢出OOM,会置die,可以使用docker ps -a查看所有被激活容器的状态。

Docker file

Dockerfile是由一系列命令和参数构成的脚本,Docker可以根据这个脚本基于某个基础镜像创建一个新的定制化的镜像,大大提高了我们部署的效率,使用Dockfile最终的结果是帮助我们定制化自己的镜像。

基本命令

  • FROM 指定基础镜像

    1. FROM <image>
    2. FROM <image>:<tag>
    3. FROM <image>@<digest>

    指定基准镜像,类似JAVA的继承,FROM使用在其他指令之前,其他指令的操作依赖于FROM指令;如果不依赖于其他镜像,构建初始镜像可使用FROM scratch命令。

  • LABEL 为镜像添加元数据

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

    LABEL指令给镜像添加元数据,也可以看作镜像的标签,对于镜像信息的描述。 LABEL指令是键值对形式的如果value中有空格,可以使用引号和\,例:LABEL desc=”This is a test lable”。 一个镜像可以有多个LABEL,新添加LABEL会覆盖原有重名LABEL,并且LABEL是分层的,每个LABEL标签都会构建一层镜像,可以使用合并写法,例如 LABEL multi.label1=”value1” \

    1. multi.label2="value2" \
    2. other="value3"

    或 LABEL multi.label1=”value1” multi.label2=”value2” other=”value3” 镜像的LABEL信息可以使用 docker inspect image:来查看

  • MAINTAINER 指定镜像维护者信息

    1. MAINTAINER <name>

    该指令现在已经被废弃,建议使用LABEL来指定,例:LABEL maintainer=”starsray.cnblogs.com”。

  • ADD 复制文件

    1. ADD <src> <dest>
    2. ADD ["<src>","<dest>"]

    从src路径复制指定内容到dest路径,src可以是Dockfile相对路径,也可以是一个URL,还可以是一个压缩包。 拷贝文件时可识别压缩包格式,docker会自动解压。 若src是一个URL,dest不以斜杠结尾,dest将会被视为文件,src对应内容将会被下载到dest文件。 若src是一个URL,dest以斜杠结尾,dest将会被视为目录,src对应内容将会被下载到dest目录。 若src是一个目录,整个目录下的内容,包括文件系统元数据将会被拷贝至dest目录。

  • WORKDIR 指定工作目录

    1. WORKDIR /path

    指定工作目录,相当于cd /path,path不存在可以自动创建,为指令RUN,CMD,ENTRYPOINT指定工作目录,以WORKDIR目录为当前目录。

  • ARG 设置构建参数

    1. ARG <name>[=<default value>]

    定义构建镜像时需要的参数,可用于FROM指令前。 ARG指令定义的参数,在docker build命令中以—build-arg a_name=a_value形式赋值。 Dockerfile中可以使用ARG定义一个变量,也可以定义多个变量,变量定义时可设置默认值,在build时传递参数则使用参数,未传递参数则使用默认值。 ARG变量定义从在Dockerfile定义的行生效,而不是从在命令行参数的使用或其它地方。 RUN指令可运行使用ARG或ENV指令定义的变量。使用ENV定义的环境变量会覆盖ARG指令定义的同名变量。 Dcoker中预设的一组ARG变量不需要预设即可使用,在执行docker —build-arg a_name=a_value即可使用。 HTTP_PROXY 、http_proxy 、HTTPS_PROXY、https_proxy、FTP_PROXY、ftp_proxy、NO_PROXY 、no_proxy 在构建镜像过程中如果ARG传递的参数未定义会出现警告。 [root@starsraywebapps]# docker build —build-arg xxccx=conly -t conly . Sending build context to Docker daemon 4.608kB Step 1/5 : from tomcat:latest —-> 6408fdc94212 … [Warning] One or more build-args [xxccx] were not consumed Successfully built 61e9f6346096 Successfully tagged conly:latest 关于ARG的更多使用可以参考https://www.centos.bz/2016/12/dockerfile-arg-instruction/

  • CMD 容器启动指令

    1. CMD ["executable", "param1", "param2"] (推荐使用)
    2. CMD ["param1", "param2"] 为[ENTRYPOINT]指令提供预设参数
    3. CMD command param1 param2 shell中执行

    用于在Docker容器创建时执行默认的命令,CMD命令可以有多个,但只会执行最后一个,CMD命令可以被覆盖。 如果使用docker run 创建容器时附加了其他命令则默认的CMD命令不会被执行,执行附加命令。

  • RUN 执行命令

    1. RUN <command> shell命令格式
    2. RUN ["executable", "param1", "param2"] exec命令格式

    用于在Docker镜像构建时执行命令,镜像构建结束,RUN命令也就结束执行。

  • COPY 复制文件

    1. COPY <src> <dest>
    2. COPY ["<src>", "<dest>"]

    复制本地的src文件到dest目录,功能类似于ADD,COPY不支持URL和压缩包。

  • ENTRYPOINT 入口点

    1. ENTRYPOINT ["executable", "param1", "param2"]
    2. ENTRYPOINT command param1 param2

    用于在Docker容器创建时执行命令,ENTRYPOINT 可以存在多个,但只会执行最后一个,ENTRYPOINT运行的命令不可被覆盖。

  • ENV 设置环境变量

    1. ENV <key> <value>
    2. ENV <key>=<value> ...

    设置环境变量,会被RUN指令使用,并在容器运行时保持。例:ENV JAVA_HOME /path/to/java。

  • EXPOSE 声明暴漏的端口

    1. EXPOSE <port> [<port>...]

    用于声明容器运行时提供服务的端口,便于镜像使用者查看该镜像服务的守护端口,运行时并不会因为声明就打开相应端口。 当运行时使用随机映射时,会自动映射EXPOSE的端口。 例:docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 -d image:

  • USER 设置用户

    1. USER <daemon>

    该指令用于指定容器运行时的用户或者UID,RUN、CMD以及ENTRYPOINT指令都将使用该用户执行命令。 例:RUN groupadd -r postgres && useradd -r -g postgres postgres

  • VOLUME 定义匿名卷

    1. VOLUME ["<路径1>", "<路径2>"...]
    2. VOLUME <路径>

    容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

  • HEALTHCHECK 健康检查

    1. HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
    2. HEALTHCHECK NONE:如果基础镜像有健康检查命令,使用这行可以屏蔽掉其健康检查命令

    HEALTHCHECK 命令通过特定参数告诉Docker如何进行容器的健康状态检查,在Docker 1.12 引入。在没有 HEALTHCHECK 命令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。这种形式存在一些问题,如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了,但却还在接受用户请求。引入HEALTHCHECK后,用该命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。

    当在一个镜像指定了 HEALTHCHECK 指令后,启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy。HEALTHCHECK 支持下列选项:

    • —interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
    • —timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
    • —retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。
  • SHELL 指令

    1. SHELL ["executable", "parameters"]

    SHELL 指令可以指定 RUN ENTRYPOINT CMD 指令的 shell,Linux 中默认为 [“/bin/sh”, “-c”]

更多命令参考官方文档:https://docs.docker.com/engine/reference/builder/

相似命令解释

Docker file中包含了很多含义近似的命令,但是在实际使用中还是有所不同的,下面对一些常用相似命令进行详细分析:

  1. RUN、CMD、ENTRYPOINT的区别
  • 执行时机不同,RUN指令在镜像构建时使用,CMD | ENTRYPOINT在容器创建时使用。
  • CMD是默认执行命令,可以被覆盖,原有命令不一定执行,ENTRYPOINT不可以被覆盖,一定会被执行。
  • ENTRYPOINT和CMD命令可以组合使用,将CMD命令当作ENTRYPOINT命令的参数来执行,例:
    ENTRYPOINT [“ps”] CMD [“-ef”]镜像构建完成,如果使用docker run image -aux,则原有CMD命令在执行时会被替换为ps -aux,这种方式实现了动态传参,不用修改Dockerfile重新构建镜像就可以在创建容器上执行自定义命令。
  1. ARG和ENV的区别
  • 从语义上看ARG是用来设置构建镜像时参数的,设置参数仅在构建时期有用,ENV用来设置环境变量,可以保存在容器运行时。
  • Dockerfile中声明ARG后可以设定默认值,也可以构建时传参设置,ENV设置的环境变量可以覆盖ARG声明的同名参数。
  • Dockerfile中ARG和ENV可以配合使用,类似于ENTRYPOINT和CMD指令。

    1. # use the value to set the ENV var default
    2. ARG A_VARIABLE
    3. ENV an_env_var=$A_VARIABLE
  • 需要注意的是虽然使用ARG设置的参数仅在构建时有效,但是使用docker history Docker入门应用 - 图5:还是可以查看构建记录,尽量避免传递密钥,password等敏感信息。

    1. [root@conly webapps]# docker build -t tomcat:0.1 .
    2. Sending build context to Docker daemon 4.608kB
    3. Step 1/7 : ARG user=test_user
    4. ...
    5. Step 7/7 : ADD https://images.cnblogs.com/cnblogs_com/conly/1600508/o_191211120217min.png ./docker-web
    6. Downloading [==================================================>] 230.1kB/230.1kB
    7. ---> Using cache
    8. ---> 61e9f6346096
    9. Successfully built 61e9f6346096
    10. Successfully tagged tomcat:0.1
    11. [root@conly webapps]# docker history tomcat:0.1
    12. IMAGE CREATED CREATED BY SIZE COMMENT
    13. ...
    14. <missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 8080 0B
    15. <missing> 2 weeks ago /bin/sh -c set -e && nativeLines="$(catalin… 0B
    16. ...
    17. <missing> 2 weeks ago /bin/sh -c #(nop) ENV TOMCAT_MAJOR=8 0B
    18. <missing> 2 weeks ago /bin/sh -c #(nop) ENV GPG_KEYS=05AB33110949… 0B
    19. <missing> 2 weeks ago /bin/sh -c #(nop) ENV LD_LIBRARY_PATH=/usr/… 0B
    20. ...
  • 完整信息命令

    1. docker history --format "table {{.ID}}\t{{.CreatedBy}}" --no-trunc image:<tag>
  1. ADD和COPY的区别
  • ADD和COPY都可以用来拷贝源文件到指定目录,在这点上用法一致。
  • ADD的源可以是本地也可以是远程的,COPY只能是本地文件。
  • 使用ADD来拷贝可识别的压缩文件时,如.tar,.war可以自动解压,COPY则不具备。
  • COPY可用于multi-stage中,复制上一阶段的镜像,详细内容看参考use multi-stage builds。此功能在Docker17.05以后才添加,极大方便了Dockerfile的维护者。

    首次使用 COPY 和 ADD 命令时也没有考虑过太多二者的区别,随着对Docker的使用会发现 COPY 命令的设计是简单,概念清晰的。而 ADD 命令是在COPY命令上的扩展,提高了使用的复杂度,尤其在使用ADD添加源为URL的情况,要注意dest路径的结尾有没有/,但这些设计在我们熟悉Docker后也会方便操作。

  1. shell和exec区别

    这两个命令并非Docker中的命令,是Linux操作系统中的命令。

  • shell 在Linux系统中,使用shell执行时脚本时,当前shell为父进程,会生成一个子进程来执行脚本,执行完毕后会退出子进程回到当前shell。
  • exec 使用exec执行时,exec进程会替换当前进程,进程PID保持不变执行结束直接退出,不会退出到进程执行之前的环境,官方推荐使用。

    Docker应用

    基本使用

    以上介绍了Docker中基本概念、工作模式、以及Dockerfile的相关内容,接下来对Docker的基本使用做一下介绍。包括镜像的拉取到容器的运行终止过程,以Tomcat镜像为例:
  1. 查找镜像

搜索Docker hub提供的Tomcat镜像源:

  1. root@starsray:~# docker search tomcat
  2. NAME DESCRIPTION STARS OFFICIAL AUTOMATED
  3. tomcat Apache Tomcat is an open source implementati 3294 [OK]
  4. tomee Apache TomEE is an all-Apache Java EE certif 95 [OK]
  5. bitnami/tomcat Bitnami Tomcat Docker Image 44 [OK]
  6. kubeguide/tomcat-app Tomcat image for Chapter 1 33
  7. arm32v7/tomcat Apache Tomcat is an open source implementati 11
  8. arm64v8/tomcat Apache Tomcat is an open source implementati 7
  9. rightctrl/tomcat CentOS , Oracle Java, tomcat application ssl 7 [OK]
  10. amd64/tomcat Apache Tomcat is an open source implementati 4
  11. jelastic/tomcat An image of the Tomcat Java application serv 3
  12. tomcat2111/pisignage-server PiSignage Server 3 [OK]
  13. cfje/tomcat-resource Tomcat Concourse Resource 2
  14. ...

使用search命令搜索出的包含了官方和非官方的镜像源,而且都是最新版本,如果想搜索某个镜像的历史版本可以使用下面脚本来辅助操作

  1. sudo mkdir -p /opt/script
  2. sudo tee /opt/script/docker-search-tag.sh <<-'EOF'
  3. #!/bin/sh
  4. #
  5. # Simple script that will display docker repository tags.
  6. #
  7. # Usage:
  8. # $ docker-show-repo-tags.sh ubuntu centos
  9. for Repo in $* ; do
  10. curl -s -S "https://registry.hub.docker.com/v2/repositories/library/$Repo/tags/" | \
  11. sed -e 's/,/,\n/g' -e 's/\[/\[\n/g' | \
  12. grep '"name"' | \
  13. awk -F\" '{print $4;}' | \
  14. sort -fu | \
  15. sed -e "s/^/${Repo}:/"
  16. done
  17. EOF

授予脚本可执行权限,并且添加软连接到可执行目录

  1. sudo chmod +x docker-search-tag.sh
  2. sudo ln -s /opt/script/docker-search-tag.sh /usr/local/bin/

使用添加的脚本命令搜索Redis镜像tag列表,相关tag都被展示出来了。

  1. starsray@starsray:/usr/bin$ docker-search-tag.sh redis
  2. redis:6.2
  3. redis:6.2.6
  4. redis:6.2.6-bullseye
  5. redis:6.2-bullseye
  6. redis:7.0-rc
  7. redis:7.0-rc2
  8. redis:7.0-rc2-bullseye
  9. redis:7.0-rc-bullseye
  10. redis:bullseye
  11. redis:latest
  1. 拉取镜像

执行拉取命令

  1. docker pull tomcat

或者指定版本:

  1. docker pull tomcat:8.5.49-jdk8-openjdk
  1. 创建容器

使用run命令通过镜像来创建一个Tomcat容器

  1. docker run tomcat
  1. 端口映射

直接使用docker run启动的容器是在当前shell窗口前台进程运行,如果没有指定端口映射,宿主机和容器之间是无法进行通信的,可以使用如下命令来重新启动容器

  1. docker run -p 8080:8080 -d tomcat
  • -p 映射端口:容器端口
  • -d 表示在后台运行容器

    需要注意的是,使用run启动后的容器,无法再进行参数修改,容器的生命周期可以查看上面部分的描述。此外端口映射解决的是宿主机与容器间的通信,通常还需要容器间的通信,下面介绍。

  1. 常用命令

docker中常用命令如下:

  1. # 搜索镜像资源
  2. docker search <imageName>
  3. # 拉取远程仓库镜像
  4. docker pull <imageName>:<tags>
  5. # 查看已下载镜像
  6. docker images
  7. # 创建容器,启动应用
  8. docker run <imageName>
  9. # 查看正在运行的镜像
  10. docker ps
  11. # 删除容器 添加-f参数强制删除
  12. docker rm <containerID>
  13. # 删除镜像
  14. docker rmi
  15. # 查看容器历史记录
  16. docker logs containerID
  17. # 查看镜像的构建历史
  18. docker history <imageName>
  19. # 宿主机与容器之间拷贝资源
  20. docker cp <FROM> <TO>

docker中还提供了一些其他命令:

  1. # 查看镜像、容器、数据卷所占用的空间
  2. docker system df
  3. # 通过容器创建一个新的镜像(慎用,建议使用Dcokerfile来创建镜像)
  4. docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
  1. 容器内部结构

Docker创建的容器后,可以使用命令进入容器内部,查看容器的信息

  1. docker exec [-it] 容器id 命令
  • 其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。此处通常需要提供一个shell来执行,一般为/bin/bash。

进入容器后,就可以对Docker容器一探究竟,此处以tomcat容器为例,容器内部结构如图所示:包含了tomcat运行的必备环境。
Docker入门应用 - 图6
进入/usrl/ocal目录,执行ls查看容器内部包含的资源

  1. root@3c7488f8d35a:/usr/local# ls /usr/local/ aegis bin etc games include lib man openjdk-8 sbin share src tomcat

在容器内部,建立在一个Linux系统基础之上的,支持了应用程序所能运行的最小安装,包含内核,网络等相关核心系统组件,以及应用运行所需要的JDK和Tomcat。
退出容器

  1. exit
  1. 数据卷挂载

通过容器内部结构的查看,会发现存在一个问题,应用运行所需要的配置信息都在容器内部,且容器没有启动时无法进行修改,修改配置信息时就很不方便,而且如果数据信息存储在容器内,当容器因为某些原因挂掉时,对于数据恢复也是灾难性的,因此Docker提供了数据挂载的功能(Docker Volume:数据卷)。
Docker入门应用 - 图7
Docker Volume是保存由 Docker 容器生成和使用的数据的首选机制。 虽然绑定挂载依赖于主机的目录结构和操作系统,但卷完全由 Docker 管理。 与绑定挂载相比,卷有几个优点:

  • 卷比绑定挂载更容易备份或迁移
  • 可以使用 Docker CLI 命令或 Docker API 管理卷
  • 卷适用于 Linux 和 Windows 容器
  • 卷可以在多个容器之间更安全地共享
  • 卷驱动程序允许将卷存储在远程主机或云服务器,以加密卷的内容或添加其他功能
  • 新卷的内容可以由容器预先填充。
  • Docker Desktop 上的卷比来自 Mac 和 Windows 主机的绑定挂载具有更高的性能。

此外,与在容器的可写层中持久化数据相比,卷通常是更好的选择,因为卷不会增加使用它的容器的大小,并且卷的内容存在于给定容器的生命周期之外。如果容器生成非持久状态数据,可以使用 tmpfs 挂载以避免将数据永久存储在任何地方,并通过避免写入容器的可写层来提高容器的性能。

使用数据卷挂载的方式也很简单,在创建容器时使用-v参数来指定需要关联的文件位置。

  1. docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

更多内容可以参考:https://docs.docker.com/storage/volumes/

  1. 容器间通信

容器和宿主机之间的通信可以通过端口映射的方式来实现,容器之间的通信,docker也提供了相应API。可以使用link或者network相关的功能来实现容器间通信。

  • docker link

link功能的使用方式如下:

  1. --link <name or id>:alias

例如关联elasticsearch和kibana,使其进行容器间通信

  1. docker run --name kibana --link=elasticsearch -p 5601:5601 -d kibana:7.12.0

需要注意的是:

The —link flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it, we recommend that you use user-defined networks to facilitate communication between two containers instead of using —link. One feature that user-defined networks do not support that you can do with —link is sharing environment variables between containers. However, you can use other mechanisms such as volumes to share environment variables between containers in a more controlled way. —link 标志是 Docker 的遗留功能。 它最终可能会被删除。 除非您绝对需要继续使用它,否则我们建议您使用用户定义的网络来促进两个容器之间的通信,而不是使用 —link。 用户定义的网络不支持您可以使用 —link 执行的一项功能是在容器之间共享环境变量。 但是,您可以使用其他机制(例如卷)以更可控的方式在容器之间共享环境变量。

  • docker network

docker network是官方推荐的容器间进行通信的使用方式,而且功能强大,包含不同的网络链接方式,支持单机集群环境下使用,下面主要针对单机环境下的使用方式进行介绍。
Docker安装完成后默认包含以下几种链接方式

  1. root@starsray:~# docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. cb33e874f2c6 bridge bridge local
  4. 4627f6c080f0 host host local
  5. 5c0a8d18036c none null local

bridge是官方推荐的链接方式,而且后面两种方式尚且不成熟。使用network的方式也很简单,例如

  1. docker run -it --network some-network --rm mysql mysql -hsome-mysql -uexample-user -p

通过—network来指定容器网络信息,当两个容器指向同一个网络就可以进行互通。
查看network bridge相关信息

  1. root@starsray:~# docker network inspect bridge
  2. [
  3. {
  4. "Name": "bridge",
  5. "Id": "cb33e874f2c660cde0c36c69c38b796860c87b6ebed5127a78d5bb88ccb2bf90",
  6. "Created": "2022-03-26T20:10:59.296202231+08:00",
  7. "Scope": "local",
  8. "Driver": "bridge",
  9. "EnableIPv6": false,
  10. "IPAM": {
  11. "Driver": "default",
  12. "Options": null,
  13. "Config": [
  14. {
  15. "Subnet": "172.17.0.0/16",
  16. "Gateway": "172.17.0.1"
  17. }
  18. ]
  19. },
  20. "Internal": false,
  21. "Attachable": false,
  22. "Ingress": false,
  23. "ConfigFrom": {
  24. "Network": ""
  25. },
  26. "ConfigOnly": false,
  27. "Containers": {},
  28. "Options": {
  29. "com.docker.network.bridge.default_bridge": "true",
  30. "com.docker.network.bridge.enable_icc": "true",
  31. "com.docker.network.bridge.enable_ip_masquerade": "true",
  32. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
  33. "com.docker.network.bridge.name": "docker0",
  34. "com.docker.network.driver.mtu": "1500"
  35. },
  36. "Labels": {}
  37. }
  38. ]

Docker中还提供了网络操作相关的其他命令

  1. root@starsray:~# docker network
  2. Usage: docker network COMMAND
  3. Manage networks
  4. Commands:
  5. connect Connect a container to a network
  6. create Create a network
  7. disconnect Disconnect a container from a network
  8. inspect Display detailed information on one or more networks
  9. ls List networks
  10. prune Remove all unused networks
  11. rm Remove one or more networks

更多network相关资料:https://docs.docker.com/network/

自定义镜像

实践才能加深理论并且更有助于理解,接下来基于CentOS7来自定义Redis的Docker镜像。
下载redis-5.0.5安装包

  1. wget http://download.redis.io/releases/redis-5.0.5.tar.gz

下载redis.conf配置文件

  1. wget http://download.redis.io/redis-stable/redis.conf

修改redis.conf

  1. bind 127.0.0.1 --> #bind 127.0.0.1
  2. daemonize no --> daemonize yes
  3. protected-mode yes --> protected-mode no

创建Dockerfile,并编写文件内容

  1. ARG desc
  2. FROM centos
  3. LABEL maintainer=www.cnblogs.com/starsray/
  4. RUN ["yum","-y","install","gcc","gcc-c++","net-tools","make"]
  5. WORKDIR /usr/local
  6. ADD redis-5.0.5.tar.gz .
  7. WORKDIR /usr/local/redis-5.0.5/src/
  8. RUN make && make install
  9. WORKDIR /usr/local/redis-5.0.5
  10. ADD redis.conf .
  11. EXPOSE 6379
  12. CMD ["redis-server","redis.conf"]

构建自定义image镜像

  1. docker build --build-arg desc="this is a docker image build test" -t starsray/redis:5.0.5 .

构建过程日志如下

  1. [root@starsray redis_dockertest]# docker build --build-arg desc="this is a docker image build test" -t conly/redis:1.0 .
  2. ...
  3. ...
  4. ...
  5. Removing intermediate container 528d15f50a03
  6. ---> 809289100143
  7. Step 9/14 : WORKDIR /usr/local/redis-5.0.5
  8. ---> Running in 566b63100414
  9. Removing intermediate container 566b63100414
  10. ---> 9cfce44318ee
  11. Step 10/14 : ADD redis.conf .
  12. ---> dc8127dafb54
  13. Step 11/14 : EXPOSE 6379
  14. ---> Running in eda8f77e9c83
  15. Removing intermediate container eda8f77e9c83
  16. ---> 08f348a33ff6
  17. Step 12/14 : WORKDIR /usr/local/redis-5.0.5/utils
  18. ---> Running in c7cd15701c85
  19. Removing intermediate container c7cd15701c85
  20. ---> 1dcde04ee437
  21. Step 13/14 : ENTRYPOINT ["./"]
  22. ---> Running in 152277e9979e
  23. Removing intermediate container 152277e9979e
  24. ---> 1c9a7b9c6bae
  25. Step 14/14 : CMD ["install_server.sh"]
  26. ---> Running in 065dc4a5ba65
  27. Removing intermediate container 065dc4a5ba65
  28. ---> 8b1990aa9224
  29. Successfully built 8b1990aa9224
  30. Successfully tagged starsray/redis:5.0.5

构建完成,查看docker镜像,可以看到除了自定义的starsray/redis:5.0.5镜像之外,此外Dockerfile中用到的CentOS7,镜像也被拉取下来,可以看出Docker中镜像缓存、分层的概念

  1. [root@starsray redis_dockertest]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. conly/redis 1.0 8b1990aa9224 3 minutes ago 587MB
  4. centos latest 0f3e07c0138f 2 months ago 220MB

使用docker run运行redis镜像

  1. [root@starsray redis_dockertest]# docker run -p 6379:6379 starsray/redis:5.0.5
  2. 1:C 12 Dec 2019 13:27:00.599 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
  3. 1:C 12 Dec 2019 13:27:00.599 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
  4. 1:C 12 Dec 2019 13:27:00.599 # Configuration loaded
  5. _._
  6. _.-``__ ''-._
  7. _.-`` `. `_. ''-._ Redis 5.0.5 (00000000/0) 64 bit
  8. .-`` .-```. ```\/ _.,_ ''-._
  9. ( ' , .-` | `, ) Running in standalone mode
  10. |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
  11. | `-._ `._ / _.-' | PID: 1
  12. `-._ `-._ `-./ _.-' _.-'
  13. |`-._`-._ `-.__.-' _.-'_.-'|
  14. | `-._`-._ _.-'_.-' | http://redis.io
  15. `-._ `-._`-.__.-'_.-' _.-'
  16. |`-._`-._ `-.__.-' _.-'_.-'|
  17. | `-._`-._ _.-'_.-' |
  18. `-._ `-._`-.__.-'_.-' _.-'
  19. `-._ `-.__.-' _.-'
  20. `-._ _.-'
  21. `-.__.-'
  22. 1:M 12 Dec 2019 13:27:00.601 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
  23. 1:M 12 Dec 2019 13:27:00.601 # Server initialized
  24. 1:M 12 Dec 2019 13:27:00.601 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
  25. 1:M 12 Dec 2019 13:27:00.601 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
  26. 1:M 12 Dec 2019 13:27:00.603 * Ready to accept connections

此时redis是阻塞状态运行,也可以重新编写Dockerfile来构建镜像让redis容器后台运行

  1. ARG desc
  2. FROM centos
  3. LABEL maintainer=www.cnblogs.com/starsray/
  4. RUN ["yum","-y","install","gcc","gcc-c++","net-tools","make"]
  5. WORKDIR /usr/local
  6. ADD redis-5.0.5.tar.gz .
  7. WORKDIR /usr/local/redis-5.0.5/src/
  8. RUN make && make install
  9. WORKDIR /usr/local/redis-5.0.5
  10. ADD redis.conf .
  11. RUN cd /usr/local/redis-5.0.5/utils && echo | /bin/bash install_server.sh
  12. ENTRYPOINT /usr/local/bin/redis-server /etc/redis/6379.conf && tail -f /var/log/redis_6379.log

运行redis,可以看到我们自定义的redis已经运行了。

  1. [root@starsray redis_dockertest]# docke run -p 6379:6379 -d starsray/redis:5.0.5 .
  2. d3b1191ae2408d5025ba55e3b893300ca9438246a10feb2d7e02fa0f29801740
  3. [root@conly redis_dockertest]# docker ps -s
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
  5. d3b1191ae240 starsray/redis:5.0.5 "/bin/sh -c '/usr/lo…" 8 seconds ago Up 7 seconds 0.0.0.0:6379->6379/tcp fervent_babbage 2.58kB (virtual 587MB)

总结

Docker消除了重复的、频繁的配置任务,并在整个开发生命周期中用于快速、简单和可移植的应用程序开发桌面和云。Docker全面的端到端平台包括UI、CLI、API和安全性,在整个应用程序交付生命周期中协同工作。

参考资料:
https://www.docker.com
https://docs.docker.com
https://docker-practice.github.io/zh-cn/container/run.html