Docker&Containerd使用总结

1、docker安装
CentOS中安装

# 配置yum源为aliyun
mv CentOS-Base.repo CentOS-Base.repo.bak
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 使用aliyun的yum源安装docker
vim /etc/yum.repos.d/docker.repo
[docker]
name=Docker Repository
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/$releasever/$basearch/stable/
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
enabled=1
# 重新生成yum缓存
yum clean all
yum makecache
# docker compose部署
yum -y install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-compose-plugin-2.27.1-1.el7.x86_64.rpm
yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose

wget --no-check-certificate https://download.docker.com/linux/centos/docker-ce.repo -P /etc/yum.repos.d/
yum list docker-ce --showduplicates | sort -r #查看可以安装的版本
yum install -y docker-ce-18.03.1.ce-1.el7.centos #或使用yum install -y docker-ce命令安装,不推荐
systemctl start dockerd.service    # 启动docker服务
Ubuntu中安装
# 一键安装

apt-get install -y apt-transport-https ca-certificates curl software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" && apt-get update && sudo apt-get install -y docker-ce

# 查看可安装的版本(中间列为docker版本号)
apt-cache madison docker-ce
# 安装指定版本
apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
apt-get install docker-ce=5:20.10.9~3-0~ubuntu-bionic
# 启动docker服务
systemctl start dockerd.service

# 二进制方式安装docker需要安装iptables才能启动docker服务
apt install iptables

2、docker daemon.json文件常用配置

# data-root后边的值是Docker数据存储的目录。确保该目录存在且Docker进程有权限写入
# 主要关注data-root的值是大硬盘目录存放docker相关文件的目录
# insecure-registries后边的值是私有镜像仓库地址,多个私有镜像仓库地址配置格式为["仓库1","仓库2"]
# registry-mirrors后边的值是配置Docker registry的镜像拉取镜像
# exec-opts部分针对于部署k8s做的预配置,可以减少容器日志保存大小及配合kubelet使用systemd
# Docker版本或内核不支持overlay2.override_kernel_check选项导致docker服务启动失败时,删除该选项
# 使用:journalctl -u docker.service --since "5 minutes ago" 命令查看docker服务启动日志
mkdir -p /etc/docker /data/docker && cat > /etc/docker/daemon.json <<EOF
{
    "insecure-registries": [
        "10.2.41.191:5000"
    ],
    "registry-mirrors": [
        "https://dockerproxy.com",
        "https://hub-mirror.c.163.com",
        "https://mirror.baidubce.com",
        "https://ccr.ccs.tencentyun.com"
    ],
    "proxies": {
        "http-proxy": "http://proxy.example.com:3128",
        "https-proxy": "https://proxy.example.com:3129",
        "no-proxy": "*.test.example.com,.example.org,127.0.0.0/8"
    },
    "data-root": "/data/docker",
    "exec-opts": [
        "native.cgroupdriver=systemd"
    ],
    "log-level": "info",
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "20m",
        "max-file": "3"
    },
    "storage-driver": "overlay2",
    "storage-opts": [
        "overlay2.override_kernel_check=true"
    ]
}
EOF

3、docker镜像操作常用命令

