Docker 日常要用的东西分三层:命令、Dockerfile 指令、构建流程。命令层决定你怎么查状态和进容器,指令层决定镜像怎么被描述出来,构建层决定同样的应用换人做能不能得到同一个结果。这篇按这三层记一遍,环境是 CentOS 7、Docker Engine 20.10.12。
先看引擎自己说了什么
docker version 的输出分成 Client 和 Server 两段,Client 是命令行工具,Server(Engine)才是真正干活的一端,下面还挂着 containerd、runc、docker-init 三个组件的版本——runc 是实际运行容器的轻量工具,containerd 负责镜像和容器生命周期。API version 1.41、Go 1.16.12 这些值决定了客户端和服务端能不能混版本用。
[root@localhost ~]# docker version
Client: Docker Engine – Community #docker客户端
Version: 20.10.12 #客户端版本号
API version: 1.41 #API版本号
Go version: go1.16.12 #使用的Go版本
Git commit: e91ed57 #此次版本提交的commit ID
Built: Mon Dec 13 11:45:41 2021
OS/Arch: linux/amd64 #系统架构
Context: default
Experimental: true
Server: Docker Engine – Community #Server引擎端
Engine:
Version: 20.10.12
API version: 1.41 (minimum version 1.12)
Go version: go1.16.12
Git commit: 459d0df
Built: Mon Dec 13 11:44:05 2021
OS/Arch: linux/amd64
Experimental: false
containerd: #containder信息
Version: 1.4.12 #containder版本
GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc: #docker引擎,核心组件
Version: 1.0.2 #版本号
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
[root@localhost ~]# docker info
Client: #客户端信息
Context: default
Debug Mode: false #Debug模式管理
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.7.1-docker)
scan: Docker Scan (Docker Inc., v0.12.0)
Server: #服务端信息
Containers: 0 #当前宿主机上有多少个容器
Running: 0 #当前宿主机上运行的容器数量
Paused: 0 #当前宿主机上暂停的容器数量
Stopped: 0 #当前宿主机上停止的容器数量
Images: 0 #当前宿主机上有多少个镜像
Server Version: 20.10.12
Storage Driver: overlay2 #使用的存储驱动,overlay2
Backing Filesystem: xfs #使用overlay2存储系统格式必须为xfs
Supports d_type: true #使用overlay2必须开启d_type
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file #日志存储类型; json-file会存储在本地,存储在Docker Root Dir指定的路径下
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
#以下支持日志存储的方式
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive #Swarm未启动
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc #RunC 是一个轻量级的工具,它是用来运行容器的
Init Binary: docker-init
containerd version: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc version: v1.0.2-0-g52b36a2
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 5.4.179-1.el7.elrepo.x86_64 #系统内核版本
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.749GiB
Name: localhost.localdomain
ID: 7FLQ:ERSG:BZNW:ERAA:UVWS:QDBW:ADGD:BZ7E:ADTV:WFWU:XKCX:TNPS
Docker Root Dir: /data/docker #docker数据存储路径,可更改,建议SSD存储单独挂载
Debug Mode: false
Registry: https://index.docker.io/v1/ #默认使用的镜像仓库
Labels:
Experimental: false
Insecure Registries: #针对于镜像仓库不是https方式访问的,可加入到下面中
127.0.0.0/8
Registry Mirrors:
https://a7ye1cuu.mirror.aliyuncs.com/
Live Restore Enabled: true #重启docker进程不会重启正在运行的容器
几个字段值得单独记:Storage Driver: overlay2 配合 Backing Filesystem: xfs,而且必须开启 d_type(Supports d_type: true),否则 overlay2 会出问题;Logging Driver: json-file 表示日志落在本地,路径就是 Docker Root Dir;Insecure Registries 用于非 HTTPS 的私有仓库;Live Restore Enabled: true 让重启 docker 进程不会重启正在运行的容器。检查 d_type 用:
[root@localhost ~]# xfs_info /

镜像与容器的常用命令
搜索、拉取、改标签。不写 tag 默认是 latest;镜像地址、名称、tag 三者完全一致时本地已存在就不会重复拉取;pull 后面不带仓库地址则默认从 Docker Hub 取。
[root@localhost ~]# docker search nginx

[root@localhost ~]# docker pull nginx

