单机编排&&私有镜像仓库

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

单机编排&&私有镜像仓库#

[TOC]


docker-compose(单体服务)#

Terminal window
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-compose
docker-compose-plugin-5.1.3-1.el10.x86_64
[root@Docker ~]# docker compose version
Docker 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 default
docker-compose_default bridge local
📌 先创建了个网络
[root@Docker docker-compose]# docker ps
nginx: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 ps
docker-compose: command not found
[root@Docker docker-compose]# docker compose ps
no 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 FILES
docker-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
# 自动创建的容器也被移除了 ✅️

Terminal window
'mysql单体服务'
# 自行清理环境
1)环境准备
[root@Docker ~]# pwd
/root
[root@Docker ~]# rm -rf ./*
[root@Docker ~]# mkdir ./mydb && cd ./mydb
[root@Docker mydb]# docker images | grep mysql
mysql:8.0.36 a53272402242 833MB
2)编写主配置文件
[root@Docker mydb]# vim db_server.yml
services:
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
Terminal window
# 既然我们学完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": {}
}, # 默认创建匿名数据卷
Terminal window
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 ls
NAME STATUS CONFIG FILES
mydb running(1) /root/mydb/db_server.yml
[root@Docker mydb]# docker network ls | grep mydb
a425873c55f1 mydb_default bridge local
[root@Docker mydb]# docker compose -f db_server.yml ps
db01 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 mysql
Welcome to the MySQL monitor.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| wordpress ✅️ |
+--------------------+
5)停止&&移除
mysql> exit
Bye
[root@Docker mydb]# docker compose -f db_server.yml down -t 0
[+] down 2/2
Container db01 Removed
Network mydb_default Removed

数据持久化#

Terminal window
1)准备工作
[root@Docker ~]# rm -rf ./*
[root@Docker ~]# mkdir ./db-volume && cd ./db-volume
2)编写配置文件
[root@Docker db-volume]# vim docker-compose.yml
services:
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 ls
DRIVER VOLUME NAME
local 192fdxxx...
local 5037bxxx...
'后面是一串神秘的字符'
Note

这样分开定义是为了==提供灵活性==

既可以在 compose 内部使用简短的别名,又可以精确控制实际的卷名称

Terminal window
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 ls
local mysql-volume
local web-server
[root@Docker db-volume]# docker compose ps
db02 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 ls
NAME STATUS CONFIG FILES
db-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 ls
local mysql-volume
local 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"

自定义网络#

Terminal window
1)准备
[root@Docker ~]# rm -rf ./*
[root@Docker ~]# mkdir db-network && cd db-network
[root@Docker db-network]# docker network ls
NETWORK ID NAME DRIVER SCOPE
66cc72cc26cd bridge bridge local
bf4d048e4eed host host local
5879c499792c none null local
'现在只有3个默认的网络'
2)配置文件
[root@Docker db-network]# vim docker-compose.yml
services:
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 ls
NETWORK ID NAME DRIVER SCOPE
dc02802cf1a2 my_db bridge local
88fee2060426 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 0

docker-compose(多服务编排)#

wordpress部署#

Terminal window
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.yml
services:
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-volume
Terminal window
3)启动服务
[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 ls
NAME STATUS CONFIG FILES
mul-wordpress running(2) ~/mul-wordpress/docker-compose.yml
[root@Docker mul-wordpress]# docker compose ps
db 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 ls
efece4192527 wordpress-net bridge local
[root@Docker mul-wordpress]# docker volume ls
DRIVER VOLUME NAME
local mysql-volume
local wordpress-volume
4)访问测试
http://10.0.0.99:81/
"停止"
docker compose down -t 0 -v

image-20260502133001606
image-20260502133001606

Zabbix部署#