# 登陆本地docker仓库
docker login -u[user] -p[password] localhost:8080
# 登出本地docker仓库
docker logout localhost:8080
# 打包系统(--exclude:排除指定目录,两条命令二选一,注意第二条命令后面有个点)
tar -cvpf /tmp/centos6-base.tar --exclude=proc --exclude=sys --exclude=dev --exclude=run --exclude=boot /
tar -cvpf /tmp/system.tar --directory=/ --exclude=proc --exclude=sys --exclude=dev --exclude=run --exclude=boot .
# 导入打包好的系统(注意docker镜像名不能有大写字母)
cat centos6-base.tar | docker import - centos6-base
docker import centos6-base.tar centos6-base
# 启动并进入容器,--rm:退出容器后自动删除容器,一般用于测试容器是否能正常运行
docker run -it --rm --name=alpine alpine:latest /bin/sh
# -p:映射端口,--name:指定容器名称,-d:表示放到后台运行,--net:指定网络类型(bridge|host|none|container:NAME/ID|user_defined_network)
docker run -p 8080:80 -p 162:162/udp --hostname=test --net=bridge --name=[NAMES] -it -d [REPOSITORY[:TAG]] /bin/bash
# 提交一个运行中的容器为镜像(-p:在commit时,将容器暂停)
docker commit -p [CONTAINER ID] [REPOSITORY[:TAG]]
# 下载docker镜像,加[:TAG]下载指定版本的镜像(centos7-ansible:6.4),不加则下载最新的镜像
docker pull ansible/centos7-ansible
# 查看本地的docker镜像
docker images
# 将Docker镜像打包成tar归档文件
docker save -o /root/image.tar [REPOSITORY]:[TAG]
# 将多个Docker镜像打包成一个tar归档文件
docker save -o images.tar image1:tag1 image2:tag2 image3:tag3 ...
# 导入.tar归档文件
docker load </root/image.tar
docker load -i /root/image.tar
# 把.tar归档文件打包为.gz格式,-9,使用最高压缩率,-k,保留原文件
gzip -c image.tar >image.tar.gz
gzip -9k image.tar
# 解压.gz格式的镜像文件
gzip -d image.tar.gz
gunzip -c image.tar.gz > image.tar
# 直接导入.gz格式的镜像文件
gzip -dc image.tar.gz | docker load
gunzip -c image.tar.gz | docker load
# 把.tar归档文件打包为.xz格式,-k,保留原文件,-z,显式指定压缩模式
xz -c image.tar >image.tar.xz
xz -T0 -zk image.tar
# 解压.xz格式的镜像文件,-d,解压,-k,保留原文件,xzcat等价于xz -dc,-Tn,使用n个线程,-T0,让程序选择线程数(使用所有可用核心)
xz -T0 -dk image.tar.xz
xzcat -T0 -k image.tar.xz >image.tar
# 直接导入.xz格式的镜像文件
xz -T0 -dc image.tar.xz | docker load
xzcat -T0 image.tar.xz | docker load
# 删除docker镜像
docker image rm -f [REPOSITORY]:[TAG]
# 删除旧标签,此操作仅删除标签,不会删除镜像本身,若还有其他标签指向同一镜像则不会删除镜像数据
docker rmi oldname1:tag1 oldname2:tag2
# 在仓库中搜索docker镜像
docker search centos7
# 检查网络配置
docker network inspect bridge

4、docker容器操作常用命令

# 运行一个容器(-d:后台运行容器;--privileged:使container内的root拥有真正的root权限)
docker container run -d --privileged -it [镜像名称] /sbin/init
# 启动或停止容器
docker container start/stop [CONTAINER ID]/[NAMES]
# 查看容器日志
docker logs [CONTAINER ID]/[NAMES]
# 进入已启动的docker容器
docker exec -it [CONTAINER ID]/[NAMES] sh
# 强制删除运行中的docker容器
docker container rm -f [CONTAINER ID]/[NAMES]
# 查看所有docker容器,docker ps查看运行中的容器
docker ps -a
# 修改容器名称
docker container rename [NAMES] [NEW_NAMES]
# 查看docker默认配置文件目录
docker info | grep "Docker Root Dir"
# 容器默认配置文件目录(489a4ec81e86前十二位为容器container id)
cd /var/lib/docker/containers/489a4ec81e869cade7fb1bd887f51f72727606ea2602292f98e10fd2fb80985b/
# 查看多个容器运行状态
docker stats [NAMES] [NAMES]
# 拷贝宿主机文件到容器
docker cp my.sh c3646071ecd2:/opt/my.sh
# 拷贝容器中的文件到宿主机
docker cp c3646071ecd2:/opt/my.sh ./my.sh
# 只清理未使用的容器
docker container prune
# 只清理未使用的镜像
docker image prune -a
# 只清理未使用的网络
docker network prune
# 只清理未使用的卷
docker volume prune
# 仅清理未使用的缓存条目(默认行为,保留当前正在使用的缓存,需要确认时不会删除正在使用的缓存)
docker builder prune
# 强制无提示清理(谨慎使用)
docker builder prune -f
# 仅保留最近1天的构建缓存
docker builder prune --filter "until=24h" -f
# 查看将要删除的内容(预览模式)
docker system prune --dry-run
# 清理未使用的镜像、容器、网络、卷
docker system prune
# 删除所有未使用的容器、镜像、网络和构建缓存
docker system prune -a
# 强制删除,不提示确认
docker system prune -a -f

5、运行中的docker容器增加端口映射
iptables -A DOCKER ! -i docker0 -o docker0 -p tcp -s 0.0.0.0/0 -d 172.17.0.2 --dport 65510 -j ACCEPT
iptables -t nat -A DOCKER ! -i docker0 -p tcp --dport 65510-j DNAT --to-destination 172.17.0.2:65510
iptables -t nat -A POSTROUTING -p tcp --dport 65510 -j MASQUERADE
iptables -nvL
iptables -t nat -nvL
查看container端口映射(使用iptables开启的端口映射无法查看)
docker container port [CONTAINER] 80/tcp
docker port [CONTAINER] 80/tcp

