Chemmy's Blog

chengming0916@outlook.com

一、核心定位

本文作为GitOps环境搭建系列的第三篇,聚焦CoreDNS内网域名解析的配置与优化。CoreDNS是K3s集群默认集成的DNS服务器,负责处理集群内部的域名解析(如Service域名、Pod域名等)。

在GitOps环境中,CoreDNS扮演”域名解析中枢”角色,为所有组件(Traefik、Gitea、ArgoCD、Tekton、Harbor等)提供统一的内网域名解析服务。通过配置自定义域名映射,可以实现通过易记的域名访问各组件,替代复杂的IP地址访问方式,提升运维效率和可维护性。

二、部署前置检查

部署前需验证K3s集群状态及CoreDNS基础运行情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 验证K3s集群状态
kubectl get nodes

# 2. 验证CoreDNS是否已运行(K3s默认集成)
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 3. 查看CoreDNS Service
kubectl get svc -n kube-system kube-dns

# 4. 测试默认DNS解析功能
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes.default

# 5. 验证内网IP可达性(替换为实际IP)
ping -c 3 192.168.1.100

前置条件检查清单:

  • K3s集群运行正常
  • CoreDNS Pod处于Running状态
  • 内网IP地址可达且稳定
  • 已规划好内网域名体系(统一使用example.io)
  • 具备kube-system命名空间操作权限

三、持久化配置CoreDNS

K3s启动时会自动部署CoreDNS组件,但直接修改CoreDNS配置文件(如编辑ConfigMap或修改/var/lib/rancher/k3s/server/manifests/coredns.yaml)存在明显缺陷——K3s重启、升级时会自动初始化CoreDNS配置,所有手动修改的内容会被覆盖。因此,需采用K3s官方推荐的coredns-custom ConfigMap持久化配置方案。

3.1 创建coredns-custom ConfigMap

创建coredns-custom.yaml配置文件,定义内网域名解析规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# coredns-custom.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns-custom
namespace: kube-system
data:
# 可选配置:开启CoreDNS解析日志,便于调试
log.override: |
log
# 自定义内网域名解析规则(CoreDNS会自动加载后缀为.server的配置片段)
gitops.server: |
example.io {
errors # 输出域名解析错误日志
cache 30 # 解析结果缓存30秒
hosts {
# GitOps组件域名映射(替换为实际IP地址)
192.168.1.100 traefik.example.io # Traefik反向代理
192.168.1.101 harbor.example.io # Harbor镜像仓库
192.168.1.102 gitea.example.io # Gitea代码仓库
192.168.1.103 tekton.example.io # Tekton CI流水线
192.168.1.104 argocd.example.io # ArgoCD GitOps核心
fallthrough # 无匹配域名时转发至下一级解析器
}
prometheus :9153 # 开启Prometheus监控
forward . /etc/resolv.conf # 非内网域名转发至宿主机DNS
loop # 防止解析环路
reload # 配置变更自动重载
loadbalance # 开启负载均衡
}

关键配置详解:

  • gitops.server:CoreDNS约定,后缀为.server的配置片段会被自动加载
  • example.io:内网根域名,所有GitOps组件域名基于此配置
  • hosts段:核心的域名-IP映射区域,按实际网络环境配置
  • fallthrough:当hosts中无匹配域名时,转发至forward指定的解析器
  • forward . /etc/resolv.conf:非内网域名转发至宿主机DNS

3.2 应用ConfigMap配置

1
2
3
4
5
# 应用CoreDNS自定义配置
kubectl apply -f coredns-custom.yaml

# 验证ConfigMap创建
kubectl get configmap coredns-custom -n kube-system -o yaml

3.3 重启CoreDNS使配置生效

1
2
3
4
5
6
7
8
# 重启CoreDNS Pod加载新配置
kubectl delete pods -n kube-system -l k8s-app=kube-dns

# 监控Pod重启过程
kubectl get pods -n kube-system -l k8s-app=kube-dns -w

# 验证CoreDNS运行状态
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=20

四、验证内网DNS解析

4.1 创建测试环境

1
2
3
4
5
# 创建测试Pod
kubectl create deploy dns-test --image=busybox:1.28 --replicas=1 -- sleep 3600

# 等待Pod启动
kubectl get pods -l app=dns-test -w

4.2 执行解析测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 进入测试Pod
kubectl exec -it $(kubectl get pod -l app=dns-test -o jsonpath='{.items[0].metadata.name}') -- /bin/sh

