Docker 从使用到镜像构建

本文记录于2020/4/18,修改于 2022/3/13

Docker官方文档
安装
使用手册

Docker安装

以Centos为例安装Docker(Centos版本需要为7.x)

  1. 如果之前有安装过老版本的docker,先卸载老版本执行
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  1. 安装yun-utils,(如果已经安装yum-utils可省略此步骤)
sudo yum install -y yum-utils
  1. 设置Docker仓库
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
  1. 正式安装Docker
 sudo yum install docker-ce docker-ce-cli containerd.io

5.启动Docker

sudo systmectl start docker

DockerHub国内镜像配置

Docker拉取镜像默认源在国外,由于人尽皆知的原因访问较慢或无法访问。所以需要将拉取镜像的位置换为国内。

  1. 登陆阿里云服务平台,可使用支付宝登陆。

  2. 在产品服务中找到镜像服务

  3. 开通镜像服务并在镜像中心下找到镜像加速器

  4. 再找到/etc/docker/daemon.json(如果没有就创建一个)在其中将绿色部分文本粘贴进入。

  5. 重启Dockersudo systemctl restart docker

  6. 享受高速(⊙﹏⊙)

Docker基础命令

docker pull ${image-id}

拉取容器镜像

docker images

查看当前容器列表

docker ps

查看当前正在运行的实例

docker run ${image-id}

启动容器,常用参数

-i 即使没有连接到容器实例也让容器实例的标准输入处于打开状态

-t 开启一个虚拟终端

-d在后台运行该实例

-p端口映射

例:-p 8080:8080

-v绑定卷,类似一个磁盘映射

例:-p /home/wxm:/home/in-wxm

docker start 实例id

启动一个已经创建的实例

docker stop 实例id

停止正在运行的实例

详见https://docs.docker.com/reference/

Docker hello-world

万物基于hello world docker官方为我们提供了一个hello-world供我们测试docker是否安装成功。现在运行它。

sudo docker run hello-world

出现这个画面表示安装成功(值得注意的是docker拉取容器镜像的命令是docker pull,但当我们运行某个容器时如果docker在本地没有找到就会去docker hub上拉取并运行。)
输入sudo docker images查看刚刚拉去到的hello-word

Docker without sudo

现在已经成功安装并运行了Docker,但有一个小问题我每次使用docker命令的时候都要加sudo这很麻烦对我来说也没必要。

使用gpasswd -a 用户名 docker将你的用户加入到docker用户组

随后执行 newgrp docker 登录到该群组即可免sudo 执行 docker 命令

运行一个Tomcat容器

前面已经看到要运行某个容器可执行docker run 容器名/容器id,但为了更清晰运行过程我决定先拉取tomcat容器镜像再执行它。
执行docker pull tomcat拉取容器镜像,默认拉取最新版镜像即标签为latest(是DockerHub上的最新镜像而不知最新版tomcat)
如果想使用特定版本的tomcat请使用docker pull tomcat:标签名

使用docker images可以查看当前你的docker中有那些容器镜像

现在使用docker run tomcat运行刚刚拉取的容器。

啊,熟悉的tomcat启动界面。
但是,现在使用浏览器访问刚刚启动的tomcat是会失败的,因为我们启动时缺少一个参数 -p-p可以指定容器内端口与宿主机端口映射关系其格式为-p 宿主机端口号:容器端口号。现在加上端口号试一试docker run -p 8080:8080 tomcat。我使用的是虚拟机虚拟机ip为192.168.64.137。访问192.168.64.137:8080

啊熟悉的404(⊙﹏⊙)