6、docker的五种网络模式
--net=bridge|host|none|container:container_id/container_name|user_defined_network   #指定容器网络模式;
--net=bridge   #默认模式。为容器创建独立的网络命名空间,分配网卡、IP地址等网络配置,并通过veth接口对,将容器挂载到一个虚拟网桥(默认为docker0)上,类似于VMware的NAT模式;
--net=host    #不为容器创建独立的网络命名空间,容器内看到的网络配置(网卡信息、路由表、Iptables规则等)均与主机上保持一致。注意其他资源还是与主机隔离的,类似于VMware的桥接模式;
--net=none    #为容器创建独立的网络命名空间,但不进行网络配置,即容器内没有创建网卡、IP地址等;
--net=container:container_id/container_name    #新创建的容器共享指定的已存在容器的网络命名空间,两个容器内的网络配置共享,但其他资源(进程空间、文件系统等)还是相互隔离的;
--net=user_defined_network    #用户自行用network相关命令创建一个网络,同一个网络内的容器彼此可见,可以采用更多类型的网络插件。
默认的桥接网络:在默认情况下,Docker使用docker0桥接网络连接所有容器。不提供自动的名字解析功能。
用户定义的桥接网络:当使用用户定义的桥接网络时,Docker会在该网络上启动一个嵌入式的DNS服务器。这个DNS服务器负责监听来自同一网络中容器的DNS查询,并将服务名称转换成相应的IP地址。实现通过容器名访问容器
https://cloud.tencent.com/developer/article/1922478      # docker容器间通信

# 创建自定义网络并固定容器IP,注意自定义网络才能固定容器IP
docker network create --driver=bridge --subnet=172.28.0.0/16 --gateway=172.28.0.1 customize_net
docker run --name report-backend --net=customize_net -p 162:162/udp -p 8000:8000 --ip=172.28.0.2 -v /app/reports:/app/reports -d report-backend:latest
docker run --name report-frontend -p 80:80 --net=customize_net --add-host=backend:172.28.0.2 --ip=172.28.0.3 -d report-frontend:latest
# 使用--dns向容器中添加dns地址
docker run --name report-frontend-dns -p 80:80 --dns 8.8.8.8 --dns 114.114.114.114 -d report-frontend:latest
# 查看当前Docker主机上的所有网络
docker network ls
# 查看网络配置
docker network inspect customize_net

7、修改容器配置文件
docker container stop fb7c338a6c93
systemctl stop docker.service
cd /var/lib/docker/containers/fb7c338a6c934359aff9936e32ebb69bf46dd7f64e1e7892a7340367850e7e0b
vim hostconfig.json
vim config.v2.json
systemctl start docker.service
docker ps -a
docker container start fb7c338a6c93
注意:
       修改容器配置文件前必需先停容器再停docker服务再修改容器配置文件,更改端口映射和网络模式,hostconfig.json文件和config.v2.json文件都需要修改。启动docker服务后使用docker ps -a命令查看不到修改完配置文件的容器时,请检查配置文件是否修改正确

8、创建容器启动脚本和健康检查脚本
[root@test /]# vim /bin/start.sh   #进入容器里创建start.sh脚本,并给脚本添加可执行权限(chmod +x /bin/start.sh)

#!/bin/bash

/etc/init.d/sshd start
/bin/bash    #保留一个终端,防止容器自动退出
# docker健康检查相关选项
docker run -d \
  --name my-container \
  --health-cmd="/check.sh" \     # 脚本必须在镜像里,脚本必须有可执行权限,脚本必须用exit 0 或exit 1 明确返回状态码,返回0 → Docker显示healthy,返回1 → Docker显示unhealthy
  --health-start-period=30s \    # 启动缓冲期:前30秒失败不计入不健康判定
  --health-interval=10s \        # 检查间隔:每10秒执行一次健康检查
  --health-retries=3 \           # 重试次数:连续失败3次才标记为unhealthy
  --health-timeout=5s \          # 超时时间:检查命令超过5秒没响应则视为失败(建议必加)
  [REPOSITORY[:TAG]]
# 返回STATUS列:healthy(健康) / unhealthy(不健康) / starting(启动缓冲期中)
docker inspect --format "{{.State.Health.Status}}" 容器名/ID
#!/bin/sh
# 健康检查脚本示例(check.sh)

# 检查 PostgreSQL 是否存活
if su - postgres -c "pg_isready -h localhost -p 5432 -q"; then
    # 获取主从状态,去除空白字符
    cluster_status=$(su - postgres -c "psql -t -c 'select pg_is_in_recovery();'" 2>/dev/null | xargs)
    if [ "$cluster_status" = "t" ]; then
        # 从库:停止除 PostgreSQL 外所有服务
        services=$(supervisorctl status | sed 's/\x1b\[[0-9;]*m//g' | grep -v 'postgresql' | awk '{print $1}' | xargs)
        if [ -n "$services" ]; then
            supervisorctl stop $services
        fi
    else
        # 主库:启动所有未运行服务
        services=$(supervisorctl status | sed 's/\x1b\[[0-9;]*m//g' | grep -v 'Running' | awk '{print $1}' | xargs)
        if [ -n "$services" ]; then
            supervisorctl start $services
        fi
    fi
    # PG 就绪,脚本退出0 → 健康检查成功
    exit 0
