单机编排&&私有镜像仓库
6948 字
35 分钟
单机编排&&私有镜像仓库

单机编排&&私有镜像仓库
[TOC]
docker-compose(单体服务)
docker-compose是Docker公司用来编排docker容器的一款工具允许用户通过一个 YAML 文件 --> 来配置应用程序的"服务"、"网络"和"数据卷"等# 通常称为 docker-compose.yml==================================# 自行清理环境[root@Docker ~]# docker rm -f $(docker ps -aq)[root@Docker ~]# docker network prune -f[root@Docker ~]# docker volume prune -fa
1)检测是否安装[root@Docker ~]# rpm -qa | grep docker-composedocker-compose-plugin-5.1.3-1.el10.x86_64[root@Docker ~]# docker compose versionDocker Compose version v5.1.3
2)单服务服务编排[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir ./docker-compose && cd ./docker-compose# 创建项目名 --> docker-compose[root@Docker docker-compose]# vim myweb.yml'名字随意,可以 -f 指定运行,但必须是yml结尾⚠️'services:# 定义一个服务# 有s myweb: # 服务的名称 image: nginx:latest # 指定镜像的名称 container_name: c1 # 指定容器的名称 ports: # 指定该端口映射 - "81:80"
3)启动服务 --> up[root@Docker docker-compose]# docker compose -f myweb.yml up -d✅️ -f 指定compose文件✅️ -d 表示放在后台运行[+] up 2/2 ✔ Network docker-compose_default Created # 创建网络 ✔ Container c1 Started # 启动容器[root@Docker docker-compose]# docker network ls | grep defaultdocker-compose_default bridge local📌 先创建了个网络[root@Docker docker-compose]# docker psnginx:latest "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 0.0.0.0:81->80/tcp, [::]:81->80/tcp c1📌 又跑了一个Nginx容器
4)查看运行状态[root@Docker docker-compose]# docker-compose psdocker-compose: command not found[root@Docker docker-compose]# docker compose psno configuration file provided: not found"没有找到配置文件"# 因为我们改了默认的名字,所以得-f指定才能够找到![root@Docker docker-compose]# docker compose -f myweb.yml ps✅️ ps --> 这个项目运行的"容器状态"# 这个项目只跑了一个容器c1 nginx:latest "/docker-entrypoint.…" myweb 9 minutes ago Up 9 minutes 0.0.0.0:81->80/tcp, [::]:81->80tcp[root@Docker docker-compose]# curl localhost:81<title>Welcome to nginx!</title>[root@Docker docker-compose]# docker compose ls✅️ 列出正在运行的"compose项目"NAME STATUS CONFIG FILESdocker-compose running(1) /root/docker-compose/myweb.yml👆项目目录 👆正在运行的容器 👆主配置文件[root@Docker docker-compose]# docker inspect c1 | grep IPAddress "IPAddress": "172.22.0.2",
5)停止并"移除"容器 --> down[root@Docker docker-compose]# docker compose -f myweb.yml down -t 0✅️ -t 0 立即执行[+] down 2/2 ✔ Container c1 Removed ✔ Network docker-compose_default Removed[root@Docker docker-compose]# docker network ls | grep default# 刚才自动创建的网络被移除了 ✅️[root@Docker docker-compose]# docker ps -a | grep c1# 自动创建的容器也被移除了 ✅️'mysql单体服务'# 自行清理环境
1)环境准备[root@Docker ~]# pwd/root[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir ./mydb && cd ./mydb[root@Docker mydb]# docker images | grep mysqlmysql:8.0.36 a53272402242 833MB
2)编写主配置文件[root@Docker mydb]# vim db_server.ymlservices: db_server: image: mysql:8.0.36 container_name: db01 ports: - "3306:3306" environment: # 定义环境变量 # 相当于 docker run -e key=value MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "wordpress" MYSQL_USER: "jiuzhao" MYSQL_PASSWORD: "passwd" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] # 向容器传递参数 # 覆盖原来的CMD指令 --> mysqld# 既然我们学完Dockerfile了# 我们来看一下镜像的详细信息[root@Docker ~]# docker inspect mysql:8.0.36"Config": { "ExposedPorts": { <-- 暴漏端口 ✅️ "3306/tcp": {}, "33060/tcp": {} }, "Env": [ <-- 环境变量 ✅️ "GOSU_VERSION=1.17", "MYSQL_MAJOR=8.0", "MYSQL_VERSION=8.0.36-1.el8", "MYSQL_SHELL_VERSION=8.0.36-1.el8" ], "Entrypoint": [ <-- 固定入口 ✅️ "docker-entrypoint.sh" ], # 这是一个初始化脚本 # 👇的CMD用来传递参数 "Cmd": [ "mysqld" <-- 默认参数 ✅️ ], # 默认执行 docker-entrypoint.sh mysqld --character-set-server=utf8 --collation-server=utf8_bin # 会覆盖掉原来的CMD指令 "Volumes": { <-- 数据卷 ✅️ "/var/lib/mysql": {} }, # 默认创建匿名数据卷3)启动服务[root@Docker mydb]# docker compose -f db_server.yml up -d# 同样是放在后台运行[+] up 2/2 ✔ Network mydb_default Created --> ✅️ 网络 ✔ Container db01 Started --> ✅️ 容器[root@Docker mydb]# docker compose lsNAME STATUS CONFIG FILESmydb running(1) /root/mydb/db_server.yml[root@Docker mydb]# docker network ls | grep mydba425873c55f1 mydb_default bridge local[root@Docker mydb]# docker compose -f db_server.yml psdb01 mysql:8.0.36 "docker-entrypoint.s…" db_server 46 seconds ago Up 45 seconds 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp
4)测试验证[root@Docker mydb]# docker exec -it db01 mysqlWelcome to the MySQL monitor.mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || wordpress ✅️ |+--------------------+
5)停止&&移除mysql> exitBye[root@Docker mydb]# docker compose -f db_server.yml down -t 0[+] down 2/2 ✔ Container db01 Removed ✔ Network mydb_default Removed数据持久化
1)准备工作[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir ./db-volume && cd ./db-volume
2)编写配置文件[root@Docker db-volume]# vim docker-compose.ymlservices: db_server: image: mysql:8.0.36 container_name: db02 ports: - "3306:3306" environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "wordpress" MYSQL_USER: "jiuzhao" MYSQL_PASSWORD: "passwd" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] volumes: # 存储卷名称(别名):容器挂载点:读写模式(rw,ro) - db:/var/lib/mysql:rw - web:/code:rw# db和 web是内部引用名,方便在 compose 文件中使用# 先引用,后声明
volumes: db: name: mysql-volume # 自定义 Docker 中实际的卷名称 web: name: web-server# mysql-volume和web-server是 Docker 实际创建的真实卷名==================================================# ⚠️如果不指定 name: web-server# ⚠️Docker 会自动创建 volumes: <-- "服务引用的数据卷" - db:/var/lib/mysql:rw - web:/code:rw
volumes:<-- "声明数据卷" db: name: mysql-volume web: "web没有指定name"[root@Docker db-volume]# docker compose up -d[+] up 4/4 ✔ Network xxx 👇 项目名+别名 ✔ Volume db-volume_web⚠️ <-- 自动创建的名称 📌 ✔ Volume mysql-volume <-- 手动指定的名称 ✅️ ✔ Container xxx'都写到这了,不手动指定一下name吗???'================================================== volumes: - db:/var/lib/mysql:rw - web:/code:rw'只有引用卷db和web ,没有声明'[root@Docker db-volume]# docker compose up -d❌️ undefined volume db: invalid compose project=================================================='最后一种匿名数据卷' 🤡 不推荐 volumes: # 里面只有容器里面的路径 # 不能指定模式(rw/ro) - /var/lib/mysql - /code[root@Docker db-volume]# docker volume prune -f[root@Docker db-volume]# docker compose up -d[root@Docker db-volume]# docker volume lsDRIVER VOLUME NAMElocal 192fdxxx...local 5037bxxx...'后面是一串神秘的字符'Note
这样分开定义是为了==提供灵活性==
既可以在 compose 内部使用简短的别名,又可以精确控制实际的卷名称
3)启动服务[root@Docker db-volume]# docker compose up -d[+] up 4/4 ✔ Network db-volume_default Created ✔ Volume web-server Created ✔ Volume mysql-volume Created ✔ Container db02 Started"两个数据卷都创建成功了"[root@Docker db-volume]# docker volume lslocal mysql-volumelocal web-server[root@Docker db-volume]# docker compose psdb02 mysql:8.0.36 "docker-entrypoint.s…" db_server 58 seconds ago Up 57 seconds 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp[root@Docker db-volume]# docker compose lsNAME STATUS CONFIG FILESdb-volume running(1) /root/db-volume/docker-compose.yml
4)停止容器&&移除网络[root@Docker db-volume]# docker compose down[+] down 2/2 ✔ Container db02 Removed ✔ Network db-volume_default Removed'创建的时候是4个,移除的时候只移除了两个'✅️ 数据卷没有被移除![root@Docker db-volume]# docker volume lslocal mysql-volumelocal web-server
5) -v# 移除服务时,同时移除数据卷[root@Docker db-volume]# docker compose down -v[+] down 2/2 ✔ Volume web-server Removed ✔ Volume mysql-volume Removed# 重新执行了一遍,把数据卷也移除了!
6)综合演示[root@Docker db-volume]# docker compose up -d[+] up 4/4 ✔ Network db-volume_default Created ✔ Volume mysql-volume Created ✔ Volume web-server Created ✔ Container db02 Started[root@Docker db-volume]# docker compose down -v -t 0[+] down 4/4 ✔ Container db02 Removed ✔ Volume mysql-volume Removed ✔ Volume web-server Removed ✔ Network db-volume_default Removed"工作中,用的最多的就是 up down"自定义网络
1)准备[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir db-network && cd db-network[root@Docker db-network]# docker network lsNETWORK ID NAME DRIVER SCOPE66cc72cc26cd bridge bridge localbf4d048e4eed host host local5879c499792c none null local'现在只有3个默认的网络'
2)配置文件[root@Docker db-network]# vim docker-compose.ymlservices: db_server: image: mysql:8.0.36 container_name: db02 ports: - "3306:3306" environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "wordpress" MYSQL_USER: "jiuzhao" MYSQL_PASSWORD: "passwd" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] networks: # 只引用网络,没有声明(定义)网络 # 下面的这些只是别名 - db_net - web_net[root@Docker db-network]# docker compose up -d❌️ undefined network web_net: invalid compose project# 在项目中并没有被定义(声明)'自然是起不来的'================================= networks: - db_net - web_net# 先引用网络(别名),后声明
networks:# 声明真实的网络# name前面没有 - db_net: name: my_db web_net: name: my_web backup: name: my_backup[root@Docker db-network]# docker compose up -d'上面虽然声明了3个网络,但只创建了2个'# 只有db_net和web_net被服务引用,所以才会被创建[+] up 3/3 ✔ Network my_web Created ✅️ ✔ Network my_db Created ✅️ ✔ Container db02 Started[root@Docker db-network]# docker network lsNETWORK ID NAME DRIVER SCOPEdc02802cf1a2 my_db bridge local88fee2060426 my_web bridge local[root@Docker db-network]# docker network inspect my_db | grep -A 4 "Config\""" "Config": [ { "Subnet": "172.19.0.0/16", "Gateway": "172.19.0.1" }# 有这两个配置足以✅️ '容器的网络从.2开始分配IP地址'[root@Docker db-network]# docker network inspect my_web | grep -A 4 "Config\""" "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" }[root@Docker db-network]# docker inspect db02 | grep IPAddress "IPAddress": "172.19.0.2", "IPAddress": "172.18.0.2",# 对于我们刚创建的容器db02来说# 它是有两个网络的,都是从.2开始分配的IP地址
3)停止服务[root@Docker db-network]# docker compose down -t 0[+] down 3/3 ✔ Container db02 Removed ✔ Network my_web Removed ✔ Network my_db Removed'在停止服务的同时把网络也移除了!'✅️ 这里只有数据卷特殊,需要加-v才能移除 📌
4)声明网络的同时,指定驱动、子网、网关'这种是最麻烦的,不推荐' 🤡# 个人感觉,自定义网络名字就可以了[root@Docker db-network]# vim docker-compose.yml...xxxx # 省略 networks: - db_net - web_net
networks: db_net: name: my_db driver: bridge # 网络驱动,网桥 ipam: driver: default # 指定IPAM的驱动,一般使用默认值 config: # 只有subnet前面有 - - subnet: 172.28.0.0/16 gateway: 172.28.0.1 web_net: # 它使用默认的 name: my_web driver: bridge--------------------------------"IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.28.0.0/16", "Gateway": "172.28.0.1" }[root@Docker db-network]# docker compose up -d[+] up 3/3 ✔ Network my_web Created ✔ Network my_db Created ✔ Container db02 Started'我们主要去看具体的网络配置'[root@Docker db-network]# docker network inspect my_db | grep -A 4 "Config\""" "Config": [ { "Subnet": "172.28.0.0/16", "Gateway": "172.28.0.1" } ✅️ 这个就是我们手动指定的网络[root@Docker db-network]# docker network inspect my_web | grep -A 4 "Config\""" "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } 📌 自动创建的子网配置 # 它是接着docker 0 --> 172.17.0.1创建[root@Docker db-network]# docker compose down -t 0docker-compose(多服务编排)
wordpress部署
1)环境准备[root@Docker ~]# docker volume prune -fa[root@Docker ~]# docker network prune -f[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir mul-wordpress && cd mul-wordpress
2)编写配置[root@Docker mul-wordpress]# vim docker-compose.ymlservices: db_server: image: mysql:8.0.36 container_name: db ports: - "3306:3306" environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "wordpress" MYSQL_USER: "jiuzhao" MYSQL_PASSWORD: "passwd" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] volumes: - db:/var/lib/mysql:rw networks: - wp-net # 指定容器的重启策略 restart: unless-stopped
wordpress: # 依赖的服务要优先启动 depends_on: - db_server image: wordpress:6.7.1 container_name: wp restart: unless-stopped ports: - "81:80" environment: WORDPRESS_DB_HOST: db_server:3306 # 这里目标主机填的是服务名,而并非容器名 WORDPRESS_DB_USER: jiuzhao WORDPRESS_DB_PASSWORD: passwd WORDPRESS_DB_NAME: wordpress volumes: - wp:/var/www/html networks: - wp-net
networks:# 两个服务使用的是一个网络 wp-net: name: wordpress-net driver: bridge ipam: driver: default config: - subnet: 172.18.0.0/16 gateway: 172.18.0.1
volumes:# 两个服务分别使用一个数据卷 db: name: mysql-volume wp: name: wordpress-volume3)启动服务[root@Docker mul-wordpress]# docker compose up -d[+] up 5/5 ✔ Network wordpress-net Created ✔ Volume mysql-volume Created ✔ Volume wordpress-volume Created ✔ Container db Started ✔ Container wp Started"一个网络,两个数据卷"[root@Docker mul-wordpress]# docker compose lsNAME STATUS CONFIG FILESmul-wordpress running(2) ~/mul-wordpress/docker-compose.yml[root@Docker mul-wordpress]# docker compose psdb mysql:8.0.36 "docker-entrypoint.s…" db_server About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp-----------------------------------------------------wp wordpress:6.7.1 "docker-entrypoint.s…" wordpress About a minute ago Up About a minute 0.0.0.0:81->80/tcp, [::]:81->80/tcp[root@Docker mul-wordpress]# docker network lsefece4192527 wordpress-net bridge local[root@Docker mul-wordpress]# docker volume lsDRIVER VOLUME NAMElocal mysql-volumelocal wordpress-volume
4)访问测试http://10.0.0.99:81/"停止"docker compose down -t 0 -v
Zabbix部署
[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir zabbix-server && cd zabbix-server[root@Docker zabbix-server]# vim docker-compose.ymlservices: mysql: image: mysql:8.0.36 container_name: db restart: unless-stopped # 指定容器的重启策略 environment: MYSQL_ROOT_PASSWORD: "root_pwd" MYSQL_DATABASE: "zabbix" MYSQL_USER: "zabbix" MYSQL_PASSWORD: "passwd" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] volumes: - db:/var/lib/mysql:rw networks: - zabbix-net
zabbix-java-gateway: container_name: zabbix-java-gateway image: zabbix-java-gateway:alpine-7.2-latest restart: unless-stopped networks: - zabbix-net
zabbix-server: container_name: zabbix-server # 依赖哪个服务 depends_on: - mysql image: zabbix-server-mysql:alpine-7.2-latest restart: unless-stopped environment: DB_SERVER_HOST: mysql # 服务名 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: passwd MYSQL_ROOT_PASSWORD: "root_pwd" ZBX_JAVAGATEWAY: zabbix-java-gateway # 服务名 networks: - zabbix-net
zabbix-web-nginx-mysql: container_name: zabbix-web-nginx-mysql depends_on: - zabbix-server image: zabbix-web-nginx-mysql:alpine-7.2-latest ports: - "8080:8080" restart: unless-stopped environment: DB_SERVER_HOST: mysql MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: passwd MYSQL_ROOT_PASSWORD: "root_pwd" networks: - zabbix-net
networks: zabbix-net: name: zabbix driver: bridge ipam: driver: default config: - subnet: 172.20.0.0/16 gateway: 172.20.0.1
volumes: db: name: zabbix-mysql-volume[root@Docker zabbix-server]# docker network ls[root@Docker zabbix-server]# docker volume ls[root@Docker zabbix-server]# docker compose up -d[+] up 6/6 ✔ Network zabbix Created ✔ Volume zabbix-mysql-volume Created ✔ Container zabbix-java-gateway Started ✔ Container db Started ✔ Container zabbix-server Started ✔ Container zabbix-web-nginx-mysql Started"一个网络,一个数据卷""4个容器"[root@Docker zabbix-server]# docker network inspect zabbix | grep IPv4Address "IPv4Address": "172.20.0.4/16", "IPv4Address": "172.20.0.2/16", "IPv4Address": "172.20.0.3/16", "IPv4Address": "172.20.0.5/16",# 4个容器的IP地址!
http://10.0.0.99:8080/
LB负载

-
请自定义3个镜像,要求使用alpine作为基础镜像
-
然后使用docker-compose一键启动
- 用户访问lb后,轮询方式访问web01和web02
- 比例为 3:1
- 用户访问lb后,轮询方式访问web01和web02
🦄 我们使用Dockerfile写三个基础镜像
借鉴之前的笔记
1)环境清理docker compose down -t 0 -v[root@Docker ~]# rm -rf ./*[root@Docker ~]# mkdir lb-server && cd lb-server[root@Docker lb-server]# mkdir ./{conf,dockerfile}# 一个放配置文件,一个Dockerfile文件
2)Nginx配置文件准备[root@Docker lb-server]# vim ./conf/lb.conf# 负载均衡的配置文件 upstream webs { server web01 weight=3; server web02 weight=1;}server { listen 80; server_name diy.kpyun.com;
location / { proxy_pass http://webs; proxy_set_header Host $http_host; proxy_http_version 1.1; }}[root@Docker lb-server]# vim ./conf/default.conf# 两台web的配置文件server { listen 80 default_server; server_name _; root /code;
location / { index index.html; }}
3)Dockerfile文件编写[root@Docker lb-server]# vim ./dockerfile/lbFROM alpine:3.20.2EXPOSE 80RUN apk update && \ apk add nginx && \ rm -rf /var/cacheCOPY ./lb.conf /etc/nginx/http.d/default.confCMD ["nginx","-g","daemon off;"]- vim ./dockerfile/web01
FROM alpine:3.20.2EXPOSE 80RUN apk update && \ apk add nginx && \ rm -rf /var/cacheRUN mkdir /code && \ echo "web01..." > /code/index.htmlCOPY ./default.conf /etc/nginx/http.d/CMD ["nginx","-g","daemon off;"]- vim ./dockerfile/web02
FROM alpine:3.20.2EXPOSE 80RUN apk update && \ apk add nginx && \ rm -rf /var/cacheRUN mkdir /code && \ echo "web02..." > /code/index.htmlCOPY ./default.conf /etc/nginx/http.d/CMD ["nginx","-g","daemon off;"]4)生成镜像[root@Docker lb-server]# docker build -f ./dockerfile/lb -t my-lb:1.0 ./conf/[root@Docker lb-server]# docker build -f ./dockerfile/web01 -t my-web01:1.0 ./conf/[root@Docker lb-server]# docker build -f ./dockerfile/web02 -t my-web02:1.0 ./conf/[root@Docker lb-server]# docker imagesmy-lb:1.0 3292e8f72107 13.9MBmy-web01:1.0 3b28a35f13c7 13.9MBmy-web02:1.0 8d0461877ed5 13.9MB
5)docker-compose文件编写[root@Docker lb-server]# vim docker-compose.yml:services: lb: image: my-lb:1.0 container_name: lb restart: unless-stopped ports: - "90:80" networks: - webs-net
web01: container_name: web01 image: my-web01:1.0 restart: unless-stopped networks: - webs-net
web02: container_name: web02 image: my-web02:1.0 restart: unless-stopped networks: - webs-net
networks: webs-net: name: my_net driver: bridge ipam: driver: default config: - subnet: 172.21.0.0/16 gateway: 172.21.0.1[root@Docker lb-server]# docker compose up -d[+] up 4/4 ✔ Network my_net Created ✔ Container web02 Started ✔ Container web01 Started ✔ Container lb Started[root@Docker lb-server]# docker inspect lb | grep IPAddress "IPAddress": "172.21.0.2",[root@Docker lb-server]# tail -1 /etc/hosts172.21.0.2 diy.kpyun.com[root@Docker lb-server]# for i in `seq 10`;do curl diy.kpyun.com;doneweb01... ❤️web01... ❤️web01... ❤️web02... 💚web01... ❤️web01... ❤️web01... ❤️web02... 💚web01... ❤️web01... ❤️镜像仓库
什么是私有仓库❓️# 不对全世界开放的镜像仓库# 一般是公司内部使用的私有镜像仓库
为什么需要私有仓库❓️1)安全性问题# 官方镜像仓库大家都可以访问🌰 若都放在官方,大家都能拿到你们公司的自建镜像2)访问速度:🌰 官方的服务器在国外,访问速度慢==============================🔖私有仓库:1)docker registry:# 轻量级的私有镜像仓库# 基本上不占用内存,很适合学习环境中使用 ✅️ 会对存储的数据进行一定的压缩处理 ✅️ 占用内存不足20MB ❌️ 没有提供较好的WebUI ❌️ 维护起来比较麻烦,尤其是删除镜像2)harbor: 🦄 基于官方的"docker registry"进行二次开发 🦄 是一个适合企业级使用的镜像仓库🔖第三方仓库: --> 轩辕镜像站(docker.xuanyuan.run)🔖docker官方仓库: --> hub.docker.comdocker registry
"清理环境"[root@Docker ~]# rm -rf ./*docker rm -f $(docker ps -aq)docker network prune -fdocker volume prune -fa
1)拉取镜像[root@Docker ~]# docker pull docker.xuanyuan.run/registry:3.0.0# 自行改标签[root@Docker ~]# docker imagesregistry:3.0.0 6c5666b861f3 77.3MB
2)运行[root@Docker ~]# docker run -d --network host --restart=unless-stopped --name c1 -v img-volume:/var/lib/registry registry:3.0.0# 和宿主机共用一个网络# 用了一个数据卷[root@Docker ~]# docker volume lsDRIVER VOLUME NAMElocal img-volume[root@Docker ~]# docker ps registry:3.0.0 "/entrypoint.sh /etc…" c1[root@Docker ~]# ss -lntup | grep 5000"默认监听5000端口"tcp LISTEN 0 *:5000 users:(("registry",pid=8496,fd=3))# 默认提供了一个web-UI
浏览器访问:http://10.0.0.99:5000/v2/_catalog
[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog{"repositories":[]}# 这个仓库没有任何的数据推送镜像
1)打tag标签🏷️[root@Docker ~]# docker tag alpine:3.20.2 10.0.0.99:5000/base/alpine:3.20.2'服务器地址(IP+端口)/项目名称/镜像'# 三个部分组成[root@Docker ~]# docker push 10.0.0.99:5000/base/alpine:3.20.2'直接推镜像!'Unavailable --> 不可达http: server gave HTTP response to HTTPS client⚠️ 服务端(搭建的私有仓库)响应HTTP给客户端(我们自己)HTTPS# 我们客户端默认使用HTTPS协议
2)强制客户端走HTTP(不安全的仓库)[root@Docker ~]# vim /etc/docker/daemon.json# 新建的文件{ "insecure-registries": ["10.0.0.99:5000"]}[root@Docker ~]# systemctl restart docker[root@Docker ~]# docker info | grep Registries -A 2"重启服务后,配置生效" Insecure Registries: 10.0.0.99:5000 ::1/128[root@Docker ~]# docker ps"重启服务后,仍然运行" --> 重启策略 unless-stoppedregistry:3.0.0 "/entrypoint.sh /etc…" c1[root@Docker ~]# ss -lntup | grep 5000# 仍然监听5000端口tcp LISTEN 0 *:5000 users:(("registry",pid=9278,fd=3))
3)再次推送镜像[root@Docker ~]# docker push 10.0.0.99:5000/base/alpine:3.20.2The push refers to repository [10.0.0.99:5000/base/alpine]c6a83fedfae6: "Pushed"[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog✅️ {"repositories":["base/alpine"]}⚠️ 版本号被隐藏了
4)另一台机器拉取镜像[root@test ~]# docker pull 10.0.0.99:5000/base/alpine:3.20.2Error response from daemon:❌️ http: server gave HTTP response to HTTPS client# 一样的报错# 客户端使用的是HTTPS[root@test ~]# vim /etc/docker/daemon.json{ "insecure-registries": ["10.0.0.99:5000"]}[root@test ~]# systemctl restart docker[root@test ~]# docker info | grep Registries -A 2 Insecure Registries: 10.0.0.99:5000 127.0.0.0/8[root@test ~]# docker pull 10.0.0.99:5000/base/alpine:3.20.23.20.2: Pulling from base/alpineDigest: sha256:eddxxx... --> 签名✍️Status: Downloaded newer image for 10.0.0.99:5000/base/alpine:3.20.2👆 镜像地址'成功拉取'[root@test ~]# docker images10.0.0.99:5000/base/alpine 3.20.2删除镜像
[root@Docker ~]# hostname -I10.0.0.99# 切换回来[root@Docker ~]# docker exec -it c1 sh/ # cd /var/lib/registry/var/lib/registry # tree ././└── docker └── registry └── v2 ├── blobs │ └── repositories/var/lib/registry # cd docker/registry/v2/var/lib/registry/docker/registry/v2 # lsblobs repositories# 主要就是它俩Docker Registry ==存储结构==:
/var/lib/registry/docker/registry/v2/ 目录包含:
blobs/目录:- 存放实际的镜像层数据(layers)
- 文件以 SHA256 哈希值命名
- 包含镜像的所有层数据
repositories/目录:- 存放仓库元数据
- 包含标签、清单等信息
/var/lib/registry/docker/registry/v2 # du -sh ./*3.5M ./blobs20.0K ./repositories📌 alpine镜像原来的大小是 7.8MB --> 3.5M"Docker Registry 会对存储的数据进行一定的压缩处理"/var/lib/registry/docker/registry/v2 # ls repositories/base# 这个base就是我们起的项目名称
1)删除元数据/var/lib/registry/docker/registry/v2 # rm -rf repositories/base⚠️删除的是它里面的项目,而不是本身的repositories目录⚠️ ❌️ rm -rf repositories/ ✅️ rm -rf repositories/base[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog{"repositories":[]}# 已经没有了'但真实的数据并没有删除'/var/lib/registry/docker/registry/v2 # du -sh ./*3.5M ./blobs0 ./repositories <-- 依旧存在这个目录✅️# 只是少了 20K 而已
2)回收镜像层数据# 彻底释放存储空间/var/lib/registry/docker/registry/v2 # registry garbage-collect /etc/distribution/config.yml/var/lib/registry/docker/registry/v2 # du -sh ./*0 ./blobs0 ./repositories"这下子就都干净了!"bug解决
"描述:" 🏷️ 已经推送的镜像无法再次推送(需重启registry容器) 🏷️ 尽管已经删除回收,推送时会有缓存============================================[root@Docker ~]# docker push 10.0.0.99:5000/base/alpine:3.20.2'再次推送刚彻底删除的镜像'The push refers to repository [10.0.0.99:5000/base/alpine]c6a83fedfae6: "Layer already exists" <-- 已经显示出异样了⚠️# 描述的是exists已存在,而不是Pushed已推送✅️ 因为刚删除不久,有缓存[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog{"repositories":["base/alpine"]}# 这里尝试拉取一下页面,有它的元数据/var/lib/registry/docker/registry/v2 # du -sh ./*0 ./blobs12.0K ./repositories'切回去看容器内部数据'# 只有元数据,没有镜像数据"解决方案" 🦄 重启docker-registries容器即可[root@Docker ~]# docker restart c1'再次推送'[root@Docker ~]# docker push 10.0.0.99:5000/base/alpine:3.20.2The push refers to repository [10.0.0.99:5000/base/alpine]c6a83fedfae6: "Pushed"# 已推送[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog{"repositories":["base/alpine"]}[root@Docker ~]# docker exec -it c1 sh/ # cd /var/lib/registry//var/lib/registry # cd docker/registry/v2/var/lib/registry/docker/registry/v2 # du -sh ./*3.5M ./blobs20.0K ./repositories✅️ '一切都回来了'[root@Docker ~]# docker pull 10.0.0.99:5000/base/alpine:3.20.2✅️ '拉取自己的镜像仓库'3.20.2: Pulling from base/alpineDigest: sha256:eddxxxStatus: Downloaded newer image for 10.0.0.99:5000/base/alpine:3.20.2[root@Docker ~]# docker images10.0.0.99:5000/base/alpine:3.20.2 eddxxx 11.7MBharbor
Harbor 是 VMware 公司开源的==企业级镜像仓库==,主要特点如下:
-
提供安全、可靠的私有镜像存储和分发
-
底层使用 Docker Compose 来管理 Harbor 服务
-
提供图形化管理界面(Web UI)
GitHub 地址:https://github.com/goharbor/harbor
- 离线安装
- 这里==建议用v2.14版本==
- 复制标签没有bug