Terminal window
[root@Docker ~]# rm -rf ./*
[root@Docker ~]# mkdir zabbix-server && cd zabbix-server
[root@Docker zabbix-server]# vim docker-compose.yml
services:
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
Terminal window
[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/

image-20260502145127661
image-20260502145127661

LB负载#

image-20260502145525651
image-20260502145525651

  • 请自定义3个镜像,要求使用alpine作为基础镜像

  • 然后使用docker-compose一键启动

    • 用户访问lb后,轮询方式访问web01和web02
      • 比例为 3:1

🦄 我们使用Dockerfile写三个基础镜像

借鉴之前的笔记

Terminal window
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/lb
FROM alpine:3.20.2
EXPOSE 80
RUN apk update && \
apk add nginx && \
rm -rf /var/cache
COPY ./lb.conf /etc/nginx/http.d/default.conf
CMD ["nginx","-g","daemon off;"]
  • vim ./dockerfile/web01
FROM alpine:3.20.2
EXPOSE 80
RUN apk update && \
apk add nginx && \
rm -rf /var/cache
RUN mkdir /code && \
echo "web01..." > /code/index.html
COPY ./default.conf /etc/nginx/http.d/
CMD ["nginx","-g","daemon off;"]
  • vim ./dockerfile/web02
FROM alpine:3.20.2
EXPOSE 80
RUN apk update && \
apk add nginx && \
rm -rf /var/cache
RUN mkdir /code && \
echo "web02..." > /code/index.html
COPY ./default.conf /etc/nginx/http.d/
CMD ["nginx","-g","daemon off;"]
Terminal window
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 images
my-lb:1.0 3292e8f72107 13.9MB
my-web01:1.0 3b28a35f13c7 13.9MB
my-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
Terminal window
[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/hosts
172.21.0.2 diy.kpyun.com
[root@Docker lb-server]# for i in `seq 10`;do curl diy.kpyun.com;done
web01... ❤️
web01... ❤️
web01... ❤️
web02... 💚
web01... ❤️
web01... ❤️
web01... ❤️
web02... 💚
web01... ❤️
web01... ❤️

镜像仓库#

Terminal window
什么是私有仓库❓️
# 不对全世界开放的镜像仓库
# 一般是公司内部使用的私有镜像仓库
为什么需要私有仓库❓️
1)安全性问题
# 官方镜像仓库大家都可以访问
🌰 若都放在官方,大家都能拿到你们公司的自建镜像
2)访问速度:
🌰 官方的服务器在国外,访问速度慢
==============================
🔖私有仓库:
1)docker registry:
# 轻量级的私有镜像仓库
# 基本上不占用内存,很适合学习环境中使用
✅️ 会对存储的数据进行一定的压缩处理
✅️ 占用内存不足20MB
❌️ 没有提供较好的WebUI
❌️ 维护起来比较麻烦,尤其是删除镜像
2)harbor:
🦄 基于官方的"docker registry"进行二次开发
🦄 是一个适合企业级使用的镜像仓库
🔖第三方仓库: --> 轩辕镜像站(docker.xuanyuan.run)
🔖docker官方仓库: --> hub.docker.com

docker registry#

Terminal window
"清理环境"
[root@Docker ~]# rm -rf ./*
docker rm -f $(docker ps -aq)
docker network prune -f
docker volume prune -fa
1)拉取镜像
[root@Docker ~]# docker pull docker.xuanyuan.run/registry:3.0.0
# 自行改标签
[root@Docker ~]# docker images
registry: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 ls
DRIVER VOLUME NAME
local 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

image-20260502184135544
image-20260502184135544

Terminal window
[root@Docker ~]# curl http://10.0.0.99:5000/v2/_catalog
{"repositories":[]}
# 这个仓库没有任何的数据

推送镜像#

Terminal window
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-stopped
registry: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.2
The 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.2
Error 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.2
3.20.2: Pulling from base/alpine
Digest: sha256:eddxxx... --> 签名✍️
Status: Downloaded newer image for 10.0.0.99:5000/base/alpine:3.20.2
👆 镜像地址
'成功拉取'
[root@test ~]# docker images
10.0.0.99:5000/base/alpine 3.20.2

删除镜像#

Terminal window
[root@Docker ~]# hostname -I
10.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 # ls
blobs repositories
# 主要就是它俩

Docker Registry ==存储结构==:

/var/lib/registry/docker/registry/v2/ 目录包含:

  1. blobs/ 目录
    • 存放实际镜像层数据(layers)
    • 文件以 SHA256 哈希值命名
    • 包含镜像的所有层数据
  2. repositories/ 目录
    • 存放仓库元数据
    • 包含标签、清单等信息
Terminal window
/var/lib/registry/docker/registry/v2 # du -sh ./*
3.5M ./blobs
20.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 ./blobs
0 ./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 ./blobs
0 ./repositories
"这下子就都干净了!"

bug解决#