# 容器内执行解析测试
# 1. 测试GitOps组件域名解析
nslookup traefik.example.io
nslookup harbor.example.io
nslookup gitea.example.io
nslookup tekton.example.io
nslookup argocd.example.io

# 2. 测试ping连通性
ping -c 3 traefik.example.io
ping -c 3 harbor.example.io

# 3. 测试外网域名解析(验证forward功能)
nslookup google.com
nslookup github.com

# 退出容器
exit

4.3 验证解析结果

解析结果应显示对应的IP地址:

  • traefik.example.io192.168.1.100
  • harbor.example.io192.168.1.101
  • gitea.example.io192.168.1.102
  • 外网域名应正常解析

4.4 清理测试资源

1
2
# 清理测试Pod
kubectl delete deploy dns-test

五、进阶配置:暴露CoreDNS供集群外访问

若需让K3s集群外的设备(如开发机、其他服务器)使用CoreDNS解析内网域名,可通过Traefik暴露CoreDNS的UDP 53端口。

5.1 配置Traefik UDP入口点

首先确保Traefik已启用UDP支持,编辑Traefik配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在Traefik HelmChartConfig中添加UDP入口点
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
dns-udp:
port: 53
expose: true
exposedPort: 53
protocol: UDP

5.2 创建IngressRouteUDP规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# coredns-external.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteUDP
metadata:
name: coredns-external
namespace: kube-system
spec:
entryPoints:
- dns-udp
routes:
- match: HostSNI(`*`)
services:
- name: kube-dns
port: 53

应用配置:

1
kubectl apply -f coredns-external.yaml

5.3 集群外设备配置

在集群外设备上配置DNS服务器:

1
2
3
4
5
6
# Linux系统
sudo echo "nameserver <K3s节点IP>" > /etc/resolv.conf

# 或编辑/etc/resolv.conf
# nameserver <K3s节点IP>
# search example.io

六、生产环境配置建议

6.1 高可用配置

1
2
3
4
5
# 配置多个DNS服务器
forward . 8.8.8.8 8.8.4.4 /etc/resolv.conf {
max_concurrent 1000 # 最大并发查询数
expire 10s # 连接过期时间
}

6.2 性能优化

1
2
3
4
5
6
7
# 调整缓存和性能参数
cache {
success 9984 3600 # 成功响应缓存
denial 9984 30 # 否定响应缓存
prefetch 10 60s # 预取设置
}
ready :8181 # 就绪检查端点

6.3 安全配置

1
2
3
4
5
# 限制访问范围
acl {
allow net 192.168.1.0/24 # 只允许内网访问
block
}

七、常见问题修复

问题现象 排查方向 修复方案
域名解析失败 CoreDNS配置/网络 检查coredns-custom ConfigMap,验证网络连通性
解析结果不正确 hosts映射错误 检查IP地址是否正确,确认网络可达
CoreDNS Pod重启失败 配置语法错误 检查CoreDNS日志:kubectl logs -n kube-system <coredns-pod>
外网域名无法解析 forward配置 检查/etc/resolv.conf内容,测试外网连通性
配置修改不生效 未重启CoreDNS 重启CoreDNS Pod:kubectl delete pods -n kube-system -l k8s-app=kube-dns

八、配置参考

所有CoreDNS配置文件和部署脚本请参考:
https://gitee.com/Chemmy/kube-template/tree/master/devops/coredns

该目录包含:

  • CoreDNS自定义配置模板
  • 生产环境优化配置
  • 外部访问配置示例
  • 监控和日志配置

总结

本文完成了CoreDNS在K3s集群中的持久化配置,实现了GitOps组件内网域名解析功能。通过coredns-custom ConfigMap方案,确保配置在K3s重启、升级后不丢失,保障域名解析服务的稳定性。

配置完成后,所有GitOps组件(Traefik、Gitea、ArgoCD、Tekton、Harbor)均可通过统一的example.io域名访问,极大简化了运维操作。下一篇文章将部署cert-manager证书管理,为所有组件配置HTTPS安全访问。

Docker Registry是Docker官方推出的轻量级私有镜像仓库解决方案,相较于Harbor等可视化工具,它具备部署简单、资源占用低的优势,非常适合中小规模容器环境的镜像管理需求。本文将从实际运维场景出发,详细拆解Registry的基础部署、HTTP/HTTPS访问配置、镜像推送拉取、缓存加速及安全认证全流程,精准解决私有仓库部署中的核心痛点,助力开发者快速搭建可用的私有镜像仓库。

一、核心问题:Docker访问Registry的HTTPS限制

