跳转至

1. 基础介绍

容器技术是一种虚拟化技术,它可以将应用程序及其依赖项打包到一个独立的运行环境中,以便于在不同的计算机上运行。容器技术可以提供更高的资源利用率、更快的应用程序启动时间和更好的可移植性。

容器技术主要由以下组成部分组成:

  • 容器镜像:容器镜像是一个只读的文件系统,包含了应用程序及其依赖项和运行时环境等。
  • 容器运行时:容器运行时是一个负责启动和管理容器的软件,可以提供容器隔离、容器网络和容器存储等功能。
  • 容器编排工具:容器编排工具是一个负责管理多个容器的软件,可以提供容器自动化部署、容器扩展和容器负载均衡等功能。

2. 安装容器

目前系统已支持docker engine,可通过如下命令安装

# dnf install docker
或
# dnf install moby

docker 是 moby 提供的能力,因此安装 moby 包即可

安装完成后通过以下命令启动docker服务:

# systemctl start docker

另外,也通过 EPOL 源的形式提供了 podman,EPOL 源默认使能,用户可按需安装,命令如下:

# dnf install podman

3. 配置容器

通常情况下,通过daemon.json文件来配置docker守护进程。Docker守护进程是Docker的核心组件,负责管理Docker容器、镜像、网络等资源,以及提供Docker API接口供其他程序调用。在Docker守护进程启动时,会读取daemon.json文件中的配置信息,并根据配置信息来初始化Docker守护进程。通过修改daemon.json文件中的配置信息,可以改变Docker守护进程的行为,例如配置镜像加速器、设置日志级别、配置存储驱动等。

常用参数如下:

  • registry-mirrors

作用:配置Docker镜像加速器地址,加速镜像下载速度。

示例:

"registry-mirrors": ["https://mirror.ccs.tencentyun.com"]
  • log-driver

作用:配置Docker容器的日志驱动,用于将容器的日志输出到文件或者标准输出中。

示例:

"log-driver": "json-file"
  • log-opts

作用:配置Docker容器的日志选项,例如日志文件的最大大小、最多保留的日志文件数等。

示例:

"log-opts": {
  "max-size": "10m",
  "max-file": "3"
}
  • storage-driver

作用:配置Docker容器的存储驱动,用于管理容器的文件系统。

示例:

"storage-driver": "overlay2"
  • bip

作用:配置Docker网桥的IP地址,用于容器之间的通信。

示例:

"bip": "172.16.0.1/24"
  • fixed-cidr

作用:配置Docker网桥的子网地址,用于容器之间的通信。

示例:

"fixed-cidr": "172.16.0.0/24"
  • mtu

作用:配置Docker网桥的MTU值,用于容器之间的通信。

示例:

"mtu": 1500
  • live-restore

作用:配置Docker是否启用容器的实时恢复功能,用于在Docker守护进程崩溃或重启时自动恢复容器。

示例:

"live-restore": true
  • default-ulimits

作用:配置Docker容器的默认资源限制,例如CPU、内存、文件描述符等。

示例:

"default-ulimits": {
  "nofile": {
    "Name": "nofile",
    "Hard": 65536,
    "Soft": 65536
  }
}

完整示例

# cat /etc/docker/daemon.json