Terminal window
"描述:"
🏷️ 已经推送的镜像无法再次推送(需重启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 ./blobs
12.0K ./repositories
'切回去看容器内部数据'
# 只有元数据,没有镜像数据
Terminal window
"解决方案"
🦄 重启docker-registries容器即可
[root@Docker ~]# docker restart c1
'再次推送'
[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: "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 ./blobs
20.0K ./repositories
✅️ '一切都回来了'
[root@Docker ~]# docker pull 10.0.0.99:5000/base/alpine:3.20.2
✅️ '拉取自己的镜像仓库'
3.20.2: Pulling from base/alpine
Digest: sha256:eddxxx
Status: Downloaded newer image for 10.0.0.99:5000/base/alpine:3.20.2
[root@Docker ~]# docker images
10.0.0.99:5000/base/alpine:3.20.2 eddxxx 11.7MB

harbor#

Harbor 是 VMware 公司开源的==企业级镜像仓库==,主要特点如下:

  • 提供安全、可靠的私有镜像存储和分发

  • 底层使用 Docker Compose 来管理 Harbor 服务

  • 提供图形化管理界面(Web UI)

GitHub 地址:https://github.com/goharbor/harbor

  • 离线安装
    • 这里==建议用v2.14版本==
    • 复制标签没有bug

image-20260505151651362
image-20260505151651362

image-20260505153433633
image-20260505153433633

Terminal window
1)上传解压
[root@Docker ~]# cd /tmp
[root@Docker tmp]# ls
harbor-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]# ls
common.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.yml
hostname: 10.0.0.99
http:
port: 80
# 后面再启用HTTPS
harbor_admin_password: passwd
# 修改登录密码
database:
password: root123
max_idle_conns: 100
max_open_conns: 900
conn_max_lifetime: 5m
conn_max_idle_time: 0
data_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: 5m0s
jobservice:
max_job_workers: 10
max_job_duration_hours: 24
job_loggers:
- STD_OUTPUT
- FILE
logger_sweeper_duration: 1
notification:
webhook_job_max_retry: 3
webhook_job_http_client_timeout: 3
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 2.15.0
proxy:
http_proxy:
https_proxy:
no_proxy:
components:
- core
- jobservice
- trivy
upload_purging:
enabled: true
age: 168h
interval: 24h
dryrun: false
cache:
enabled: false
expire_hours: 24
Terminal window
3)安装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 ls
NAME STATUS CONFIG FILES
harbor running(9) /usr/local/harbor/docker-compose.yml
4)测试验证
http://10.0.0.99/
✅️用户名: admin
✅️密码: passwd

image-20260505131440522
image-20260505131440522

新建项目#

image-20260505134651161
image-20260505134651161

image-20260505135839503
image-20260505135839503

Terminal window
'推送命令'
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.2
dial 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 -a
Exited (128)
........
Up
Exited (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.2
authorization 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 -d
admin:passwd
'用户名:密码'
7)再次推送
[root@Docker harbor]# docker push 10.0.0.99/kpyun/alpine:3.20.2
The push refers to repository [10.0.0.99/kpyun/alpine]
c6a83fedfae6: "Pushed"
# 这次就推送上去了

image-20260505153927312
image-20260505153927312

image-20260505154101909
image-20260505154101909

Terminal window
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 passwd
Login Succeeded
[root@test ~]# docker pull 10.0.0.99/kpyun/alpine:3.20.2
'刚才复制的命令 <-- web页面'
[root@test ~]# docker images
10.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.99
Removing login credentials for 10.0.0.99
'后接镜像仓库的网址'
[root@test ~]# cat /root/.docker/config.json
{
"auths": {}
}
✅️ 现在里面就没有密码信息了

镜像仓库迁移#

Terminal window
项目背景:
早期的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 5000
4096 *: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配置仓库

image-20260505165335583
image-20260505165335583


  • 新建复制规则

image-20260505165700650
image-20260505165700650


  • 启动复制规则

image-20260505165827155
image-20260505165827155

image-20260505165912514
image-20260505165912514

image-20260505165949981
image-20260505165949981


  • 设置项目为公开

image-20260505170339223
image-20260505170339223

image-20260505170355253
image-20260505170355253

image-20260505170640542
image-20260505170640542


  • 测试验证
Terminal window
[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
✅️ 成功拉取

镜像主从同步#

Terminal window
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 ls
NAME STATUS CONFIG FILES
harbor running(9) /usr/local/harbor/docker-compose.yml
[root@test /usr/local/harbor]# docker login 10.0.0.128 -u admin -p passwd
Login Succeeded
2)访问测试
http://10.0.0.128/