Docker客户端默认强制采用HTTPS协议访问Registry,若私有仓库未配置SSL证书、仅支持HTTP访问,会触发经典报错:

1
Get https://192.168.0.110:5000/v1/_ping: http: server gave HTTP response to HTTPS client

该问题的核心原因的是:Docker客户端默认向Registry发起HTTPS请求,但未配置SSL的Registry仅能返回HTTP响应,导致通信链路中断。针对此问题,我们提供两种解决方案,分别适配测试/内网和生产环境。

方案A:临时放宽HTTP限制(测试/内网环境)

通过修改Docker启动参数,允许指定私有仓库的HTTP访问,配置简单高效,适合内网测试场景(生产环境不推荐,存在安全风险)。具体步骤如下:

  1. 编辑Docker服务配置文件,添加HTTP访问信任参数:
1
2
3
vim /usr/lib/systemd/system/docker.service
# 在ExecStart行末尾添加--insecure-registry参数,指定私有仓库IP和端口
ExecStart=/usr/bin/dockerd --insecure-registry=192.168.0.110:5000
  1. 重启Docker服务,使配置生效:
1
2
systemctl daemon-reload
systemctl restart docker.service

配置完成后,执行docker pull 192.168.0.110:5000/panda/mysql:v1即可正常拉取私有仓库镜像。

方案B:配置HTTPS加密访问(生产环境)

生产环境需保障镜像传输安全,必须通过SSL证书实现HTTPS加密访问,具体步骤如下:

1. 准备SSL证书

需提前准备CA根证书(CA_Cert.pem)、服务端证书(my.crt)及私钥(myprivate.key),证书绑定的域名需与Registry访问域名一致(如www.my.com),同时在客户端`/etc/hosts`中配置域名与Registry服务器IP的映射关系,避免域名解析失败。

1
2
3
4
5
# 示例:证书文件存放目录及文件列表
ls -l /root/cert_test/
# -rw-------. 1 root root 1359 CA_Cert.pem # CA根证书(客户端需导入信任)
# -rw-------. 1 root root 4509 my.crt # Registry服务端证书
# -rw-------. 1 root root 1679 myprivate.key # 证书私钥

2. 启动带HTTPS的Registry容器

通过环境变量指定证书和私钥路径,将证书目录挂载到容器内部,确保Registry能正常读取证书:

1
2
3
4
5
6
7
docker run -d \
-v /var/my_registry/:/var/lib/registry \ # 镜像数据持久化到宿主机
-v /root/cert_test/:/etc/cert.d \ # 挂载证书目录
-e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/cert.d/my.crt \ # 服务端证书路径
-e REGISTRY_HTTP_TLS_KEY=/etc/cert.d/myprivate.key \ # 证书私钥路径
-p 5000:5000 \
my_registry # 自定义Registry镜像(也可使用官方registry镜像)

3. 客户端信任CA证书

以CentOS系统为例,将CA根证书导入系统信任列表,确保客户端能正常识别HTTPS证书:

1
2
cp CA_Cert.pem /etc/pki/ca-trust/source/anchors/
update-ca-trust

验证HTTPS访问有效性:

1
2
curl -I https://www.my.com:5000/  # 返回200 OK即表示HTTPS配置成功
docker pull www.my.com:5000/panda/my_registry # 可正常拉取镜像

二、Registry基础部署与镜像管理

1. 基础部署(无认证)

快速部署无认证的Registry,适合内网临时测试,核心是拉取官方镜像、启动容器并实现数据持久化:

1
2
3
4
5
6
7
8
9
# 拉取Docker官方Registry镜像
docker pull registry

# 启动Registry容器,配置端口映射和数据挂载
docker run -d -p 5000:5000 \
--restart=always \
--name="registry" \
-v /opt/registry:/var/lib/registry \
registry
  • --restart=always:配置容器随Docker服务自动启动,也可在/etc/docker/daemon.json中添加"live-restore": true实现全局自动恢复;

  • /var/lib/registry:Registry默认的镜像存储路径,挂载到宿主机可避免容器删除后镜像数据丢失。

2. 客户端配置私有仓库信任

客户端需配置私有仓库信任,才能正常与Registry通信,编辑/etc/docker/daemon.json文件:

1
2
3
4
{
"registry-mirrors": ["https://阿里云加速地址"], # 可选配置,加速官方镜像拉取
"insecure-registries": ["10.4.7.7:5000"] # 信任私有仓库的HTTP访问
}

保存配置后,重启Docker服务(systemctl restart docker),客户端即可正常识别私有仓库。