1)上传解压[root@Docker ~]# cd /tmp[root@Docker tmp]# lsharbor-offline-installer-v2.14.3.tgz[root@Docker tmp]# tar xf harbor-offline-installer-v2.14.3.tgz -C /usr/local/
2)修改配置文件[root@Docker tmp]# cd /usr/local/harbor/[root@Docker harbor]# lscommon.sh harbor.v2.14.3.tar.gz harbor.yml.tmpl ...[root@Docker harbor]# cp harbor.yml{.tmpl,}# 把备份文件复制出来"把后缀tmpl去掉"[root@Docker harbor]# ls...xxx harbor.yml.tmpl "harbor.yml"[root@Docker harbor]# vim harbor.ymlhostname: 10.0.0.99http: port: 80# 后面再启用HTTPSharbor_admin_password: passwd# 修改登录密码database: password: root123 max_idle_conns: 100 max_open_conns: 900 conn_max_lifetime: 5m conn_max_idle_time: 0data_volume: /var/lib/harbor# 更改数据卷目录# 如果卸载harbor的话,要把这个目录手动删除掉trivy: ignore_unfixed: false skip_update: false skip_java_db_update: false db_repository: ghcr.io/aquasecurity/trivy-db java_db_repository: ghcr.io/aquasecurity/trivy-java-db offline_scan: false security_check: vuln insecure: false timeout: 5m0sjobservice: max_job_workers: 10 max_job_duration_hours: 24 job_loggers: - STD_OUTPUT - FILE logger_sweeper_duration: 1notification: webhook_job_max_retry: 3 webhook_job_http_client_timeout: 3log: level: info local: rotate_count: 50 rotate_size: 200M location: /var/log/harbor_version: 2.15.0proxy: http_proxy: https_proxy: no_proxy: components: - core - jobservice - trivyupload_purging: enabled: true age: 168h interval: 24h dryrun: falsecache: enabled: false expire_hours: 243)安装harbor服务[root@Docker harbor]# ./install.sh# 底层就是用shell脚本写的[Step 5]: starting Harbor ...[+] up 10/10 ✔ Network harbor_harbor Created ✔ Container harbor-log Started ✔ Container harbor-db Started ✔ Container registryctl Started ✔ Container harbor-portal Started ✔ Container redis Started ✔ Container registry Started ✔ Container harbor-core Started ✔ Container harbor-jobservice Started ✔ Container nginx Started✅️ Harbor has been installed and started successfully.[root@Docker harbor]# docker compose lsNAME STATUS CONFIG FILESharbor running(9) /usr/local/harbor/docker-compose.yml
4)测试验证http://10.0.0.99/✅️用户名: admin✅️密码: passwd
新建项目