image-20260505181505602
image-20260505181505602


  • 主镜像仓库(.99) —> 备用(.128)

  • 配置仓库

image-20260505182126701
image-20260505182126701


  • 复制规则管理

image-20260505182437700
image-20260505182437700

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

image-20260505182559478
image-20260505182559478

  • ✅️ 成功同步

==🤔疑问==: 如果备用仓库也被创建了项目,会同步至主仓库嘛❓️

  • 🌿自然不会 ✅️
    • 我们设置的规则是 —> 同步至从库
      • 每分钟 push推送 一次
Terminal window
'在从库创建项目,随便推几个镜像'
📌 先在web页面中创建项目
# 从库中
[root@test /usr/local/harbor]# docker push 10.0.0.128/haha/busybox:latest
The push refers to repository [10.0.0.128/haha/busybox]
068f50152bbc: "Pushed"
✅️ '主库这个时候是没有这个项目的!'
--> 设置新的"复制规则"
# 又来一个

image-20260505184648849
image-20260505184648849

  • 等一会主库也有了

基于事件#

image-20260505225504702
image-20260505225504702

相比传统的定时触发, 它实现了近实时、主动推送的同步机制

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

image-20260505230133889
image-20260505230133889

image-20260505230237052
image-20260505230237052


  • 删除测试

image-20260505230330452
image-20260505230330452

image-20260505230456087
image-20260505230456087


  • ==增加镜像测试==
Terminal window
[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
'推送至主库'
# 很快也会同步至从库
✅️ 你主库一推,立马同步至从库

image-20260505230957620
image-20260505230957620

高可用#

image-20260505231558402
image-20260505231558402

  1. 把所有的镜像推送至一个地方(NFS)
    1. 宿主机之间keepalived
  2. 镜像之间互相同步(pull & push) <— 官方推荐
    1. 👆就是我们演示的==主从同步==
    2. 宿主机之间keepalived
Terminal window
1)安装keepalived
# 两个节点都安装
[root@Docker ~]# dnf -y install keepalived
[root@test ~]# yum -y install keepalived
2)修改配置文件
[root@Docker ~]# vim /etc/keepalived/keepalived.conf
global_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.conf
global_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 a
2: 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'

image-20260506084442187
image-20260506084442187

Terminal window
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
'此时实际是推送至主库中'
# 因为有复制规制,也会复制到从库中

image-20260506085835890
image-20260506085835890

image-20260506090224371
image-20260506090224371

Terminal window
6)VIP漂移
'关闭 stop 主库的keepalived'
[root@Docker harbor]# systemctl stop keepalived.service
[root@test /usr/local/harbor]# ip a
2: 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
'漂移至从库中'

image-20260506090158116
image-20260506090158116

Terminal window
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.04
The push refers to repository [10.0.0.3/kpyun/ubuntu]
f63eb04151bc: "Pushed"

image-20260506091008711
image-20260506091008711

Terminal window
8)启动keepalived
[root@Docker harbor]# systemctl start keepalived
'优先级不同,抢占回来!'
inet 10.0.0.99/24 brd 10.0.0.255
valid_lft forever preferred_lft forever
inet 10.0.0.3/32 scope global eth0

HTTPS证书配置#

image-20260506103218333
image-20260506103218333

Terminal window
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.zip
Aliyun 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.key
docker.kpyun.fun.pem
2)修改配置文件
'主机名和https'
[root@Docker harbor]# vim harbor.yml
hostname: docker.kpyun.fun
https:
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/hosts
10.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:latest
The push refers to repository [docker.kpyun.fun/kpyun/centos]
174f56854903: "Pushed"
6)Windows映射
10.0.0.3 docker.kpyun.fun
# 自动跳转 80 --> 443

image-20260506105148524
image-20260506105148524

脚本优化#

[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.6
docker login -u admin -p passwd docker.kpyun.fun
docker push docker.kpyun.fun/kpyun/oldboyedu-games:v0.6
docker logout docker.kpyun.fun
[root@Docker ~]# sh build.sh
Login Succeeded --> 成功登录
The push to repository [docker.kpyun.fun/kpyun/oldboyedu-games] --> 推送镜像
5dcfac0f2f9c: "Pushed"
.......
Removing login credentials for docker.kpyun.fun --> 退出登录

image-20260506110828895
image-20260506110828895

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

单机编排&&私有镜像仓库
https://www.kpyun.fun/posts/docker/docker06/
作者
久棹
发布于
2026-02-27
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录