else
    # PG 未就绪,脚本退出1 → 健康检查失败
    exit 1
fi

9、docker容器使用systemctl命令报错
root@nginx:~# systemctl
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
使用以下命令运行容器

docker run --cpus 2 -m 2g -p 22:22 -p 5000:5000 --add-host=nginx:192.168.1.2 --add-host=mysql:192.168.1.3 -v /sites:/var/www/html --restart=always --privileged --name flask --hostname centos8 --net=bridge -it -d  centos8:1.0.0 /usr/sbin/init

参数说明:
     --cpus            指定可以使用cpu的核数
     -m                  指定可以使用的内存大小
     -p                   指定映射端口
     --add-host     添加hosts解析
     -v                   映射主机目录到容器目录
     --privileged   使容器有root权限需要和/usr/sbin/init配合使用
     --name          指定容器名称
     --hostname   指定容器主机名
     --net              指定网络类型
     --restart=always  "无条件重启"。无论容器如何停止(包括你手动docker stop),只要Docker守护进程启动运行,它就会尽力启动这个容器。它不区分容器停止的原因。 这通常用于你需要该容器持续运行,即使管理员手动停止后,也能在守护进程重启时自动恢复的场景(但需谨慎,这可能违背管理员意图)。
     --restart=unless-stopped  "除非已停止"。这是更常用且通常更符合预期的策略。容器因自身原因(进程退出)或Docker守护进程重启而停止时,它会自动重启。关键点:当且仅当容器是被用户使用docker stop命令明确停止时,Docker会记录这个"已停止"状态,并且以后(包括守护进程重启后)不再自动启动它。 这尊重了管理员的明确停止操作,是生产环境中实现高可用容器的推荐策略。

10、docker、ctr、crictl命令对比

命令 docker ctr(containerd),在k8s集群中使用ctr需要加上  -n k8s.io crictl(kubernetes)
查看运行的容器 docker ps ctr task ls/ctr container ls crictl ps
查看镜像 docker images ctr image ls
# 在k8s集群中使用ctr命令查看镜像
ctr -n k8s.io image ls
crictl images
查看容器日志 docker logs crictl logs
查看容器数据信息 docker inspect ctr container info [CONTAINER] crictl inspect
查看容器资源 docker stats ctr task metrics [TASK]
(获取容器的内存、CPU和PID的限额与使用量)
crictl stats
启动/关闭已有容器 docker start/stop ctr task kill [TASK]     (关闭)
ctr task rm [TASK]     (删除)
ctr task start --log-uri /var/log/xxx.log -d [CONTAINER]    (启动)
crictl start/stop
运行一个新的容器 docker run ctr run -d --rm --net-host --mount type=bind,src=[HOST_PATH],dst=[CONTAINER_PATH],options=rbind:rw --log-uri /var/log/xxx.log [IMAGE] [CONTAINER_NAME]
-d后台运行,--mount指定宿主机目录挂载到容器目录,--log-uri指定容器日志文件路径(需要先创建xxx.log文件)
无(最小单元为pod)
修改镜像标签 docker tag ctr image tag
# 在k8s集群中使用ctr修改镜像标签
ctr -n k8s.io images tag [源TAG] [修改后TAG]
创建一个新的容器 docker create ctr container create crictl create
导入镜像 docker load ctr -n k8s.io images import image.tar
# 在k8s集群中导入.gz和.xz格式镜像
gzip -dc image.tar.gz | ctr -n k8s.io images import -
xz -T0 -dc image.tar.xz | ctr -n k8s.io images import -
xzcat -T0 image.tar.xz | ctr -n k8s.io images import -
导出镜像 docker save ctr image export <导出文件名> <镜像名>
删除容器 docker rm ctr container rm crictl rm
删除镜像 docker rmi ctr image rm crictl rmi
拉取镜像 docker pull ctr image pull ctictl pull
推送镜像 docker push ctr image push
# 在k8s集群中使用ctr命令推送镜像,-k:忽略证书
ctr -n k8s.io image push -k [IMAGE]
进入容器内 docker exec

ctr task exec --exec-id 0 -t [TASK] sh
(必须要指定--exec-id,这个id可以随便写,只要唯一就行)

crictl exec

11、nerdctl工具操作Containerd