'推送命令'1)先打标记[root@Docker harbor]# docker tag alpine:3.20.2 10.0.0.99/kpyun/alpine:3.20.2
2)推送[root@Docker harbor]# docker push 10.0.0.99/kpyun/alpine:3.20.2dial tcp 10.0.0.99:443: connect: connection refused'还是老问题'# 客户端默认连接HTTPS:443端口
3)改配置&重启服务[root@Docker harbor]# vim /etc/docker/daemon.json{ "insecure-registries": ["10.0.0.99:5000","10.0.0.99"]}# 逗号分隔'修改Docker配置文件,需要重启服务'[root@Docker harbor]# systemctl restart docker[root@Docker harbor]# docker compose ps -aExited (128)........UpExited (128)Exited (128)'发现很多容器都异常退出了!'
4)停止再重启✅️ 常见的解决办法![root@Docker harbor]# docker compose down -t 0'小细节 --> 没有-v --> 保留数据卷'# 刚才创建的项目会保留下来[root@Docker harbor]# docker compose up -d# 再次启动容器
5)再次推送[root@Docker harbor]# docker push 10.0.0.99/kpyun/alpine:3.20.2authorization failed --> 认证失败,没有权限
6)需要先进行登录[root@Docker harbor]# docker login 10.0.0.99 -u admin -p passwd# 指定服务器地址,默认是Docker Hub# 我这里同时指定了密码Your credentials are stored unencrypted in '/root/.docker/config.json'.# 被存储在这个文件中[root@Docker harbor]# cat /root/.docker/config.json{ "auths": { "10.0.0.99": { "auth": "YWRtaW46cGFzc3dk" } }}# 我们可以通过base64把它解码出来[root@Docker harbor]# echo YWRtaW46cGFzc3dk | base64 -dadmin:passwd'用户名:密码'
7)再次推送[root@Docker harbor]# docker push 10.0.0.99/kpyun/alpine:3.20.2The push refers to repository [10.0.0.99/kpyun/alpine]c6a83fedfae6: "Pushed"# 这次就推送上去了