3. 镜像推送与拉取

(1)镜像打标签(核心步骤)

Docker镜像推送至私有仓库前,必须按指定格式打标签,格式为:仓库IP:端口/自定义路径/镜像名:标签,否则无法正常推送:

1
2
# 示例:将本地centos:6.9镜像打标签,适配私有仓库格式
docker tag centos:6.9 10.4.7.7:5000/jerry/centos:v6.9

(2)推送镜像到私有仓库

1
docker push 10.4.7.7:5000/jerry/centos:v6.9

(3)拉取私有仓库镜像

1
docker pull 10.4.7.7:5000/jerry/centos:v6.9

(4)仓库镜像查询(无原生search命令)

原生Registry不支持docker search命令,需通过REST API查询镜像信息,常用查询命令如下:

1
2
3
4
5
# 查看私有仓库中所有镜像仓库
curl -XGET http://10.4.7.7:5000/v2/_catalog # 返回{"repositories":["jerry/centos"]}

# 查看指定镜像的所有标签
curl -XGET http://10.4.7.7:5000/v2/jerry/centos/tags/list # 返回{"name":"jerry/centos","tags":["v6.9"]}

三、Registry缓存配置:代理官方仓库

对于内网多台主机使用容器的场景,配置Registry缓存官方镜像,可实现“一次拉取、本地缓存、多次复用”,大幅提升镜像拉取速度,减少外网带宽消耗。

1. 修改Registry配置文件

创建config-example.yml配置文件,添加代理配置,指向Docker官方仓库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
proxy:
remoteurl: https://registry-1.docker.io # 代理Docker官方仓库,实现镜像缓存

2. 构建自定义Registry镜像

1
docker build -t docker-registry:v0.1 .

3. 启动缓存仓库

挂载配置文件和数据目录,启动缓存版Registry容器:

1
2
3
4
5
6
docker run -d -p 5000:5000 \
--restart=always \
--name docker-registry \
-v $(pwd)/config-example.yml:/etc/docker/registry/config.yml \
-v /home/registry:/var/lib/registry \
docker-registry:v0.1

4. 客户端配置镜像加速

修改客户端/etc/docker/daemon.json,将私有仓库设为镜像源,实现官方镜像缓存拉取:

1
2
3
{
"registry-mirrors":["http://10.4.7.7:5000"]
}

重启Docker服务后,客户端拉取官方镜像(如docker pull node:8.4.0-onbuild)时,Registry会自动从官方仓库拉取并缓存,后续拉取相同镜像时,直接从本地缓存返回,速度大幅提升。

四、安全加固:添加用户名密码认证

默认部署的Registry无任何认证机制,内网所有用户均可自由推送、拉取甚至删除镜像,存在极大安全风险。通过htpasswd配置HTTP基本认证,可实现用户名密码校验,提升仓库安全性。

1. 生成密码文件

安装httpd-tools工具,生成用户名密码文件,用于Registry认证校验:

1
2
3
4
5
6
7
8
9
10
11
# 安装htpasswd工具(CentOS系统)
yum install httpd-tools -y

# 创建认证文件存储目录
mkdir /opt/registry-auth -p

# 生成单用户(用户名为oldguo,密码为123,-B表示加密存储)
htpasswd -Bbn oldguo 123 > /opt/registry-auth/htpasswd

# 追加多用户(可选,使用>>避免覆盖原有用户)
htpasswd -Bbn newuser newpass >> /opt/registry-auth/htpasswd

2. 启动带认证的Registry容器

挂载密码文件目录,通过环境变量指定认证方式和密码文件路径,启动带认证的Registry:

1
2
3
4
5
6
7
8
docker run -d -p 5000:5000 \
-v /opt/registry-auth/:/auth/ \ # 挂载密码文件目录
-v /opt/registry:/var/lib/registry \ # 镜像数据持久化
--name register-auth \
-e "REGISTRY_AUTH=htpasswd" \ # 指定认证方式为htpasswd
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ # 认证域(自定义描述)
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \ # 密码文件路径
registry

3. 客户端认证访问

配置认证后,客户端推送、拉取镜像前必须先登录私有仓库,输入正确的用户名和密码:

1
2
docker login 10.4.7.7:5000  # 执行后输入用户名oldguo、密码123
docker push 10.4.7.7:5000/jerry/centos:v6.9 # 登录成功后可正常推送

五、常见问题解答

1. 配置缓存后能否正常下载官方镜像?