# k8s默认使用k8s.io,而nerdctl默认使用default namspace。如果需要查看k8s相关镜像需要加上"-n k8s.io"来指定
# 查看镜像
nerdctl -n k8s.io image ls
# 导出镜像
nerdctl -n k8s.io image save registry.images.net/nginx:latest -o nginx_latest.tar
# 导入镜像
nerdctl -n k8s.io image load -i nginx_latest.tar
# 修改镜像tag
nerdctl -n k8s.io tag registry.images.net/nginx:latest registry.cloud.net/nginx:latest
# 上传镜像到仓库
nerdctl -n k8s.io image push registry.cloud.net/nginx:latest
# 查看k8s集群中pod的CONTAINER ID
nerdctl -n k8s.io ps
# 进入pod
nerdctl -n k8s.io exec -it [CONTAINER ID] -- sh
# 登陆仓库
nerdctl login -u admin -p passw0rd registry.cloud.net
# 登出仓库
nerdctl logout registry.cloud.net

12、使用dockerfile文件构建镜像

# 使用本地镜像作为基础镜像,先把镜像pull到本地,然后再使用dockfile文件打包镜像,本地没有则从镜像源pull
# [root@localhost ~]# docker pull alpine
# [root@localhost ~]# docker images
# REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
# alpine              latest              aded1e1a5b37        3 weeks ago         7.83MB
FROM alpine:latest

# 设置工作目录
WORKDIR /app

# 定义WEBSERVER变量,如果没有指定,默认为nginx,该变量可以在构建Docker镜像时通过--build-arg选项传递给Docker build
# docker build --build-arg WEBSERVER=apache -t registry.docker.net/apache:1.0 .
#ARG WEBSERVER=nginx

# 在Dockerfile中使用Shell命令实现条件逻辑,每个RUN命令都会在Docker镜像中创建一个新层,这会增加镜像的大小。可以尝试使用&&连接符组合命令
#RUN if [ "$WEBSERVER" = "nginx" ]; then \
#       apk update && apk install -y nginx; \
#   elif [ "$WEBSERVER" = "apache" ]; then \
#       apt-get update && apt-get install -y apache2; \
#   else \
#       echo "No valid webserver specified"; \
#   fi

# alpine镜像修改时区
#RUN apk add --no-cache tzdata \
#    && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
#    && echo "Asia/Shanghai" > /etc/timezone \
#    && rm -rf /usr/share/zoneinfo/UTC || true    # 清理tzdata的缓存信息(可选,减少镜像大小)

# alpine镜像安装中文字体包,其它镜像中文字体包名:ttf-noto-cjk
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
#    && apk update \
#    && apk add --no-cache fontconfig ttf-dejavu freetype harfbuzz ca-certificates \
#    && apk add --no-cache ttf-freefont font-noto-cjk \
#    && fc-cache -fv

# --no-cache-dir: 这个选项告诉pip不要缓存安装包,以减少镜像的体积。在Docker中,由于每个命令都会生成一个新的镜像层,如果不使用这个选项,pip会将下载的包缓存到镜像中,从而增加镜像的大小
#COPY requirements.txt .
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
#    && apk add --no-cache python3 py3-pip \
#    && pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/

# 安装Python依赖包
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk add --no-cache curl python3 py3-pip \
    && pip install --no-cache-dir --break-system-packages \
    Flask \
    gevent \
    gevent-websocket \
    Flask-SocketIO \
    flask-sqlalchemy \
    paramiko \
    requests \
    -i https://mirrors.aliyun.com/pypi/simple/

# 暴露Flask默认端口(按需修改)
EXPOSE 5000

# 建议在运行时挂载代码,或在此处添加代码复制
COPY flask /app/flask

# 设置默认启动命令(根据实际情况修改)
CMD ["python", "./flask/flaskrun.py"]

# -f dockerfile: 这个选项指定要使用的Dockerfile的文件名。默认情况下,Docker会查找名为Dockerfile的文件,但如果你将其命名为其他文件名(如 dockerfile),就需要使用此选项来指定。
# -t flask:1.0: 这个选项用于为创建的镜像指定一个名称和标签。在这里,镜像的名称是 flask,标签是 1.0,最终形成的完整镜像名为 flask:1.0。
# .: 这个点表示上下文目录。Docker客户端会将当前目录中的文件(及其子目录)作为构建上下文,Dockerfile 中的指令能使用这些文件。
# 使用dockerfile文件构建镜像命令
# [root@localhost ~]# docker build -t registry.docker.net/flask:1.0 -f dockerfile .
# [root@localhost ~]# docker images
# REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
# registry.docker.net/flask   1.0                 1bad3fad52ad        24 minutes ago      114MB
# alpine                      latest              aded1e1a5b37        3 weeks ago         7.83MB
# 启动docker
# [root@localhost ~]# docker run -p 5000:5000 --name flask -d registry.docker.net/flask:1.0
# [root@localhost ~]# docker ps -a
# CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
# 97d8bb75d612        registry.docker.net/flask:1.0   "python ./flask/flas…"   4 seconds ago       Up 3 seconds        0.0.0.0:5000->5000/tcp   flask
# 注意:使用docker save导出的镜像必需用docker load导入,否则导入的镜像将不可用