8)测试验证'切另一台机器验证!'[root@test ~]# vim /etc/docker/daemon.json{ "insecure-registries": ["10.0.0.99:5000","10.0.0.99"]}[root@test ~]# systemctl restart docker[root@test ~]# docker login 10.0.0.99 -u admin -p passwdLogin Succeeded[root@test ~]# docker pull 10.0.0.99/kpyun/alpine:3.20.2'刚才复制的命令 <-- web页面'[root@test ~]# docker images10.0.0.99/kpyun/alpine 3.20.2
9)密码保护# 在登录的时候,你的密码被保存[root@test ~]# cat /root/.docker/config.json{ "auths": { "10.0.0.99": { "auth": "YWRtaW46cGFzc3dk" } }}⚠️ 容易被盗窃!# 养成习惯,不用的时候,退出登录状态[root@test ~]#docker logout 10.0.0.99Removing login credentials for 10.0.0.99'后接镜像仓库的网址'[root@test ~]# cat /root/.docker/config.json{ "auths": {}}✅️ 现在里面就没有密码信息了镜像仓库迁移
项目背景: 早期的docker registry镜像管理不方便 后续将其迁移到harbor仓库项目步骤: 1.配置仓库 2.新建复制规则 3.启动复制规则 4.设置项目为公开 5.测试验证==================================1)环境准备[root@Docker harbor]# docker run -d --network host --restart=unless-stopped --name c1 -v img-volume:/var/lib/registry registry:3.0.0[root@Docker harbor]# ss -lntup | grep 50004096 *:5000 users:(("registry",pid=76702,fd=6))[root@Docker harbor]# curl localhost:5000/v2/_catalog{"repositories":["base/alpine"]}# 复用的数据卷,所以数据并没有丢'再推几个镜像'[root@Docker harbor]# docker tag nginx:latest 10.0.0.99:5000/base/nginx:latest[root@Docker harbor]# docker tag mysql:8.0.36 10.0.0.99:5000/base/mysql:8.0.36# 打标签,后推送[root@Docker harbor]# docker push 10.0.0.99:5000/base/nginx:latest[root@Docker harbor]# docker push 10.0.0.99:5000/base/mysql:8.0.36[root@Docker harbor]# curl localhost:5000/v2/_catalog{"repositories":["base/alpine","base/mysql","base/nginx"]}
2)harbor配置仓库
- 新建复制规则