可以。Registry的proxy配置会自动代理官方仓库,客户端拉取官方镜像时,Registry会先检查本地是否有缓存:有缓存则直接返回,无缓存则从官方仓库拉取并缓存,不影响正常使用。

2. 能否直接执行pull centos:6.9,省略私有仓库前缀?

不能。Docker默认优先从Docker Hub拉取镜像,原生Registry不支持省略仓库前缀的拉取方式。若需实现该功能,可替换为Harbor等增强型仓库工具,或手动修改镜像标签为短名称(不推荐,易造成镜像混淆)。

3. 执行docker search查询私有仓库镜像失败,如何解决?

原生Registry未实现docker search的API兼容,无法直接通过该命令查询。可通过REST API查询(如curl -XGET http://10.4.7.7:5000/v2/_catalog);若需可视化搜索、镜像管理功能,建议替换为Harbor(基于Registry开发,功能更完善)。

六、总结

Docker Registry作为轻量级私有镜像仓库,是中小规模容器环境的优选方案,核心优势在于部署简单、资源占用低、可灵活扩展。本文梳理的核心要点的如下:

  • 测试/内网环境:优先采用--insecure-registry配置,快速开启HTTP访问,提升部署效率;

  • 生产环境:必须配置HTTPS加密访问+用户名密码认证,双重保障镜像传输和存储安全;

  • 性能优化:通过配置镜像缓存代理,减少外网依赖,提升内网镜像拉取速度,降低带宽消耗;

  • 镜像管理:严格遵循“仓库IP:端口/路径/镜像名:标签”的标签格式,通过REST API查询镜像信息。

通过本文的步骤配置,可快速搭建一个安全、高效的Docker私有镜像仓库,满足企业内网容器镜像的存储、管理和分发需求,为容器化部署提供可靠的镜像支撑。

KubeEdge中的数据结构设计

Device

字段 类型 说明
ID string 设备唯一编码
Name string 设备名称
Description string 设别描述
State string 设备状态
LastOnline DateTime 最后在线时间
Attributes Map<string,MsgAttr> 设备属性(上报属性)
Twin Map<string,MsgTwin> 设备孪生属性(可控制属性)

MsgAttr

字段 类型 说明
Value string 属性名称
Optional bool 是否可为空
Metadata TypeMetadata 属性类型元数据

MsgTwin

字段 类型 说明
Expected TwinValue 期望值
Actual TwinValue 实际值
Optional bool 是否可为空
Metadata TypeMetadata 属性类型元数据
ExpectedVersion TwinVersion 期望值版本
ActualVersion TwinVersion 实际值版本

数据库表设计

Device

字段 类型 说明
ID 设备实例唯一ID
Name 设备实例名称
Description 设备描述
State 设备状态
LastOnline 最后在线时间

DeviceAttr

字段 类型 说明
ID 属性实例唯一ID
DeviceId 设备实例唯一ID
Name 设备名称
Description 设备描述
Value 设备属性值
Optional bool 是否可空
AttrType 属性类型
Metadata 属性元数据

DeviceTwin

字段 类型 说明
ID
DeviceID
Name
Description
Expected
Actual
ExpectedMeta
ActualMeta
ExpectedVersion
ActualVersion
Optional
AttrType
Metadata

DEVICE

字段 类型 说明
ID int 自增ID
SN varchar(20) 设备唯一编码
NAME varchar(20) 设备名称
MARKED BOOL 设备是否标记
IP varchar(15) 设备IP地址
LOCATION varchar(200) 设备安装位置

DEVICE_ATTR

字段 类型 说明
ID int 自增ID
KEY varchar(20) 属性名
CHANNEL
VALUE int 属性值
DEVICE_ID int 属性所属设备ID
SCALE int 缩放倍率,当数值有小数时可用倍率缩放
UNIT varchar(20) 数值单位

DEVICE_STATE

字段 类型 说明
ID int 自增ID
DEVICE_ID int 属性所属设备ID
PORT int 设备接收端口
VALUE int 数值
UNIT varchar(20) 数值单位

DEVICE_LINKAGE

字段 类型 说明
ID int 自增ID
CAT
DEVICE_ID int 属性所属设备ID
PORT int 设备接收端口
TARGET 联动目标
TRIGGER 联动触发器
TRIGGER_ALARM 联动触发告警
ACTION 联动动作
PARAM 参数

DEVICE_ALARM

字段 类型 说明
ID 自增ID
APP_ID 固件ID
CAT
REPORTER
PORT 端口
CODE 编码
MSG 消息
ALARM_TYPE 告警类型
SEVERITY
STATUS 状态
0%