# 容器健康状态检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
   CMD curl -f http://localhost:5000 || exit 1
# 每隔30秒执行一次curl -f http://localhost:5000,容器启动10秒后开始检测,如果失败超过3次且超时在5秒内,该容器被判定为不健康
# CMD curl -f http://localhost:5000:执行的命令,如果命令返回状态码0,表示健康;非0表示不健康
# --interval:两次检测间隔时间,默认30秒
# --timeout:每次检测超时时间,超过认为失败,默认30秒
# --start-period:容器启动后多长时间开始健康检测,默认0
# --retries:失败多少次后标记为不健康,默认3
# 注意:在Dockerfile中只能有一个HEALTHCHECK指令。如果您列出多个,则只有最后一个HEALTHCHECK将生效

13、Dockerfile多阶段构建镜像示例

# 构建阶段命名:AS builder将此阶段命名为builder,后续阶段可以使用FROM ... AS final,并通过COPY --from=builder将构建产物从该阶段拷贝到最终镜像
# Stage: builder
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage: runtime
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]

14、多架构镜像构建

# 安装buildx
mkdir -p /usr/libexec/docker/cli-plugins
BUILDX_VERSION=v0.32.1
curl -L "https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-amd64" \
  -o /usr/libexec/docker/cli-plugins/docker-buildx
chmod +x /usr/libexec/docker/cli-plugins/docker-buildx
# 安装QEMU模拟器
docker run --rm --privileged tonistiigi/binfmt --install all
# 创建一个支持多平台的builder,--driver docker-container,默认的docker驱动不支持多平台构建,必须切换到docker-container驱动,它会启动一个独立的BuildKit 容器来执行构建任务
docker buildx create --name multiarch --platform linux/amd64,linux/arm64,linux/arm/v7 --driver docker-container --bootstrap --use
# 检查支持的平台列表
docker buildx inspect multiarch --bootstrap | grep Platforms:
Platforms:  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/loong64, linux/arm/v7, linux/arm/v6
# 查看已创建的builde
docker buildx ls
# 切换到已存在的builde
docker buildx use multiarch
# 删除一个builde
docker buildx rm multiarch
# 构建多架构镜像并把镜像推送到仓库
# --platform,参数指定目标平台,逗号分隔。--push,是必须的。多平台镜像无法直接--load到本地Docker(因为本地只能存一个平台的镜像),所以必须推送到远程仓库
docker buildx build --platform linux/amd64,linux/arm64 -t your-registry/your-app:tag --push .
# 本地测试单个平台单独指定,不支持同时指定两个平台:--platform linux/arm64 --load
docker buildx build --platform linux/arm64 --pull --no-cache -t myapp:latest --load .
# 验证manifest list,你会看到它包含两个平台的 digest,确认构建成功
docker buildx imagetools inspect your-registry/your-app:latest
# 安装QEMU用户态模拟器
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# 使用qemu-user手动模拟
docker run -it --rm --platform linux/arm64 --name myapp myapp:latest /bin/sh
# 验证镜像平台
docker image inspect myapp:latest --format '{{.Architecture}}/{{.Os}}'
#!/usr/bin/env bash
set -euo pipefail

########################################
# 0) 变量(按需修改)
########################################
REGISTRY="crpi-g05smmlotxjkdb8e.cn-hangzhou.personal.cr.aliyuncs.com"
NAMESPACE="xwupiaomiao"

BASE_REPO="${REGISTRY}/${NAMESPACE}/alpine"
BASE_TAG="3.20-multi"

APP_REPO="${REGISTRY}/${NAMESPACE}/myapp"
APP_TAG="v1.0.0"

# myapp 项目目录(含 Dockerfile)
APP_DIR="/root"

########################################
# 1) 登录私有仓库
########################################
docker login "${REGISTRY}"

########################################
# 2) 安装/注册 binfmt(支持跨架构构建)
########################################
docker run --privileged --rm tonistiigi/binfmt --install all

########################################
# 3) 准备 buildx builder
########################################
docker buildx rm multiarch >/dev/null 2>&1 || true
docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap

########################################
# 4) 发布多架构 base 到私有仓库
#    用官方 alpine 作为源,推成你私有仓库 tag
########################################
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t "${BASE_REPO}:${BASE_TAG}" \
  --pull \
  --push \
  - <<'EOF'