- 启动复制规则



- 设置项目为公开



- 测试验证
[root@test ~]# docker login 10.0.0.99 -u admin -p passwd'先去项目中复制命令'[root@test ~]# docker pull 10.0.0.99/base/mysql:8.0.36# 这样更简便Status: Downloaded newer image for 10.0.0.99/base/mysql:8.0.36✅️ 成功拉取镜像主从同步
1)在另一个节点安装harbor'test节点'# 过程省略[root@test /usr/local/harbor]# ./install.sh[root@test /usr/local/harbor]# docker compose up -d[+] Running 10/10[root@test /usr/local/harbor]# vim /etc/docker/daemon.json{"insecure-registries": ["10.0.0.99:5000","10.0.0.128"]}⚠️ 指向自己[root@test /usr/local/harbor]# systemctl restart docker[root@test /usr/local/harbor]# docker compose lsNAME STATUS CONFIG FILESharbor running(9) /usr/local/harbor/docker-compose.yml[root@test /usr/local/harbor]# docker login 10.0.0.128 -u admin -p passwdLogin Succeeded
2)访问测试http://10.0.0.128/
-
主镜像仓库(.99) —> 备用(.128)
-
配置仓库

- 复制规则管理

- 等一分钟 …
- 验证备用仓库是否同步