[root@localhost ~]# docker tag nginx:latest docker.devops.com/nginx:1.20.1
运行与进入:-it 前台起一个 shell,加 -d 后台运行并只输出容器 ID;之后用 exec 进去,退出后容器仍在跑。
前台启动:
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 6 weeks ago 141MB
[root@localhost ~]# docker run -it nginx:latest /bin/bash
root@f87d99293f63:/#
后台启动:-d参数
[root@localhost ~]# docker container run -it -d nginx:latest /bin/bash
eee23811d4ec6b5a5e8903ae98eb8487c84157da6cbeb6ad14551b45a7dd3b64
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eee23811d4ec nginx:latest "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 80/tcp dazzling_wiles
[root@localhost ~]# docker container exec -it eee23811d4ec /bin/bash
root@eee23811d4ec:/# exit
exit
[root@localhost ~]# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eee23811d4ec nginx:latest "/docker-entrypoint.…" 30 seconds ago Up 30 seconds 80/tcp dazzling_wiles
指定容器名称喝容器暴露端口
[root@localhost ~]# docker container run -it -d -p 8080:80 --name nginx-web nginx /bin/bash
浏览器访问宿主机IP+8080端口
其余几个高频动作:
docker ps # 正在运行的容器
docker ps -a # 全部容器
docker ps -q # 运行中容器的 ID
docker ps -qa # 全部容器的 ID
docker logs -f <CONTAINER ID或NAMES>
docker exec -it <CONTAINER ID或NAMES>
语法:
#本机文件拷贝至容器中
docker cp 本机文件 CONTAINER ID:目标路径
#容器中文件拷贝至本机
docker cp CONTAINER ID:文件名称 本机路径
指定名称和端口映射用 -p 8080:80 --name nginx-web,浏览器访问宿主机 IP 加 8080 就能看到页面。
Dockerfile 指令
FROM 是必需的,且必须是第一条指令;唯一的例外是 ARG,它可以写在 FROM 前面用来参数化基础镜像,构建时用 --build-arg 参数名=值 覆盖默认值。一个 Dockerfile 可以出现多个 FROM,用于多阶段构建。
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]
ARG CODE_VERSION=latest
FROM nginx:${CODE_VERSION}
…
FROM mysql:${CODE_VERSION}
…
MAINTAINER 已弃用,作者信息改用 LABEL:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
RUN 执行 shell 命令,exec 格式会被解析成 JSON,所以不能用单引号:
RUN <command> (shell格式)
RUN ["executable", "parameter1", "parameter2"] (exec格式)
EXPOSE 只是声明容器监听的端口和协议(默认 tcp),它不对外暴露端口,外部要访问必须在 docker run 时用 -p 映射到宿主机:
EXPOSE <port> [<port>/<protocol>...]
CMD 与 ENTRYPOINT 的关系最容易搞错,对应到 K8s 的 deployment 里,CMD 是 ARGS、ENTRYPOINT 是 COMMAND。两者至少要有一个;同时存在时 ENTRYPOINT 是启动命令,CMD 变成它的参数:
CMD ["executable", "parameter1", "parameter2"](exec格式,首选)
CMD ["parameter1","parameter2"](给ENTRYPOINT提供默认参数)
CMD command parameter1 parameter2(shell格式)
ENTRYPOINT ["executable", "parameter1", "parameter2"] (执行格式,首选)
ENTRYPOINT command parameter1 parameter2 (shell格式)
数据、环境、文件与工作目录:
VOLUME ["/data"]
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径>",... "<目标路径>"]
ADD <源路径>... <目标路径>
ADD ["<源路径>",... "<目标路径>"](路径包含空格的必须使用这种格式)
WORKDIR /path/to/workdir
USER <user>[:<group>] or
USER <UID>[:<GID>]
COPY 只复制不解压,路径不存在会自动建目录;ADD 遇到 tar、tar.gz、gzip、bzip2、xz 格式的包会在容器里自动解压,路径含空格必须用 JSON 数组写法。WORKDIR 类似 cd,相对路径是相对上一个工作目录。
构建一次并验证
建目录、放一个 nginx-1.20.2.tar.gz 用来测 ADD 解压,写 Dockerfile:
[root@containers ~]# mkdir dockerbuild
[root@containers ~]# cd dockerbuild/
[root@containers dockerbuild]# ls
nginx-1.20.2.tar.gz #此文件用来测试ADD指令解压
[root@containers dockerbuild]# vim Dockerfile
ARG CODE_VERSION=latest
FROM nginx:${CODE_VERSION}
LABEL user="example"
RUN mkdir -p /opt/data
EXPOSE 80
CMD ls /opt
ADD ./nginx-1.20.2.tar.gz /opt/data/
USER nginx
不建议同一类操作写成多条指令,镜像层数和体积都会涨。执行构建:
[root@containers dockerbuild]# docker build -t nginx:test .
Sending build context to Docker daemon 1.065MB
Step 1/8 : ARG CODE_VERSION=latest
Step 2/8 : FROM nginx:${CODE_VERSION}
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
---> 605c77e624dd
Step 3/8 : LABEL user="example"
---> Running in ce207d3cd193
Removing intermediate container ce207d3cd193
---> 460d8c9fe6b4
Step 4/8 : RUN mkdir -p /opt/data
---> Running in abb022bf6313
Removing intermediate container abb022bf6313
---> 4351cc5281de
Step 5/8 : EXPOSE 80
---> Running in f3ab52ae69f4
Removing intermediate container f3ab52ae69f4
---> 467c37a81979
Step 6/8 : CMD ls /opt
---> Running in 52268dae069b
Removing intermediate container 52268dae069b
---> 6df238b44d40
Step 7/8 : ADD ./nginx-1.20.2.tar.gz /opt/data/
---> d22f60131ab7
Step 8/8 : USER nginx
---> Running in b5cb554091ac
Removing intermediate container b5cb554091ac
---> 8cfb7c300a8c
Successfully built 8cfb7c300a8c
Successfully tagged nginx:test
跑起来看 ADD 是否真的解压了,--rm 让容器退出后自动删除,测试阶段建议都带上:
[root@containers dockerbuild]# docker container run -it --rm nginx:test /bin/bash
nginx@391aa2f4aa2b:/$ ls /opt/data/
nginx-1.20.2
nginx@391aa2f4aa2b:/$ ls /opt/data/nginx-1.20.2/
CHANGES CHANGES.ru LICENSE README auto conf configure contrib html man src
容易出问题的地方
一、xfs 没开 d_type 就上 overlay2,容器启动报 mount 相关错误,先 xfs_info / 确认再重装。二、把 EXPOSE 当成端口映射,服务起来了外部照样连不上。三、CMD 覆盖 ENTRYPOINT:在 K8s 里改 args 和 command 的效果跟 Dockerfile 里这两条是一一对应的,写清楚谁是指令谁是参数。四、json-file 日志默认不设上限,长期跑能把 Docker Root Dir 所在分区写满,记得配 logging opt 的 max-size。
















暂无评论内容