FROM alpine:3.20
EOF

########################################
# 5) 验证 base 是多架构
########################################
docker buildx imagetools inspect "${BASE_REPO}:${BASE_TAG}"

########################################
# 6) 生成/覆盖 myapp Dockerfile(示例)
#    如果你已有 Dockerfile,可只把 FROM 改成私有 multi-arch base
########################################
cat > "${APP_DIR}/Dockerfile" <<EOF
FROM ${BASE_REPO}:${BASE_TAG}
CMD ["/bin/sh"]
EOF

########################################
# 7) 发布 myapp 多架构镜像
########################################
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t "${APP_REPO}:${APP_TAG}" \
  -t "${APP_REPO}:latest" \
  --pull \
  --push \
  "${APP_DIR}"

########################################
# 8) 验证 myapp 是多架构
########################################
docker buildx imagetools inspect "${APP_REPO}:${APP_TAG}"
docker buildx imagetools inspect "${APP_REPO}:latest"

########################################
# 9) 本地拉取并验证 arm64 运行
# docker buildx imagetools inspect <image>:<tag> 里要看到:
# linux/amd64
# linux/arm64
# arm64 容器里 readelf -h /bin/sh 要出现 Machine: AArch64
########################################
docker pull --platform linux/arm64 "${APP_REPO}:${APP_TAG}"
docker run --rm --platform linux/arm64 "${APP_REPO}:${APP_TAG}" sh -c "readelf -h /bin/sh | grep Machine || true"
docker image inspect "${APP_REPO}:${APP_TAG}" --format '{{.Architecture}}/{{.Os}}'
View Code

15、 阿里云docker pull镜像报错