- ✅️ 成功同步
==🤔疑问==: 如果备用仓库也被创建了项目,会同步至主仓库嘛❓️
- 🌿自然不会 ✅️
- 我们设置的规则是 —> 主同步至从库
- 每分钟 push推送 一次
- 我们设置的规则是 —> 主同步至从库
'在从库创建项目,随便推几个镜像'📌 先在web页面中创建项目# 从库中[root@test /usr/local/harbor]# docker push 10.0.0.128/haha/busybox:latestThe push refers to repository [10.0.0.128/haha/busybox]068f50152bbc: "Pushed"
✅️ '主库这个时候是没有这个项目的!'--> 设置新的"复制规则"# 又来一个
- 等一会主库也有了
基于事件

相比传统的定时触发, 它实现了近实时、主动推送的同步机制
- 目前实验 —> 仅在push推送时可供选择
- pull拉取没有这个选项
| 特性 | 定时复制(旧方式) | 事件驱动复制(新方式) |
|---|---|---|
| 触发机制 | 按固定时间间隔(如每分钟)轮询主库变更 | 主库在发生关键事件时主动通知复制任务(如 push/delete/tag) |
| 延迟 | 最高可达配置间隔(如 1 分钟) | 秒级甚至毫秒级(取决于网络与系统负载) |
| 资源开销 | 周期性扫描,可能重复检查无变更内容 | 仅在真实事件发生时触发,更高效 |
- 修改复制规则
- 主同步至从库
- 每分钟 push推送 一次 —> ==基于事件触发==
- 主同步至从库