但是我想放一个自己写的页面怎么办呢,这时就需要另一个重要的参数-v其作用是将宿主机的文件目录与容器内文件目录绑定。类似与共享目录。首先进入容器内看看容器内tomcat放在了哪里,执行docker run -it tomcat /bin/bash进入容器。后面紧随其后的/bin/bash表示替换容器启动时执行的命令为/bin/bash。(详见docker run

可以看到容器内tomcat路径为/usr/local/tomcat。

退出容器执行docker run -d -p 8080:8080 -v /home/alming/wxm:/usr/local/tomcat/webapps tomcat

容器映射的目录映射关系为:
宿主机/home/wxm->容器/usr/local/tocmcat/webapps
wxm下还有一个wxm文件夹,里面有一张小哎咪.jpg

输入192.168.64.137:8080/wxm/fxe.jpg看看可爱的小哎咪吧。

构建镜像

Dockerfile

书写格式

  1. 所有的指令是非大小写敏感的,但习惯写为大写有助于与你的参数做区分

  2. 所有的指令按照Dockerfile文件顺序执行

  3. 一个Dockerfile必须以FROM指令开始(但可以在解析器指令parse derictive、注释comments或全局参数ARGs后)

  4. FROM前可以有一个或多个ARG,这些ARG中声明的变量将会在FROM行中使用

  5. 与shell,python等脚本语言类似Dockerfile中以#开头的行会被当做注释,如果它出现在Dockerfile文件的最上方并且是合法的解析器指令。它将会当作解析器处理,同一个解析器只会处理一次,第二次声明也将会当作注释处理。(合法的解析器包括syntax和escape)

.dockerignore

构建docker镜像时有上下文概念,例如以docker build -t 镜像名 .命令构建镜像是上下文即为Dockerfile所在目录(当然执行该命令的工作目录也在Dockerfile所在目录)。
docker 构建镜像时会将上下文中的所有文件拷贝到docker的构建进程中,就像.gitignore一样声明在.dockerignore中的文件或文件夹在拷贝时会被忽略。

构建指令

FROM

 所有Dockerfile最先执行的指令(当然最先是在排除前文提到的解析器指令和参数等的前提下,因为这几个指令都是可选的)
 该指令指定一个基础镜像(也可以理解为父镜像)。为之后一系列操作提供基础运行环境。
 该指令可以使用已定义过的ARG,使用方式为${参数名},与shell很想对吗?没错之后还会有很多相似之处。

RUN

 RUN指令用于在构建容器时执行你指定的任意命令。
 RUN指令有两种格式

shell格式
RUN /bin/bash -c 'source \$HOME/.bashrc; \
echo $HOME'

改格式下你可以使用 \ 来在另一行编写你未完成的单个命令,并且可以使用${}操作符,json格式则不可以。

exec格式
RUN ["/bin/bash", "-c", "echo hello"]

exec格式会被转换为一个json数组,所以你因该使用双引号"来包裹你额单词而不是单引号',另外在该格式中应避免反斜杠 \尤其是在windows中\标识了windows的文件目录。

CMD

一个Dockerfile中只能有一个CMD命令,如果写了多个那么只有最后一个生效。它的目的是为容器提供一个默认执行应用。
该命令会被命令行参数所替换例如如果启动时执行命令为docker run -it 容器名 /bin/sh则CMD内容将被替换为 /bin/sh
CMD命令一共有三种格式

exec格式
CMD ["executable","param1","param2"]

该格式是最推荐使用的格式

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

当它作为ENTRYPOINT的参数的时候ENTRYPOINT和CMD都必须是json数组的格式。

shell格式
CMD command param1 param2

使用改格式默认会在/bin/sh -c中执行,如果不想使用/bin/sh -c执行命令请使用exec格式

LABLE

LABLE为构建的镜像添加一些key-value格式的元数据,和RUN一样可以使用反斜杠 \ 在下一行完成单条过长的元数据。
例:

FROM ubuntu:18.04
WORKDIR /usr/local
LABEL wxm="wxm530" \
      alming="alming530"

构建完成后 docker inspect 镜像名

"WorkingDir": "/usr/local",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
     "alming": "alming530",
      "wxm": "wxm530"
}

LABLE包包括前镜像和父镜像的LABLE,如果重复了以最新的为准.

EXPOSE

EXPOSE指定Docker容器运行时向外暴露的端口,可以指定TCP或UDP协议端口,默认采用TCP协议。指令格式EXPOSE 80/tcp EXPOSE 80/udp

ENV

ENV即环境变量,它有两种格式

ENV <key> <value>

该格式设置一个单个的环境变量,第一个完整的字符串是key key+空格后的所有值都是value,
它会被其他环境变量所解析,如果没有转义不应该在改格式中写引号"。(这里不理解,只是翻译了一下官方文档)

ENV <key>=<value> ...

改格式允许在一行定义多个环境变量,以空格分隔。如果环境变量本身需要空格将有空格的变量使用引号"括起来或使用\来转义空格。

注意ENV添加的环境变量对于容器来说是持久的。如果需要临时的变量则使用RUN <key>=<value> <command>.

ADD

  • ADD指令用于将主机或者某个url上的文件资源拷贝到将要构建的镜像当中。
  • 源文件地址可以使用Go’s filepath.Match rules.解析规则的通配符。
  • 目的地址是目标容器的绝对地址或者是WORKDIR的相对地址(关于WORKDIR参照WORKDIR文档)。
  • 如果源地址中包含特殊字符则需要按照Go语言的转义规则将它们转义。
  • 添加到容器中的文件默认由GID和UID为0的用户创建,如果想改变使用 --chown参数,这一部分详细参照官方文档。
  • 如果添加的文件是归档文件还会被默认加压。
    该指令有两种格式。

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

COPY

COPY指令与ADD基本一致,但它不会解压添加到容器中的归档文件

ENTRYPOINT

ENTRYPOINT和CMD类似都用于指定容器启动时容器内执行的命令或执行可执行文件,CMD中的指令最终都会以参数的形式传递给ENTRYPOINT(前提是ENTRYPOINT是exec格式)。
ENTRYPOINT有两种格式

shell格式
ENTRYPOINT command param1 param2

改格式不会接收CMD作为参数,但有一个缺点就是使用docker stop命令无法正常关闭容器内正在运行的应用,(个人理解为对于容器中运行的应用来说容器停止时它们都是强制退出的,也就是说如果程序中有结束程序的钩子函数可能无法被正常执行)

所以使用改格式时需要在命令前添加exec例如 ENTRYPOINT exec top -b

exec格式
ENTRYPOINT ["executable", "param1", "param2"]