{
  "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}

配置文件编辑完成后,可以使用以下命令重启Docker服务使配置生效:

# systemctl restart docker

4. 容器管理

4.1 启停容器

4.1.1 直接运行一个容器

以拉起一个busybox镜像为例,执行如下命令,从docker官方的镜像库中下载最新的busybox镜像

# docker pull busybox

用户可以直接通过 docker run 命令运行一个容器,如下:

# docker run busybox /bin/echo "Hello world"
Hello world

其中 busybox 为镜像名,/bin/echo "Hello world" 即容器执行的命令

4.1.2 创建交互式容器

此外,用户可以使用 -it 选项来创建一个交互式的容器,在交互界面执行命令,如下

# docker run -it busybox /bin/sh

执行后,即可进入交互界面

/ # 
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # echo "Hello world"
Hello world

4.1.3 后台运行容器

用户可以通过 -d 选项在后台运行容器,命令如下:

# docker run -d --name=my_container busybox /bin/sh -c "while true;do echo Hello world;sleep 1;done"

4.1.4 结束容器

停止容器

# docker stop 3586b3a12366

或者是kill掉容器

# docker kill 3586b3a12366

删除容器

# docker rm 3586b3a12366

4.2 容器信息查询

Docker提供了多种查询相关的命令,可以用于查询Docker容器、镜像、网络等信息。以下是一些常用的Docker查询命令及其作用:

  • docker ps

用于列出当前正在运行的Docker容器, 查看容器的名称、ID、状态、端口映射等信息。

# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
cb3435ac0f78   busybox   "/bin/sh -c 'while t…"   7 seconds ago   Up 5 seconds             my_container
  • docker logs

用于查看Docker容器的日志信息。

# # docker logs cb3435ac0f78
Hello world
Hello world
...
Hello world
  • docker network ls

查看网络的名称、ID、驱动程序等信息。

# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4500f433c4e2   bridge    bridge    local
30217a81dce2   host      host      local
020a952b0758   none      null      local
  • docker volume ls

查看卷的名称、驱动程序、挂载点等信息。

# docker volume ls
  • docker stats

查看容器的CPU、内存、网络、磁盘等资源使用情况。

# docker stats
CONTAINER ID   NAME            CPU %     MEM USAGE / LIMIT   MEM %     NET I/O       BLOCK I/O   PIDS
cb3435ac0f78   my_container   0.00%     496KiB / 3.552GiB   0.01%     1.97kB / 0B   0B / 0B     1

4.3 容器修改

docker提供了多种命令,用于修改Docker容器:

  • 修改容器配置

使用 docker update 命令可以修改容器的配置,例如修改容器的CPU和内存限制、添加或删除容器的网络配置等。例如,以下命令可以将容器的CPU限制设置为1个核心:

# docker update --cpus 1 <container_name>
  • 修改容器文件系统

使用 docker cp 命令可以将文件复制到容器中,从而修改容器的文件系统。例如,以下命令可以将本地的文件复制到容器的/tmp目录中:

# docker cp <local_file> <container_name>:/tmp/
  • 修改镜像标签

使用 docker tag 命令可以为镜像添加或修改标签。例如,以下命令可以将镜像的标签修改为latest:

# docker tag <image_name>:<old_tag> <image_name>:latest
  • 修改镜像元数据

使用 docker commit 命令可以修改镜像的元数据,例如修改镜像的作者、描述等。例如,以下命令可以为镜像添加作者信息:

# docker commit --author "John Doe" <container_name> <new_image_name>
  • 修改Docker配置

使用 docker config 命令可以修改Docker的配置,例如修改Docker的日志级别、修改Docker的存储驱动等。例如,以下命令可以修改Docker的日志级别为debug:

# docker config set log-level debug

5. rootless容器

在docker中可以使用rootless模式运行docker deamon和容器,在该模式下不需要root权限。docker在20.10版本之后正式支持该模式。rootless模式利用user namespace将容器的root用户与docker守护进程用户映射到宿主机的非特权用户范围内,这样就提升了容器的安全隔离性。

5.1 环境准备

假设容器环境已经配置完全,为运行rootless容器,还需安装以下组件

# dnf install -y shadow-utils fuse-overlayfs iptables
获取并安装docker-rootless-extras

# wget https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-20.10.21.tgz
# tar -xf docker-rootless-extras-20.10.21.tgz
# cd docker-rootless-extras && cp ./* /usr/bin/.
创建非root用户

# useradd rootlesstest
# loginctl enable-linger rootlesstest
确保用户rootlesstest有至少65536个子UIDs/GIDs
# cat /etc/subuid
rootlesstest:231072:65536
# cat /etc/subgid
rootlesstest:231072:65536

5.2 运行rootless dockerd守护进程和rootless容器

启动容器deamon

# dockerd-rootless-setuptool.sh install
# ps -ef | grep dockerd
rootles+    1737    1630  0 20:16 ?        00:00:00 rootlesskit --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /usr/bin/dockerd-rootless.sh
rootles+    1745    1737  0 20:16 ?        00:00:00 /proc/self/exe --net=vpnkit --mtu=1500 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /usr/bin/dockerd-rootless.sh
rootles+    1777    1745  0 20:16 ?        00:00:00 dockerd
rootles+    1799    1777  0 20:16 ?        00:00:00 containerd --config /run/user/1002/docker/containerd/containerd.toml --log-level info
可见deamon已经以rootlesstest用户运行。 运行rootless容器

# docker pull busybox
# docker run -tid busybox sh
b371390eaeaf45677ddb6de17c54df9f78fba0d513f715fb50f0c7edb80cc89e
# docker inspect -f "{{.State.Pid}}" b371390ea
2376
# ps -ef | grep 2376
rootles+    2376    2353  0 21:06 pts/0    00:00:00 sh
# docker exec b371390ea sh -c "whoami"
root
可见容器进程在宿主机上面以rootlesstest用户执行,容器里面依然显示为root用户

6. 镜像管理

在Docker中,镜像是一种轻量级、可移植的打包格式,用于存储和传输Docker容器的文件系统和应用程序。镜像包含了一个完整的文件系统,包括操作系统、应用程序、库文件、配置文件等,以及一些元数据,例如镜像的名称、标签、版本号等。

6.1 镜像操作命令

Docker提供了多种命令,用于管理Docker镜像,包括增加、删除、修改和查询等操作。以下是一些常用的Docker镜像管理命令及其功能:

  • docker images

docker images命令用于列出本地的Docker镜像。使用docker images命令可以查看镜像的名称、标签、大小等信息。

# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
busybox      latest    7cfbbec8963d   7 weeks ago   4.86MB
  • docker pull

docker pull命令用于从Docker镜像仓库中拉取一个新的Docker镜像。使用docker pull命令可以指定镜像的名称、标签等参数。

  • docker push

docker push命令用于将一个本地的Docker镜像推送到Docker镜像仓库中。以下是其使用场景:

首先,需要在 Docker Hub 或其他 Docker 镜像仓库中创建一个新的仓库,用于存储 Docker 镜像。假设用户已创建了一个名为 mywork 的账户,并在账户中创建了一个 myimage 的仓库。

接下来,需要使用 docker tag 命令为本地的 Docker 镜像添加标签,以便将其推送到 Docker 镜像仓库中,格式如下:

# docker tag <image_name>:<tag> mywork/<image_name>:<tag>

其中,是本地的Docker镜像名称,<tag>是本地的Docker镜像标签。

例如,以下命令可以为本地的Docker镜像添加 myrepo 的标签:

# docker tag busybox mywork/myimage:1.0

然后,需要使用docker login命令登录到Docker镜像仓库中。例如,以下命令可以登录到Docker Hub中:

# docker login

最后,使用docker push命令将本地的Docker镜像推送到Docker镜像仓库中。例如,以下命令可以将本地的Docker镜像推送到 mywork 仓库中:

# docker push mywork/myimage:1.0
  • docker build

docker build命令用于从Dockerfile构建一个新的Docker镜像。使用docker build命令可以指定Dockerfile的路径、镜像的名称、标签等参数。

  • docker tag

docker tag命令用于为一个本地的Docker镜像添加或修改标签。使用docker tag命令可以指定镜像的名称、标签等参数。

  • docker rmi

docker rmi命令用于删除一个本地的Docker镜像。使用docker rmi命令可以删除镜像的文件系统、元数据等资源。

  • docker inspect

docker inspect命令用于查看Docker镜像的详细信息。使用docker inspect命令可以查看镜像的元数据、配置、状态等信息。

  • docker history

docker history命令用于查看Docker镜像的历史记录。使用docker history命令可以查看镜像的每一层的构建信息、大小等信息。

# docker history 7cfbbec8963d
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
7cfbbec8963d   7 weeks ago   /bin/sh -c #(nop)  CMD ["sh"]                   0B      
<missing>      7 weeks ago   /bin/sh -c #(nop) ADD file:27beb116a0bcfe544…   4.86MB 

6.2 Dockerfile配置

Docker镜像构建是指通过Dockerfile文件定义Docker镜像的构建过程和配置信息,然后使用docker build命令将Dockerfile文件构建成一个Docker镜像。Dockerfile文件是Docker镜像构建的核心文件,用于定义Docker镜像的构建过程和配置信息。Dockerfile文件是一个文本文件,其中包含了一系列的指令和参数,用于指定Docker镜像的构建过程和配置信息。

以下是Docker镜像构建的基本流程:

  • 编写Dockerfile文件

以下为一个示例:

# 使用腾讯云镜像源
FROM ccr.ccs.tencentyun.com/library/opencloudos:latest

# 安装必要的软件包
RUN yum update -y && \
    yum install -y nginx

# 复制配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80

# 启动Nginx服务
CMD ["nginx", "-g", "daemon off;"]
  • 构建Docker镜像

使用docker build命令构建Docker镜像。在构建Docker镜像时,Docker会根据Dockerfile文件中的指令和参数,自动执行一系列的操作,包括下载基础镜像、安装软件包、配置环境变量、添加文件等操作,最终生成一个完整的Docker镜像。

以下是一个示例docker build命令:

# docker build -t myimage:latest .

在这个命令中,-t参数指定了镜像的名称为myimage,:latest表示使用最新版本的标签,.表示Dockerfile文件所在的目录。

  • 上传Docker镜像

使用docker push命令将Docker镜像上传到Docker Hub或者其他的Docker镜像仓库中,以便其他人可以使用该镜像。

以下是一个示例docker push命令:

# docker push myimage:latest

在这个命令中,myimage:latest是要上传的镜像名称。

7. 维护

7.1 容器的备份和恢复

在Docker中,容器的备份和恢复是非常重要的操作,可以快速地恢复容器的状态,避免数据丢失和应用程序中断。

  • 备份容器

要备份一个Docker容器,可以使用docker export命令将容器导出为一个tar文件。以下是备份容器的命令:

# docker export <container_name> > <backup_file>.tar

其中,是要备份的容器名称,是备份文件的名称。

  • 恢复容器

要恢复一个Docker容器,可以使用docker import命令将备份文件导入为一个新的Docker镜像。然后使用docker run命令启动一个新的容器。以下是恢复容器的命令:

# docker import <backup_file>.tar <new_image_name>:<tag>
# docker run -it --name <new_container_name> <new_image_name>:<tag>

其中,是备份文件的名称,是新的Docker镜像名称,<tag>是新的Docker镜像标签,是新的容器名称。

需要注意的是,恢复容器时需要先将备份文件导入为一个新的Docker镜像,然后再使用docker run命令启动一个新的容器。

7.2 容器的监控和日志管理

在Docker中,容器的监控和日志管理是非常重要的操作,可以实时监控容器的状态,及时发现和解决问题。以下一些基础的维测命令:

  • 监控容器

要监控一个Docker容器,可以使用docker stats命令查看容器的实时资源使用情况。以下是监控容器的命令:

# docker stats <container_name>

其中,是要监控的容器名称。

  • 查看容器日志

要查看一个Docker容器的日志,可以使用docker logs命令查看容器的标准输出和标准错误输出。以下是查看容器日志的命令:

# docker logs <container_name>

其中,是要查看日志的容器名称。

  • 导出容器日志

要导出一个Docker容器的日志,可以使用docker cp命令将容器的日志文件复制到本地文件系统中。以下是导出容器日志的命令:

# docker cp <container_name>:/var/log/<log_file> <local_path>

其中,是要导出日志的容器名称,是要导出的日志文件名称,是本地文件系统中的路径。

7.3 容器安全和权限管理

在Docker中,容器的安全和权限管理是非常重要的操作,可以保护容器和应用程序的安全性。以下是一个使用场景示例:

  • 创建用户组

要创建一个Docker容器的用户组,可以使用groupadd命令创建一个新的用户组。以下是创建用户组的命令:

# groupadd <group_name>

其中,是要创建的用户组名称。

  • 创建用户

要创建一个Docker容器的用户,可以使用useradd命令创建一个新的用户,并将其添加到用户组中。以下是创建用户的命令:

# useradd -g <group_name> <user_name>

其中,是要添加到的用户组名称,是要创建的用户名称。

  • 启动容器时指定用户

要在启动一个Docker容器时指定用户,可以使用--user选项指定容器的用户和用户组。以下是启动容器时指定用户的命令:

# docker run -it --user <user_name>:<group_name> <image_name> --cap-add <capabilities> --cap-drop <capabilities>

其中,是要指定的用户名称,是要指定的用户组名称,是要启动的Docker镜像名称,<capabilities>指用来控制容器权限的能力集。

默认情况 Docker 容器内的进程将以 root 用户运行的,因此指定用户可以提高容器安全性。

关于能力集可以使用如下命令查询

# man capabilities

以下是一些常见的capabilities及其作用:

CAP_CHOWN
允许进程修改任意文件的所有者和组。

CAP_DAC_OVERRIDE
允许进程忽略文件的DAC(Discretionary Access Control)权限,即忽略文件的所有者和组权限。

CAP_DAC_READ_SEARCH
允许进程读取任意文件和目录,即使该文件或目录的权限不允许读取。

CAP_FOWNER
允许进程修改任意文件的所有者。

CAP_NET_RAW
允许进程使用原始套接字,即可以发送和接收任意类型的网络数据包。

CAP_NET_ADMIN
允许进程进行网络管理操作,例如配置网络接口、修改路由表等。

CAP_SYS_ADMIN
允许进程进行系统管理操作,例如挂载文件系统、修改系统时间等。

CAP_SYS_CHROOT
允许进程使用chroot系统调用,即将进程的根目录切换到指定的目录。

CAP_SYS_PTRACE
允许进程使用ptrace系统调用,即可以跟踪和修改其他进程的执行状态。

CAP_SYS_RESOURCE
允许进程修改系统资源限制,例如进程的CPU时间、内存使用量等。

7.4 容器配置健康检查

目前原生的容器已经支持健康检查的功能,需要用户通过编写 Dockerfile 文件进行设置,本文提供了将分布举例说明

1、编写Dockerfile文件

编写一个Dockerfile文件,用于构建一个包含健康检查脚本的镜像。以下是一个示例Dockerfile文件:

FROM ccr.ccs.tencentyun.com/library/opencloudos:latest

COPY healthcheck.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/healthcheck.sh

HEALTHCHECK --interval=5s --timeout=3s \
  CMD /usr/local/bin/healthcheck.sh || exit 1

在这个Dockerfile文件中,使用COPY指令将健康检查脚本healthcheck.sh复制到镜像中,并使用RUN指令给脚本添加可执行权限。

最后使用HEALTHCHECK指令定义了一个健康检查命令,该命令会每5秒执行一次,超时时间为3秒,如果脚本返回非0状态码,则认为容器不健康。

2、编写健康检查脚本

接下来,需要编写一个健康检查脚本,用于检查容器的健康状态。以下是一个示例健康检查脚本:

#!/bin/bash

if curl -s http://localhost:8080/healthcheck | grep -q "OK"; then
  exit 0
else
  exit 1
fi

在这个健康检查脚本中,使用curl命令访问容器中的一个健康检查接口,如果接口返回的内容包含OK,则认为容器健康,否则认为容器不健康。

3、构建镜像

使用以下命令构建镜像:

# docker build -t myimage:latest ./Dockerfile

在这个命令中,-t参数指定了镜像的名称为myimage,:latest表示使用最新版本的标签。

4、启动容器

使用以下命令启动容器:

# docker run -d --name mycontainer -p 8080:8080 myimage:latest

在这个命令中,-d参数表示以后台模式启动容器,--name参数指定容器的名称为mycontainer,-p参数指定容器的端口映射,myimage:latest表示使用myimage镜像的最新版本启动容器。

5、检查容器健康状态

使用以下命令检查容器的健康状态:

# docker inspect --format='{{json .State.Health}}' mycontainer

在这个命令中,--format参数指定了输出格式为JSON,mycontainer是容器的名称。

7.5 hook-spec

Docker容器的hook-spec是一种在容器生命周期中执行脚本的机制,可以在容器的不同阶段执行脚本,例如在容器启动前、启动后、停止前、停止后等,本文将分部举例说明:

1、创建hook-spec脚本 可以在容器中创建一个脚本文件,并将其保存在/etc/docker/目录下,如:

# cat /etc/docker/hook_name.sh
#!/bin/bash
echo "Container hello_tencent is starting..."

2、设置hook-spec脚本权限 要使hook-spec脚本可以执行,需要设置脚本的执行权限。

# chmod +x /etc/docker/hook_name.sh

3、配置hook-spec 使用 --add-host 选项将hook-spec脚本添加到容器中。以下是配置hook-spec的命令:

# docker run -it --add-host <hook_name>:<hook_path> <image_name>

其中,是hook-spec脚本名称,是hook-spec脚本路径,是要启动的Docker镜像名称。

需要注意的是,hook-spec脚本的执行顺序是按照文件名的字母顺序执行的。

同时,hook-spec脚本的执行结果会被记录在容器的日志中。如果hook-spec脚本执行失败,容器将无法启动或停止。因此,在编写hook-spec脚本时,需要谨慎考虑脚本的执行逻辑和错误处理机制。

8. 具体问题场景介绍

8.1 dnf install失败

具体报错如下,实际上是整个yum源失效,同时伴随着网络问题 img

结论:

glibc在2.34版本新增了clone3系统调用,如果clone3失败且返回ENOSYS则会重新走到旧的clone调用。然而docker 20.10.9之前的版本对于不识别的clone3,会返回EPERM而非glibc期望的ENOSYS,因此会导致clone失败

使用本系统上的 docker 不会存在问题,避免使用 docker 20.10.9 之前的旧版本环境部署本系统的容器镜像。