- 删除测试


- ==增加镜像测试==
[root@Docker harbor]# docker tag oldboyedu-linux-tools:v0.1 10.0.0.99/kpyun/oldboyedu-linux-tools:v0.1[root@Docker harbor]# docker push 10.0.0.99/kpyun/oldboyedu-linux-tools:v0.1'推送至主库'
# 很快也会同步至从库✅️ 你主库一推,立马同步至从库
高可用

- 把所有的镜像推送至一个地方(NFS)
- 宿主机之间keepalived
- 镜像之间互相同步(pull & push) <— 官方推荐
- 👆就是我们演示的==主从同步==
- 宿主机之间keepalived
1)安装keepalived# 两个节点都安装[root@Docker ~]# dnf -y install keepalived[root@test ~]# yum -y install keepalived
2)修改配置文件[root@Docker ~]# vim /etc/keepalived/keepalived.confglobal_defs { router_id 10.0.0.99}
vrrp_instance VI_1 { interface eth0 virtual_router_id 50 priority 150 advert_int 1
authentication { auth_type PASS auth_pass 1111 }
virtual_ipaddress { 10.0.0.3 }}[root@test ~]# vim /etc/keepalived/keepalived.confglobal_defs { router_id 10.0.0.128}
vrrp_instance VI_1 { interface eth0 virtual_router_id 50 priority 100 advert_int 1
authentication { auth_type PASS auth_pass 1111 }
virtual_ipaddress { 10.0.0.3 }}'虚拟Mac地址就先不开了'# 我这里一个Centos,一个Rocky,虚拟Mac地址显示不出来
3)重启服务[root@Docker ~]# systemctl restart keepalived[root@test ~]# systemctl restart keepalived'10.xxx.99的优先级更高 --> 有虚拟IP'[root@Docker ~]# ip a2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:0c:29:1c:7e:be brd ff:ff:ff:ff:ff:ff altname enp3s0 altname ens160 altname enx000c291c7ebe inet 10.0.0.99/24 brd 10.0.0.255 scope global noprefixroute eth0 valid_lft forever preferred_lft forever inet 10.0.0.3/32 scope global eth0 valid_lft forever preferred_lft forever
4)测试验证http://10.0.0.3/'此时映射到10.xxx.99'
5)推送测试[root@Docker harbor]# docker tag redis:7.2.8 10.0.0.3/kpyun/redis:7.2.8[root@Docker harbor]# vim /etc/docker/daemon.json[root@Docker harbor]# systemctl restart docker[root@Docker harbor]# docker compose down -t 0[root@Docker harbor]# docker compose up -d[root@Docker harbor]# docker login 10.0.0.3 -u admin -p passwd[root@Docker harbor]# docker push 10.0.0.3/kpyun/redis:7.2.8'此时实际是推送至主库中'# 因为有复制规制,也会复制到从库中