该格式下每个参数都是一个字符不能连写例如有两个参数-c-t则不能写成["command","-c -t" ]因该写成["command","-c","-t"]并且所有参数都要使用双引号"",所有写在CMD中的命令将会自动添加在数组的尾部作为参数,同时CMD内容可被启动时命令行内容替换,所以可以使用命令行替换CMD内容继而追加道ENTRYPOINT中。
例:

//Dockerfile
FROM ubuntu:18.04
WORKDIR /usr/local
ENTRYPOINT ["echo"]
CMD wxm

执行docker build -t wxm .构建镜像
先不加参数运行docker run -it wxm运行结果

[alming@localhost docker]$ docker run -it wxm
/bin/sh -c wxm
[alming@localhost docker]$ 

可以看到wxm被打印说明CMD中内容确实被追加到ENTRYPOINT中了,同时看到还打印了/bin/sh -c侧面说明了CMD中命令默认由/bin/sh -c 执行,这一点官方文档中也有提及

接下来运行容器时指定自定义参数docker run -it wxm alming

[alming@localhost docker]$ docker run -it wxm alming
alming
[alming@localhost docker]$ 

可以看到参数被正确替换并传递。
另外如果要为容器中的可执行文件编写可执行脚本以在ENTRYPOINT中执行需要注意使用exec加gosu启动可执行文件这样可以保证启动的进程的PID为1从而可以接收到docker stop传过来的停止信号从而优雅的结束该进程。目的也是为了保证程序退出前的准备工作正常完成。
下面是官方示例:

#!/usr/bin/env bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi
exec "$@"

VOLUME

在容器中创建你声明的挂载点,即创建一个目录。并且会默认关联到宿主机/var/lib/docker/volume下的一个文件夹下的_data文件夹。该文件夹由docker生成名称是一个hash码

[root@192 volumes]# pwd
/var/lib/docker/volumes
[root@192 volumes]# ls
0a31112d023a994c3dc4ed945a75fa4c55ce9d94ff80c200d2574bb0270df3d3
0f61fd7fdf69653ab4d5dc6c576b5e809553c83914c8c295bfc3511c56ac50eb
10b2add0f578d26f79fc9ac69df126ab93793314d98ebe37c93e97aa545486bf
17c764a4a52320ce2a85ec7ccab81c6b3845e53225bfc955d3308dc09ead7618

和手使用-v指定的文件夹一样和容器内的文件夹内容同步。
其值可以是纯字符转也可以是json数组
USER

USER指令用来设置用户名(或UID)组名(或GID)。设置完成后,接下来的RUN,ENTRYPOINT,CMD中所执行的命令都有该用户完成。
格式

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

WORKDIR

WORKDIR指令为RUN,CMD,ENTRYPOINT,ADD,COPY指定工作空间
格式

WORKDIR /path/to/workdir

它可以定义多次并且每次都会以上一个WORKDIR指令为相对目录,官方示例为

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最终打印结果为/a/b/c
WORKDIR 还可以解析之前定义过的ENV中的内容,但注意只能解析Dockerfile中定义的ENV系统环境变量是取不到的,官方示例:

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

最总打印结果为/path/$DIRNAME

ARG

用户在使用docker build指令时可通过 --build-arg <varname>=<value>将参数传递给Dockerfile中声明的ARG中以供之后通过$参数名使用。
同时它可以有默认值ARG user1=someuser,并且其他指令只能调用在它本身之前声明过的ARG。
注意如果ENV定义的变量名和ARG重复了ENV的值将会覆盖ARG的值
Docker中有一些预定义的ARG这些ARG不需要你声明也可以使用包括

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy
    这些预定义变量将不会被docker history输出

ONBUILD

ONBUILD指定当子镜像被构建时需要执行的指令,其中声明的指令将会被插入到子镜像的FROM指令之后执行。
注意,ONBUILD不可嵌套使用并且不会触发FROM指令。

STOPSIGNAL

STOPSIGNAL指定使用docker stop停止容器时容器内应用程序的终止行为,格式为

STOPSIGNAL signal

以下内容出自stackoverflow非官方文档,文档未对此指令做细致解释。原文

可选取值为SIGKILL ,SIGTERM ,SIGINT
其中SIGTERMSIGINT可以正常关闭正在运行的应用,SIGKILL则不能
SIGKILL相当于kill -9 <PID>
SIGTERM 相当于kill <PID>
SIGINT 相当于Ctrl + c

HEALTHCHECK

HEALTHCHECK目的是在容器中运行特定的指令以检查容器中的应用设否正常工作,他也有两种格式:

HEALTHCHECK [OPTIONS] CMD command

HEALTHCHECK NONE
继承自父镜像,默认不进行任何检测

SHELL

SHELL指令用于切换RUN,CMD,ENTRYPOINT的默认shell,默认情况下linux使用的是["/bin/sh", "-c"]Windows使用的是["cmd", "/S", "/C"]通常用于当默认shell执行不了某个命令时使用SHELL指令切换shell执行完成后再通过SHELL指令切回原来的shell.
大幻梦森罗万象狂气断罪眼 2333

posted @ 2022-03-13 21:15  小艾咪  阅读(204)  评论(0)    收藏  举报