[root@localhost ~]# docker pull crpi-g05smmlotxjkdb8e.cn-hangzhou.personal.cr.aliyuncs.com/xxxxxx/alpine
Using default tag: latest
Error: remote trust data does not exist for crpi-g05smmlotxjkdb8e.cn-hangzhou.personal.cr.aliyuncs.com/xxxxxx/alpine: crpi-g05smmlotxjkdb8e.cn-hangzhou.personal.cr.aliyuncs.com does not have trust data for crpi-g05smmlotxjkdb8e.cn-hangzhou.personal.cr.aliyuncs.com/xxxxxx/alpine
# 解决方法,设置环境变量来禁用内容信任,这样运行的Docker pull命令将不会进行内容信任验证
# 临时允许未签名的镜像
[root@localhost ~]# export DOCKER_CONTENT_TRUST=false
# 永久设置
[root@localhost ~]# echo "export DOCKER_CONTENT_TRUST=false" >>.bashrc
[root@localhost ~]# source ~/.bashrc
# 允许使用未签名的镜像源
[root@localhost ~]# echo '{"insecure-registries": ["your-registry-address:port"]}' >/etc/docker/daemon.json
# 启动Docker守护进程时添加--insecure-registry
[root@localhost ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --insecure-registry your-registry-address:port

16、docker-compose常用命令

# ==================== 服务启动与停止(最常用) ====================
docker compose up -d          # 后台静默启动所有服务,生产/开发首选
docker compose up             # 前台启动,实时打印所有服务日志,适合调试
docker compose down           # 停止并删除容器、网络,保留数据卷(安全清理)
docker compose down -v        # 彻底清理:删除容器+网络+数据卷(数据清空,谨慎使用)

# ==================== 状态查看与日志排查 ====================
docker compose ps                  # 快速查看所有服务运行状态、端口、运行时长
docker compose logs                # 查看所有服务全部日志
docker compose logs -f web         # 实时跟踪 Web 服务动态日志(高频排查问题)
docker compose logs --tail=50 db   # 只查看数据库最近50行日志,精准定位报错

# ==================== 单服务精准操作 ====================
docker compose restart web    # 单独重启指定服务
docker compose stop web       # 停止指定服务,保留容器
docker compose start web      # 启动已停止的指定服务
docker compose up -d db       # 单独启动/更新指定服务

# ==================== 容器进入与交互式操作 ====================
docker compose exec db bash          # 进入数据库容器终端
docker compose exec web sh           # 进入 Web 服务容器终端
docker compose exec cache redis-cli  # 直接连接 Redis 命令行

# ==================== 配置校验与辅助操作 ====================
docker compose config             # 校验 YAML 配置文件语法是否报错
docker compose config --services  # 列出当前项目所有已定义服务
docker compose top                # 查看各容器内部运行进程

# ==================== 部署与运维操作 ====================
docker compose -f docker-compose.yml up -d     # 一键后台启动服务
docker compose -f docker-compose.yml ps        # 查看服务运行状态
docker compose -f docker-compose.yml down      # 停止服务,保留所有数据(文章、主题、插件不丢失)
docker compose -f docker-compose.yml down -v   # 彻底清空所有数据,重置环境(谨慎使用)

17、docker-compose.yml配置文件示例

services:
  my-service:
    # 镜像配置(二选一:直接拉取/本地构建)
    image: my-image:v1          # 直接使用远程/本地已有镜像
    build: .                    # 从当前目录 Dockerfile 构建镜像
    build:                      # 精细化构建配置
      context: ./backend        # 构建上下文目录
      dockerfile: Dockerfile.prod   # 指定专属构建文件
      args:                     # 构建阶段环境变量
        - APP_VERSION=v1.0

    # 端口映射配置
    ports:
      - "8080:80"               # 主机端口:容器端口
      - "127.0.0.1:8080:80"     # 仅绑定本地访问,禁止外网访问

    # 数据挂载配置(两种核心方式)
    volumes:
      - ./data:/app/data           # 绑定挂载:本地目录与容器目录同步
      - my-named-vol:/app/storage  # 命名卷:Compose 托管持久化存储

    # 环境变量配置(三种写法)
    environment:
      - KEY=value               # 列表式配置
    environment:                
      KEY: value                # 字典式配置(更清晰)
    env_file:
      - .env                    # 加载外部环境变量文件(适合存放敏感信息)

    # 依赖与重启策略
    depends_on:
      - db                      # 服务启动依赖
    restart: unless-stopped     # 重启策略:always/on-failure/no/unless-stopped

    # 网络与资源限制
    networks:
      - frontend
    deploy:
      resources:
        limits:
          cpus: '1.0'           # 限制CPU核心数
          memory: 512M          # 限制最大内存占用

    # 服务健康检查(保障服务稳定运行)
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s             # 检查间隔
      timeout: 10s              # 超时判定时间
      retries: 3                # 失败重试次数
      start_period: 40s         # 启动预热等待时间

    # 自定义启动配置
    command: ["python", "app.py"]   # 覆盖镜像默认启动命令
    entrypoint: ["/entrypoint.sh"]  # 覆盖容器入口脚本
    working_dir: /app              # 容器工作目录
    user: "1000:1000"              # 指定容器运行用户

参考链接:
      https://docs.docker.com/reference/
      https://www.cnblogs.com/acatsmiling/p/18474276                # 二进制安装Docker以及Docker Compose
      https://download.docker.com/linux/static/stable/x86_64/       # docker二进制文件下载
      https://www.cnblogs.com/fps2tao/p/10557257.html              # 修改运行中的docker容器的端口映射
      https://www.cnblogs.com/kingsonfu/p/11578073.html          # docker容器添加对外映射端口
      https://www.cnblogs.com/maohai-kdg/p/13474024.html       # docker安装
      https://hub-stage.docker.com/_/centos/tags         # CentOS docker镜像
      https://www.cnblogs.com/zoujiaojiao/p/17021724.html        # nsenter命令进入容器网络命名空间
      https://blog.csdn.net/qq_35745940/article/details/119900634       # nsenter命令进入容器网络命名空间
      https://www.cnblogs.com/lifuqiang/articles/16815740.html           #  安装containerd
      https://www.akiraka.net/kubernetes/1139.html#18         # docker、ctr、crictl命令对比
      https://www.cnblogs.com/hukey/p/17282408.html         # ctr命令使用说明
      https://icloudnative.io/posts/getting-started-with-containerd/      # Containerd使用教程
      https://github.com/containerd/nerdctl                                   # nerdctl工具下载
      https://www.cnblogs.com/kissit/p/18366388                        # Containerd高级命令行工具nerdctl安装及使用
      https://www.cnblogs.com/chen2ha/p/17086900.html          # containerd镜像构建工具nerdctl和buildkit
      https://github.com/moby/buildkit                                          # buildctl和builkitd下载
      https://www.jianshu.com/p/835179171609                         # 使用buildkit构建镜像
      https://github.com/tech-shrimp/docker_image_pusher       # 从github推送镜像到aliyun个人仓库
      https://docker.aityp.com/         # 渡渡鸟镜像同步站
      https://www.rclogs.com/2024/06/docker-registry-build               # 自建Docker镜像/源加速的方法
      https://blog.csdn.net/u010702254/article/details/146243390     # x86与Arm多架构Docker镜像打包
      https://github.com/xfan1024/qemu-user-static                          # 在x86架构上运行其它架构的docker
      https://docs.podman.org.cn/en/latest/Commands.html            # 使用podman命令管理容器

posted @ 2021-05-26 16:05  風£飛  阅读(602)  评论(0)    收藏  举报