6)VIP漂移'关闭 stop 主库的keepalived'[root@Docker harbor]# systemctl stop keepalived.service[root@test /usr/local/harbor]# ip a2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:0c:29:ec:ba:7b brd ff:ff:ff:ff:ff:ff inet 10.0.0.128/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.0.0.3/32 scope global eth0 valid_lft forever preferred_lft forever'漂移至从库中'
7)再次推送测试'因为10.xxx.99里有对应的配置,我们还在那里推送'[root@Docker harbor]# docker tag ubuntu:22.04 10.0.0.3/kpyun/ubuntu:22.04[root@Docker harbor]# docker push 10.0.0.3/kpyun/ubuntu:22.04The push refers to repository [10.0.0.3/kpyun/ubuntu]f63eb04151bc: "Pushed"
8)启动keepalived[root@Docker harbor]# systemctl start keepalived'优先级不同,抢占回来!'inet 10.0.0.99/24 brd 10.0.0.255 valid_lft forever preferred_lft foreverinet 10.0.0.3/32 scope global eth0HTTPS证书配置

1)上传证书[root@Docker harbor]# pwd/usr/local/harbor[root@Docker harbor]# unzip /tmp/24850683_docker.kpyun.fun_nginx.zip -d /usr/local/harbor/Archive: /tmp/24850683_docker.kpyun.fun_nginx.zipAliyun Certificate Download inflating: /usr/local/harbor/docker.kpyun.fun.pem inflating: /usr/local/harbor/docker.kpyun.fun.key[root@Docker harbor]# ls | grep docker.kpyun.docker.kpyun.fun.keydocker.kpyun.fun.pem
2)修改配置文件'主机名和https'[root@Docker harbor]# vim harbor.ymlhostname: docker.kpyun.funhttps: port: 443 certificate: /usr/local/harbor/docker.kpyun.fun.pem private_key: /usr/local/harbor/docker.kpyun.fun.key
3)清理环境&重新安装[root@Docker harbor]# docker compose down -t 0[root@Docker harbor]# ./prepare[root@Docker harbor]# ./install.sh
4)强制走HTTPS[root@Docker harbor]# vim /etc/docker/daemon.json{ "insecure-registries": []}# 都删除掉[root@Docker harbor]# systemctl restart docker[root@Docker harbor]# docker compose down -t 0[root@Docker harbor]# docker compose up -d[root@Docker harbor]# docker login docker.kpyun.fun -u admin -p passwd# 重新登录
5)映射&打标签[root@Docker harbor]# tail -1 /etc/hosts10.0.0.3 docker.kpyun.fun[root@Docker harbor]# docker tag centos:latest docker.kpyun.fun/kpyun/centos:latest[root@Docker harbor]# docker push docker.kpyun.fun/kpyun/centos:latestThe push refers to repository [docker.kpyun.fun/kpyun/centos]174f56854903: "Pushed"
6)Windows映射10.0.0.3 docker.kpyun.fun# 自动跳转 80 --> 443
脚本优化
[root@Docker harbor]# cd ~[root@Docker ~]# vim build.sh#!/bin/bash# 可以是写好的Dockerfile --> 自动build构建# 如果是Dockerfile,在构建的同时,就要打上自己私有仓库的地址!# 自动打标签,自动推送docker tag oldboyedu-games:v0.6 docker.kpyun.fun/kpyun/oldboyedu-games:v0.6docker login -u admin -p passwd docker.kpyun.fundocker push docker.kpyun.fun/kpyun/oldboyedu-games:v0.6docker logout docker.kpyun.fun[root@Docker ~]# sh build.shLogin Succeeded --> 成功登录The push to repository [docker.kpyun.fun/kpyun/oldboyedu-games] --> 推送镜像5dcfac0f2f9c: "Pushed".......Removing login credentials for docker.kpyun.fun --> 退出登录
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
传统业务容器化
Docker容器以RuoYi-Vue为例演示Java项目全流程容器化,涵盖Maven打包、Vue前端与Compose多服务编排部署
2
Docker结课实践考核
Docker容器Docker容器技术结课实践考核,涵盖容器化部署、编排及运维实战
3
Dockerfile详解
Docker容器详解Dockerfile全部核心指令与ENTRYPOINT/CMD配合机制,实战多阶段构建与镜像优化
4
Linux底层特性&&初识Dockerfile
Docker容器手操chroot与OverlayFS分层结构,实践cgroup资源限制与namespace隔离,初识Dockerfile构建
5
数据卷&&网络
Docker容器讲解数据卷挂载方式与docker0网桥原理,掌握四种网络类型及自定义DNS,实战多项目部署
随机文章随机推荐



