Chemmy's Blog

chengming0916@outlook.com

一、 架构概述与设计目标

1.1 设计目标
  • **高可用 (HA)**:通过 Keepalived 实现 NFS 服务的 VIP (Virtual IP) 漂移,当主节点故障时,备用节点自动接管服务,客户端无感知。
  • 数据同步:通过 Rsync + Inotify 实现主备节点间共享数据的实时单向同步,确保备用节点上的数据与主节点一致。
  • 服务监控:Keepalived 监控 NFS 服务进程,异常时尝试重启,重启失败则主动放弃 VIP,触发故障转移。
1.2 核心组件与架构
  • NFS Server (主/备):提供实际的共享存储服务。
  • Keepalived:提供 VIP (172.16.60.244) 并监控 NFS 服务健康状态。
  • Rsync + Inotify:实现主备节点 /data/k8s_storage 目录的数据同步。
  • **客户端 (K8s Nodes)**:通过 VIP 挂载 NFS,不感知后端物理服务器切换。

架构示意图

二、 环境准备

2.1 服务器规划
角色 主机名 IP 地址 备注
NFS Master nfs-master 172.16.60.235 初始 VIP 持有者
NFS Slave nfs-slave 172.16.60.236 备用节点
虚拟 IP (VIP) - 172.16.60.244 供 K8s 集群挂载的地址

技术要求

  • 两台 NFS 节点服务器配置应尽可能一致。
  • 建议为 NFS 共享目录 (/data/k8s_storage) 使用独立的硬盘或分区。
2.2 基础系统配置

在两台节点服务器上执行:

1
2
3
4
5
6
7
# 1. 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 2. 关闭 SELinux (需重启生效)
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0

三、 部署 NFS 服务 (主备节点相同操作)

3.1 安装与配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 安装 NFS 软件包
yum install -y nfs-utils rpcbind

# 2. 创建共享目录
mkdir -p /data/k8s_storage

# 3. 配置 NFS 导出 (`/etc/exports`)
# 允许 K8s 节点网段 (172.16.60.0/24) 挂载
echo "/data/k8s_storage 172.16.60.0/24(rw,sync,no_root_squash)" > /etc/exports

# 4. 使配置生效
exportfs -arv

# 5. 启动并设置开机自启
systemctl enable --now rpcbind nfs-server
3.2 验证 NFS 服务
1
2
3
4
5
6
7
8
# 查看本机 NFS 导出列表
showmount -e localhost
# 输出应类似:/data/k8s_storage 172.16.60.0/24

# 在 K8s 节点上测试手动挂载 (可选)
mount -t nfs 172.16.60.235:/data/k8s_storage /mnt
df -h | grep k8s_storage
umount /mnt

四、 配置 Keepalived 实现高可用

核心要点:配置为**非抢占模式 (nopreempt)**,避免 VIP 在节点恢复后频繁来回切换,可能导致数据不一致。

4.1 安装 Keepalived

在两台节点上执行:

1
yum install -y keepalived
4.2 配置 Keepalived (主备差异)
  • Master 节点 (/etc/keepalived/keepalived.conf):
    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
    ! Configuration File for keepalived
    global_defs {
    router_id nfs_master
    }
    vrrp_script chk_nfs {
    script "/etc/keepalived/nfs_check.sh"
    interval 2
    weight -20
    }
    vrrp_instance VI_1 {
    state BACKUP # 初始状态都设为 BACKUP
    interface eth0
    virtual_router_id 51
    priority 100 # Master 优先级更高
    advert_int 1
    nopreempt # 关键:非抢占模式
    authentication {
    auth_type PASS
    auth_pass 1111
    }
    track_script {
    chk_nfs
    }
    virtual_ipaddress {
    172.16.60.244/24
    }
    }
  • Slave 节点:配置文件与 Master 几乎相同,仅需修改两处:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    global_defs {
    router_id nfs_slave # 修改 router_id
    }
    ...
    vrrp_instance VI_1 {
    ...
    priority 80 # 降低优先级
    ...
    }
4.3 创建 NFS 健康检查脚本

在两台节点上创建 /etc/keepalived/nfs_check.sh

1
2
3
4
5
6
7
8
9
#!/bin/bash
A=`ps -C nfsd --no-header | wc -l`
if [ $A -eq 0 ]; then
systemctl restart nfs-server.service
sleep 2
if [ `ps -C nfsd --no-header | wc -l` -eq 0 ]; then
pkill keepalived # 如果重启失败,杀死 keepalived 触发 VIP 转移
fi
fi

赋予执行权限:chmod +x /etc/keepalived/nfs_check.sh

4.4 启动与验证 Keepalived
1
2
3
4
5
6
7
8
systemctl enable --now keepalived

# 查看 VIP 绑定情况
ip addr show eth0 | grep 172.16.60.244
# 输出类似:inet 172.16.60.244/32 scope global eth0

# 测试 VIP 可连通性
ping -c 3 172.16.60.244

故障转移测试

  1. 在持有 VIP 的 Master 节点上停止 keepalived:systemctl stop keepalived
  2. 观察 VIP 是否漂移到 Slave 节点 (ip addr 命令)。
  3. 注意:由于是非抢占模式,当原 Master 节点恢复后,VIP 不会自动漂回。

五、 配置 Rsync + Inotify 实现数据同步

核心逻辑只有当前持有 VIP 的节点,才启动 inotifywait 监控进程,将数据同步到对端。 避免双向同步导致数据循环和冲突。

5.1 安装软件包

在两台节点上执行:

1
yum install -y rsync inotify-tools
5.2 配置 Rsync 服务端
  • Master 节点 (/etc/rsyncd.conf):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    uid = root
    gid = root
    use chroot = 0
    port = 873
    hosts allow = 172.16.60.0/24
    max connections = 0
    timeout = 300
    pid file = /var/run/rsyncd.pid
    lock file = /var/run/rsyncd.lock
    log file = /var/log/rsyncd.log
    log format = %t %a %m %f %b
    transfer logging = yes

    [master_web]
    path = /data/k8s_storage
    comment = master_web
    ignore errors
    read only = no
    list = no
    auth users = rsync
    secrets file = /etc/rsyncd.passwd
  • Slave 节点:配置与 Master 基本相同,仅修改模块名:
    1
    2
    3
    [slave_web]  # 修改此处
    path = /data/k8s_storage
    ...
5.3 配置 Rsync 认证

在两台节点上创建密码文件:

1
2
3
4
5
6
7
# 1. 服务端密码文件 (`/etc/rsyncd.passwd`)
echo "rsync:123456" > /etc/rsyncd.passwd
chmod 600 /etc/rsyncd.passwd

# 2. 客户端密码文件 (`/opt/rsyncd.passwd`,用于同步时认证对端)
echo "123456" > /opt/rsyncd.passwd
chmod 600 /opt/rsyncd.passwd
5.4 启动 Rsync 服务
1
2
systemctl enable --now rsyncd
ss -tlnp | grep 873 # 验证端口监听
5.5 配置自动同步脚本 (核心)

原理:每个节点都运行一个监控脚本 (vip_monitor.sh),定期检查本机是否持有 VIP。如果持有,则启动数据同步进程 (rsync_inotify.sh) 同步到对端;如果不持有,则杀死本机的同步进程。

  1. 创建数据同步脚本 (/opt/rsync_inotify.sh):

    • Master 节点内容 (同步到 Slave):
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      #!/bin/bash
      host=172.16.60.236 # Slave IP
      src=/data/k8s_storage/
      des=slave_web # Slave 的 rsync 模块名
      password=/opt/rsyncd.passwd
      user=rsync
      inotifywait=/usr/bin/inotifywait

      $inotifywait -mrq --timefmt '%Y%m%d %H:%M' --format '%T %w%f%e' \
      -e modify,delete,create,attrib $src \
      | while read files; do
      rsync -avzP --delete --timeout=100 --password-file=${password} $src $user@$host::$des
      echo "${files} was rsynced" >> /tmp/rsync.log 2>&1
      done
    • Slave 节点内容 (同步到 Master):只需修改 hostdes 变量为 Master 的信息。
  2. 创建 VIP 监控脚本 (/opt/vip_monitor.sh):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash
    VIP_NUM=`ip addr | grep 244 | wc -l`
    RSYNC_INOTIRY_NUM=`ps -ef | grep /usr/bin/inotifywait | grep -v grep | wc -l`

    if [ ${VIP_NUM} -ne 0 ]; then
    # 本机持有 VIP
    if [ ${RSYNC_INOTIRY_NUM} -eq 0 ]; then
    # 如果同步进程未启动,则启动它
    nohup sh /opt/rsync_inotify.sh &
    fi
    else
    # 本机不持有 VIP
    if [ ${RSYNC_INOTIRY_NUM} -ne 0 ]; then
    # 如果同步进程正在运行,则杀死它
    pkill -f rsync_inotify.sh
    pkill -f inotifywait
    fi
    fi
  3. 创建持续运行脚本 (/opt/rsync_monit.sh):

    1
    2
    3
    4
    5
    6
    #!/bin/bash
    while [ "1" = "1" ]
    do
    /bin/bash /opt/vip_monitor.sh > /dev/null 2>&1
    sleep 5 # 每5秒检查一次VIP状态
    done
  4. 设置开机自启与启动

    1
    2
    3
    4
    5
    6
    7
    chmod +x /opt/*.sh
    # 将以下内容添加到 /etc/rc.local (并确保 rc.local 有执行权限)
    echo "nohup /bin/bash /opt/rsync_monit.sh &" >> /etc/rc.local
    chmod +x /etc/rc.d/rc.local

    # 立即启动
    nohup /bin/bash /opt/rsync_monit.sh &

六、 最终验证与总结

6.1 功能验证
  1. VIP 漂移与数据同步
    • 在 VIP 当前所在节点 (如 Master) 的 /data/k8s_storage 创建文件。
    • 观察文件是否自动同步到对端节点。
    • 停止当前节点的 keepalived,触发 VIP 漂移。
    • 在新的 VIP 持有节点上创建文件,观察同步是否反向进行。
  2. NFS 服务故障
    • 在 VIP 持有节点上强制停止 NFS 服务 (systemctl stop nfs-server)。
    • 观察 nfs_check.sh 脚本是否会重启 NFS,如果重启失败,VIP 是否漂移。
6.2 部署到 Kubernetes

在 K8s 的 PersistentVolume (PV) 定义中,使用 VIP (172.16.60.244) 作为 NFS 服务器地址。这样,无论后端哪台物理服务器实际提供服务,K8s 集群都能持续访问存储。

6.3 关键注意事项
  • 非抢占模式:是此架构稳定性的关键,避免脑裂和数据不一致。
  • 单向同步:确保同一时刻只有一端向另一端同步数据。
  • 网络与性能:主备节点间网络延迟会影响同步实时性。对于超大规模或IO密集型场景,需评估 rsync 性能是否满足。
  • 数据一致性rsync 不是分布式文件系统,在主备切换瞬间,如果数据未完全同步,可能存在极小时间窗口的数据不一致风险。对于极高一致性要求场景,需考虑更高级的存储方案(如 Ceph/GlusterFS)。
  • 安全:生产环境应使用更复杂的 rsync 密码,并考虑使用 SSH 隧道加密同步流量。

一、 概述与风险提示

使用场景

  • 不慎提交了敏感信息(如密码、密钥)。
  • 误提交了大文件导致仓库体积膨胀。
  • 需要清理版本控制历史中的临时文件。

⚠️ 重要风险提示

  1. 不可逆操作:修改 Git 历史会改变提交的哈希值 (SHA),影响所有协作者。
  2. 必须备份:执行任何历史修改操作前,务必备份整个仓库
  3. 团队协调:操作前应通知所有协作者,操作后需重新 clone 仓库。
  4. 替代方案:如果只是想删除最新提交中的文件,使用 git rm 即可,无需修改历史。

二、 方法一:git filter-branch

适用于批量处理整个仓库的历史记录。

1
2
3
4
5
6
7
# 切换到仓库根目录
cd /path/to/repo

# 执行删除操作
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch example.txt' \
--prune-empty --tag-name-filter cat -- --all

参数说明

  • --force:强制覆盖旧的备份分支。
  • --index-filter:对每个提交的索引执行命令。
  • git rm --cached --ignore-unmatch:从索引中移除文件,但忽略文件不存在的情况。
  • --prune-empty:删除因操作变为空的提交。
  • --tag-name-filter cat:保留原有标签名称。
  • --all:处理所有分支。

清理残留

1
2
3
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now --aggressive

三、 方法二:git rebase

适用于处理少量连续提交中的文件删除。

1
2
3
4
5
6
# 1. 查看提交历史,确定目标提交范围
git log --oneline

# 2. 开始交互式 rebase
# 例如从 HEAD~5 开始,包含最近5个提交
git rebase -i HEAD~5

在打开的编辑器中,找到包含目标文件的提交,将其 pick 改为 edit

1
2
3
pick abc1234 添加配置文件
edit def5678 添加敏感文件 <-- 改为 edit
pick 89a0123 修复bug

保存退出后,执行以下操作:

1
2
3
4
5
6
7
8
# 删除文件
git rm example.txt

# 修改当前提交(不改变消息)
git commit --amend --no-edit

# 继续 rebase 过程
git rebase --continue

如果有多个提交需要处理,重复上述 edit -> git rm -> amend -> continue 的流程。

四、 方法三:git filter-repo(推荐)

git filter-repo 是目前最推荐的工具,速度快、灵活性高、功能强大。

安装

1
2
# 使用 pip 安装
python3 -m pip install --user git-filter-repo

删除单个文件

1
git filter-repo --path example.txt --invert-paths

删除多个文件或目录

1
git filter-repo --path-rename example.txt: --path-rename sensitive/: --invert-paths

删除大于指定大小的文件

1
git filter-repo --strip-blobs-bigger-than 10M --invert-paths

⚠️ 重要filter-repo 要求仓库是干净的 clone,建议使用以下方式:

1
2
3
4
5
6
7
8
9
10
11
# 1. 克隆仓库(使用 --mirror 完整克隆)
git clone --mirror https://github.com/user/repo.git

# 2. 进入仓库目录
cd repo.git

# 3. 执行过滤
git filter-repo --path example.txt --invert-paths

# 4. 推送更新
git push --force

五、 方法对比与总结

特性 filter-branch rebase filter-repo
速度 取决于提交数
适用场景 大量历史处理 少量连续提交 所有场景
学习曲线 中等 较低
灵活性
推荐程度 ❌ 不推荐 ⚠️ 慎用 ✅ 强烈推荐

建议流程

  1. 优先考虑使用 **git filter-repo**。
  2. 操作前务必备份仓库
  3. 通知协作者即将进行的维护。
  4. 操作完成后,强制推送到远程:git push --force --all
  5. 提醒所有协作者重新 clone 仓库。

1. 协议识别

执行 git remote -v 确认远程仓库协议:

  • http://https://:使用 HTTP 代理配置
  • git@ssh://:使用 SSH 代理配置

2. HTTP/HTTPS 代理配置

Git 统一通过 http.proxy 处理 HTTP 与 HTTPS 流量。

  • 全局生效

    1
    2
    3
    4
    # HTTP/HTTPS 代理
    git config --global http.proxy http://127.0.0.1:<port>
    # SOCKS5 代理
    git config --global http.proxy socks5://127.0.0.1:<port>
  • 指定域名生效(以 GitHub 为例)

    1
    2
    git config --global http.https://github.com.proxy http://127.0.0.1:<port>
    git config --global http.https://github.com.proxy socks5://127.0.0.1:<port>

3. SSH 代理配置

修改 ~/.ssh/config,通过 ProxyCommand 转发流量。

  • Linux / macOS

    1
    2
    3
    Host github.com
    User git
    ProxyCommand nc -X connect -x 127.0.0.1:<port> %h %p
  • Windows

    1
    2
    3
    Host github.com
    User git
    ProxyCommand connect -H 127.0.0.1:<port> %h %p

    注:%h%p 为 SSH 内置占位符,禁止修改。Windows 需确保 connect.exe 已加入 PATH。

4. 验证与清理

1
2
3
4
5
6
7
# 查看当前代理配置
git config --global --get http.proxy
git config --global --get http.https://github.com.proxy

# 清除全局代理
git config --global --unset http.proxy
git config --global --unset http.https://github.com.proxy

5. 配置优先级与注意事项

配置层级 作用范围 优先级
仓库级 (git config) 当前 .git 目录 最高
全局级 (--global) 当前用户所有仓库
系统环境变量 (HTTP_PROXY) 系统全局进程 最低
  • 代理软件需保持运行,否则 Git 操作直接超时。
  • 生产环境建议仅对特定域名配置代理,避免拦截内网或私有仓库流量。
  • SSH 代理配置修改后无需重启,下次连接自动生效。

一、使用 SC 命令管理 Windows 服务

SC.exe 是一个强大的命令行工具,用于与 Windows 服务控制管理器通信,可以创建、配置、启动、停止和删除系统服务。

1.1 基础语法

SC 命令的基本语法如下:

1
SC [\\Servername] command Servicename [Optionname= Optionvalues]
  • Servername:远程计算机名(如 \\192.168.1.100),本地操作可省略。
  • Command:要执行的操作命令。
  • Servicename:服务的键名(注册表中的名称),不同于显示名称。
  • Optionname= Optionvalues:选项名和值。注意:等号后面必须有一个空格

1.2 常用命令速览

命令 功能描述
create 创建服务(添加到注册表)
delete 删除服务
start 启动服务
stop 停止服务
config 更改服务配置(永久生效)
query 查询服务状态
qc 查询服务配置信息

1.3 核心操作示例

1. 创建服务

将可执行程序注册为自动启动的服务。

1
sc create ServiceName binPath= "C:\Path\To\YourProgram.exe" start= auto

示例:将 Tomcat 注册为服务

1
sc create Tomcat binPath= "F:\apache-tomcat\bin\startup.bat" start= auto

2. 删除服务

1
sc delete ServiceName

示例:删除 Tomcat 服务

1
sc delete Tomcat

3. 配置与查询服务

  • 更改服务启动类型(如启用 Telnet):
    1
    2
    sc config tlntsvr start= auto
    net start tlntsvr
  • 查询服务状态
    1
    sc query ServiceName
  • 查询服务详细配置
    1
    sc qc ServiceName

1.4 SC CREATE 命令详解

创建服务时可以指定更多参数,格式如下:

1
sc create Servicename [type= {own|share}] [start= {boot|system|auto|demand|disabled}] [binPath= <二进制路径>] [obj= <账户名>] [Displayname= <显示名称>] [depend= <依赖服务>]

关键参数说明

  • type=:服务类型。own 为独立进程,share 为共享进程(默认)。
  • start=:启动类型。auto 为自动,demand 为手动(默认),disabled 为禁用。
  • binPath=(必需) 可执行文件的完整路径。
  • obj=:运行服务的账户,默认为 LocalSystem
  • Displayname=:在服务管理器中显示的名称。
  • depend=:该服务所依赖的其他服务(用空格分隔)。

复杂创建示例

1
sc create MyService binPath= "C:\MyApp\app.exe --config config.xml" type= own start= auto Displayname= "我的后台服务" depend= RPCSS/Tcpip

二、使用 NSSM 封装任意程序为服务

对于非原生服务程序(如普通 .exe 控制台程序),可以使用 NSSM (Non-Sucking Service Manager) 将其封装为标准的 Windows 服务。它比微软自带的 srvany 更强大易用。

2.1 NSSM 的优势

  1. 支持任何 .exe 程序。
  2. 安装和修改配置非常简单(有图形界面)。
  3. 可重定向程序输出到日志文件(支持日志轮换)。
  4. 具备服务守护功能,程序崩溃后可自动重启。
  5. 可自定义环境变量。

2.2 基本使用流程

1. 服务安装

打开命令行,执行:

1
nssm install <ServiceName>

这会弹出一个图形化配置窗口。在 “Application” 标签页中,设置:

  • Path:选择你的可执行程序。
  • Startup directory:设置程序的工作目录。
  • Arguments:如有需要,填入启动参数。

配置完成后,点击 “Install service”

命令行静默安装示例(安装 Jenkins Agent):

1
2
3
4
5
nssm install Jenkins "%PROGRAMFILES%\Java\jre7\bin\java.exe"
nssm set Jenkins AppParameters -jar slave.jar -jnlpUrl https://jenkins/computer/%COMPUTERNAME%/slave-agent.jnlp
nssm set Jenkins AppDirectory C:\Jenkins
nssm set Jenkins AppStdout C:\Jenkins\jenkins.log
nssm start Jenkins

2. 服务管理

  • 启动服务nssm start <ServiceName>
  • 停止服务nssm stop <ServiceName>
  • 重启服务nssm restart <ServiceName>

3. 修改配置

1
nssm edit <ServiceName>

再次打开图形界面修改参数。

4. 删除服务

1
2
3
nssm remove <ServiceName>
# 或自动确认删除
nssm remove <ServiceName> confirm

三、其他服务管理方式

3.1 使用 Regsvr32 注册控件

Regsvr32 用于注册 .dll.ocx 等控件文件。

1
Regsvr32 [/s] [/u] DLLName
  • /s:静默注册,不显示成功对话框。
  • /u:卸载控件。

3.2 通过注册表手动删除服务

如果 sc delete 失败,可以手动删除:

  1. Win + R,输入 regedit 打开注册表编辑器。
  2. 导航至:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
  3. 找到与服务名对应的键值,右键删除即可。

四、总结与最佳实践

场景 推荐工具 关键命令/操作
管理原生/已知服务 SC 命令 sc start/stop/config/query
将自定义程序安装为服务 SC 命令 sc create ... binPath= ...
封装复杂程序(需日志、守护) NSSM nssm install (图形界面配置)
注册/卸载系统控件 Regsvr32 Regsvr32 MyControl.dll

重要提醒

  1. 使用 sc create 时,binPath=start= 等参数中的等号后必须有一个空格
  2. 如果路径或服务名包含空格,必须使用双引号包裹。
  3. 大多数服务操作需要管理员权限
  4. 修改服务配置后,有时需要重启服务或计算机才能生效。

通过熟练掌握 SC 命令和 NSSM 工具,你可以高效地在 Windows 环境下完成各种服务的部署、管理和维护工作。

一、核心定位

本文作为GitOps环境搭建系列的第五篇,聚焦基础组件(数据库和缓存)的部署与配置。在GitOps环境中,数据库和缓存是支撑核心组件(Gitea、ArgoCD、Tekton、Harbor等)运行的关键基础设施。

基础组件包括:

  • PostgreSQL/MySQL:关系型数据库,用于存储Gitea、Harbor等组件的元数据
  • Redis:内存缓存,用于提升组件性能和会话管理

本文采用独立命名空间规划,将PostgreSQL部署在postgres命名空间,Redis部署在redis命名空间,MySQL作为备选方案部署在mysql命名空间。所有配置均适配K3s轻量级环境,使用local-path存储类保障数据持久化,并通过Traefik的IngressRouteTCP实现服务访问。

二、部署前置检查

部署前需验证K3s集群状态及存储配置:

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

# 2. 验证存储类配置
kubectl get storageclass
kubectl describe storageclass local-path

# 3. 验证Traefik运行状态
kubectl get pods -n kube-system -l app=traefik

# 4. 检查命名空间
kubectl get ns postgres redis mysql 2>/dev/null || echo "命名空间不存在,将自动创建"

# 5. 验证网络连通性
ping -c 3 8.8.8.8

前置条件检查清单:

  • K3s集群运行正常
  • local-path存储类可用
  • Traefik Pod处于Running状态
  • 网络可访问外网(用于拉取镜像)
  • 具备集群管理权限

三、创建独立命名空间

为实现数据库与缓存服务的资源隔离和精细化管理,分别创建专属命名空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# namespaces.yaml
apiVersion: v1
kind: Namespace
metadata:
name: postgres
---
apiVersion: v1
kind: Namespace
metadata:
name: redis
---
apiVersion: v1
kind: Namespace
metadata:
name: mysql

应用配置:

1
2
3
4
kubectl apply -f namespaces.yaml

# 验证命名空间创建
kubectl get namespaces | grep -E "postgres|redis|mysql"

四、部署PostgreSQL

4.1 配置PostgreSQL

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# postgresql.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
namespace: postgres
data:
POSTGRES_DB: "gitea"
POSTGRES_USER: "gitea"
POSTGRES_PASSWORD: "gitea123"
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
PGDATA: "/var/lib/postgresql/data/pgdata"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: postgres
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: postgres-config
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
type: ClusterIP

4.2 配置IngressRouteTCP(可选)

如需通过Traefik外部访问PostgreSQL,配置IngressRouteTCP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# postgres-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: postgres-ingressroute-tcp
namespace: postgres
spec:
entryPoints:
- postgres-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: postgres
port: 5432

4.3 应用PostgreSQL配置

1
2
3
4
5
6
7
8
9
10
# 部署PostgreSQL
kubectl apply -f postgresql.yaml

# 可选:部署IngressRouteTCP
kubectl apply -f postgres-ingressroute-tcp.yaml

# 验证部署状态
kubectl get pods -n postgres
kubectl get pvc -n postgres
kubectl get svc -n postgres

五、部署Redis

5.1 配置Redis

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# redis.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: redis
data:
redis.conf: |
bind 0.0.0.0
protected-mode no
port 6379
requirepass "redis123456"
appendonly yes
appendfsync everysec
dir /data
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: redis
spec:
serviceName: redis
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command: ["redis-server", "/etc/redis/redis.conf"]
ports:
- containerPort: 6379
volumeMounts:
- name: redis-config
mountPath: /etc/redis
- name: redis-data
mountPath: /data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "local-path"
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: redis
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
type: ClusterIP

5.2 配置IngressRouteTCP(可选)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# redis-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: redis-ingressroute-tcp
namespace: redis
spec:
entryPoints:
- redis-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: redis
port: 6379

5.3 应用Redis配置

1
2
3
4
5
6
7
8
9
# 部署Redis
kubectl apply -f redis.yaml

# 可选:部署IngressRouteTCP
kubectl apply -f redis-ingressroute-tcp.yaml

# 验证Redis运行状态
kubectl get pods -n redis
kubectl exec -it redis-0 -n redis -- redis-cli -a redis123456 ping

六、备选方案:部署MySQL

6.1 配置MySQL

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# mysql.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
namespace: mysql
data:
my.cnf: |
[mysqld]
default_authentication_plugin=mysql_native_password
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
namespace: mysql
type: Opaque
data:
mysql-root-password: cm9vdDEyMzQ1Ng== # root123456 base64编码
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: mysql
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql-root-password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "local-path"
resources:
requests:
storage: 20Gi
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: mysql
spec:
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
type: ClusterIP

6.2 配置IngressRouteTCP(可选)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# mysql-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: mysql-ingressroute-tcp
namespace: mysql
spec:
entryPoints:
- mysql-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: mysql
port: 3306

6.3 应用MySQL配置

1
2
3
4
5
6
7
8
# 部署MySQL(备选方案)
kubectl apply -f mysql.yaml

# 可选:部署IngressRouteTCP
kubectl apply -f mysql-ingressroute-tcp.yaml

# 验证MySQL运行状态
kubectl get pods -n mysql

七、验证部署结果

7.1 验证组件状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看所有基础组件状态
kubectl get pods -n postgres
kubectl get pods -n redis
kubectl get pods -n mysql 2>/dev/null || echo "MySQL未部署"

# 查看服务状态
kubectl get svc -n postgres
kubectl get svc -n redis
kubectl get svc -n mysql 2>/dev/null || echo "MySQL未部署"

# 查看持久化存储
kubectl get pvc -n postgres
kubectl get pvc -n redis
kubectl get pvc -n mysql 2>/dev/null || echo "MySQL未部署"

7.2 测试连接功能

1
2
3
4
5
6
7
8
9
10
11
# 测试PostgreSQL连接
kubectl run postgres-test --rm -it --image=postgres:15-alpine -n postgres -- \
psql -h postgres.postgres.svc.cluster.local -U gitea -d gitea -c "SELECT 1;"

# 测试Redis连接
kubectl run redis-test --rm -it --image=redis:7-alpine -n redis -- \
redis-cli -h redis.redis.svc.cluster.local -a redis123456 ping

# 测试MySQL连接(如部署)
kubectl run mysql-test --rm -it --image=mysql:8.0 -n mysql -- \
mysql -h mysql.mysql.svc.cluster.local -uroot -proot123456 -e "SELECT 1;"

7.3 验证IngressRouteTCP(如配置)

1
2
3
4
# 查看IngressRouteTCP状态
kubectl get ingressroutetcps.traefik.containo.us -n postgres 2>/dev/null || echo "未配置"
kubectl get ingressroutetcps.traefik.containo.us -n redis 2>/dev/null || echo "未配置"
kubectl get ingressroutetcps.traefik.containo.us -n mysql 2>/dev/null || echo "未配置"

八、服务访问方式

8.1 集群内访问

  • PostgreSQL: postgres.postgres.svc.cluster.local:5432
  • Redis: redis.redis.svc.cluster.local:6379
  • MySQL: mysql.mysql.svc.cluster.local:3306

8.2 集群外访问(需配置IngressRouteTCP)

  • PostgreSQL: Traefik节点IP:5432(需Traefik配置postgres-tcp入口点)
  • Redis: Traefik节点IP:6379(需Traefik配置redis-tcp入口点)
  • MySQL: Traefik节点IP:3306(需Traefik配置mysql-tcp入口点)

九、日常运维命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看组件日志
kubectl logs -f postgres-0 -n postgres
kubectl logs -f redis-0 -n redis
kubectl logs -f mysql-0 -n mysql 2>/dev/null || echo "MySQL未部署"

# 重启组件
kubectl rollout restart statefulset postgres -n postgres
kubectl rollout restart statefulset redis -n redis
kubectl rollout restart statefulset mysql -n mysql 2>/dev/null || echo "MySQL未部署"

# 数据备份(PostgreSQL示例)
kubectl exec postgres-0 -n postgres -- pg_dump -U gitea gitea > gitea-backup-$(date +%Y%m%d).sql

# 进入容器调试
kubectl exec -it postgres-0 -n postgres -- /bin/bash
kubectl exec -it redis-0 -n redis -- /bin/sh
kubectl exec -it mysql-0 -n mysql -- /bin/bash 2>/dev/null || echo "MySQL未部署"

十、常见问题修复

问题现象 排查方向 修复方案
Pod一直Pending 存储类/资源不足 检查local-path存储类,确认节点有足够资源
数据库连接失败 服务发现/认证 检查Service selector,验证用户名密码
Redis认证失败 密码配置 确认redis.conf中的requirepass配置正确
数据持久化失败 PVC绑定问题 检查PVC状态:kubectl describe pvc -n <namespace>
IngressRouteTCP不生效 Traefik入口点配置 确认Traefik已配置对应TCP入口点

十一、配置参考

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

该目录包含:

  • PostgreSQL完整配置
  • Redis完整配置
  • MySQL完整配置
  • 生产环境优化配置
  • 备份和恢复脚本

总结

本文完成了GitOps环境基础组件(PostgreSQL、Redis、MySQL)的标准化部署,采用独立命名空间实现资源隔离,使用StatefulSet保障有状态服务的稳定性,通过local-path存储类实现数据持久化。

基础组件部署完成后,GitOps环境已具备完整的数据存储和缓存能力。下一篇文章将部署Gitea代码仓库,为GitOps环境提供代码托管服务。

一、核心定位

本文作为GitOps环境搭建系列的第九篇,聚焦容器镜像仓库Harbor的部署与配置。Harbor是由CNCF孵化而成的企业级开源Registry项目,提供完整的镜像存储、签名、扫描和分发能力。

在GitOps环境中,Harbor扮演”镜像存储中枢”角色,作为GitOps流程的镜像仓库环节,接收来自Tekton构建的镜像,并为ArgoCD提供可信的镜像源。Harbor与Gitea、Tekton、ArgoCD协同工作,形成完整的”代码→构建→镜像→部署”自动化流水线。

二、部署前置检查

部署前需验证K3s集群状态及前序组件运行情况:

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

# 2. 验证PostgreSQL运行状态
kubectl get pods -n postgres

# 3. 验证Redis运行状态
kubectl get pods -n redis

# 4. 验证Traefik运行状态
kubectl get pods -n kube-system -l app=traefik

# 5. 验证cert-manager运行状态
kubectl get pods -n cert-manager

# 6. 验证域名解析
nslookup harbor.example.io
nslookup notary.example.io

前置条件检查清单:

  • K3s集群运行正常
  • PostgreSQL数据库可用(用于存储Harbor元数据)
  • Redis缓存服务可用(用于Harbor会话缓存)
  • Traefik反向代理可用
  • cert-manager证书管理可用
  • 域名harbor.example.ionotary.example.io已解析至K3s节点IP
  • 已创建Harbor数据库和用户(如未创建,见下文步骤)

三、准备Harbor数据库

3.1 创建Harbor数据库

1
2
3
4
# 在PostgreSQL中创建Harbor数据库
kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "CREATE DATABASE harbor;"
kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "CREATE USER harbor WITH PASSWORD 'harbor123';"
kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE harbor TO harbor;"

3.2 创建Harbor命名空间

1
2
# 创建Harbor专属命名空间
kubectl create namespace harbor

四、配置Harbor证书

4.1 创建Harbor证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# harbor-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: harbor-cert
namespace: harbor
spec:
secretName: harbor-tls-secret
issuerRef:
name: selfsigned-cluster-issuer
kind: ClusterIssuer
commonName: harbor.example.io
dnsNames:
- harbor.example.io
- notary.example.io
duration: 2160h
renewBefore: 360h
privateKey:
algorithm: RSA
size: 2048
usages:
- server auth

4.2 应用证书配置

1
2
3
4
5
6
# 应用证书配置
kubectl apply -f harbor-certificate.yaml

# 验证证书状态
kubectl get certificate -n harbor
kubectl describe certificate harbor-cert -n harbor

五、标准化部署Harbor

5.1 添加Helm仓库

1
2
3
# 添加Harbor官方Helm仓库
helm repo add harbor https://helm.goharbor.io --force-update
helm repo update

5.2 创建Harbor配置

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# harbor-values.yaml
# 参考:https://gitee.com/Chemmy/kube-template/blob/master/devops/Harbor/harbor-values.yaml

# 全局配置
expose:
type: ingress
tls:
enabled: true
certSource: secret
secret:
secretName: "harbor-tls-secret"
notarySecretName: "harbor-tls-secret"
ingress:
hosts:
core: harbor.example.io
notary: notary.example.io
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.entrypoints: websecure

externalURL: https://harbor.example.io

# 管理员密码
harborAdminPassword: "HarborAdmin123!"

# 持久化存储
persistence:
enabled: true
resourcePolicy: "keep"
persistentVolumeClaim:
registry:
storageClass: "local-path"
accessMode: ReadWriteOnce
size: 100Gi
chartmuseum:
storageClass: "local-path"
accessMode: ReadWriteOnce
size: 5Gi
jobservice:
storageClass: "local-path"
accessMode: ReadWriteOnce
size: 5Gi
trivy:
storageClass: "local-path"
accessMode: ReadWriteOnce
size: 5Gi

# 外部数据库配置(使用前序部署的PostgreSQL)
database:
type: external
external:
host: "postgres.postgres.svc.cluster.local"
port: "5432"
username: "harbor"
password: "harbor123"
coreDatabase: "harbor"
clairDatabase: "harbor_clair"
notaryServerDatabase: "harbor_notary_server"
notarySignerDatabase: "harbor_notary_signer"

# 外部Redis配置
redis:
type: external
external:
addr: "redis.redis.svc.cluster.local:6379"
password: "redis123456"

# 启用ChartMuseum
chartmuseum:
enabled: true
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

# 启用Trivy漏洞扫描
trivy:
enabled: true
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"

# 资源限制
nginx:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"

portal:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"

core:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

jobservice:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

registry:
registry:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

notary:
enabled: true
server:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
signer:
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"

5.3 部署Harbor

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
31
# 部署Harbor
helm install harbor harbor/harbor \
--namespace harbor \
--version 1.13.2 \
-f harbor-values.yaml

# 或使用在线配置
helm install harbor harbor/harbor \
--namespace harbor \
--version 1.13.2 \
--set expose.type=ingress \
--set expose.tls.enabled=true \
--set expose.tls.secret.secretName=harbor-tls-secret \
--set expose.ingress.hosts.core=harbor.example.io \
--set expose.ingress.hosts.notary=notary.example.io \
--set externalURL=https://harbor.example.io \
--set harborAdminPassword=HarborAdmin123! \
--set persistence.enabled=true \
--set persistence.persistentVolumeClaim.registry.storageClass=local-path \
--set persistence.persistentVolumeClaim.registry.size=100Gi \
--set database.type=external \
--set database.external.host=postgres.postgres.svc.cluster.local \
--set database.external.port=5432 \
--set database.external.username=harbor \
--set database.external.password=harbor123 \
--set redis.type=external \
--set redis.external.addr=redis.redis.svc.cluster.local:6379 \
--set redis.external.password=redis123456 \
--set chartmuseum.enabled=true \
--set trivy.enabled=true \
--set notary.enabled=true

六、验证部署结果

6.1 验证组件状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看Harbor Pod状态(首次启动需要2-3分钟)
kubectl get pods -n harbor -w

# 查看Service状态
kubectl get svc -n harbor

# 查看Ingress状态
kubectl get ingress -n harbor

# 查看证书状态
kubectl get certificate -n harbor

# 查看PVC状态
kubectl get pvc -n harbor

6.2 测试访问功能

1
2
3
4
5
6
7
8
9
10
11
# 等待Harbor完全启动
sleep 120

# 测试HTTPS访问
curl -k https://harbor.example.io

# 查看Harbor日志
kubectl logs -n harbor -l app=harbor --tail=50

# 测试Notary访问
curl -k https://notary.example.io

6.3 初始化Harbor

  1. 浏览器访问:https://harbor.example.io
  2. 用户名:admin
  3. 密码:HarborAdmin123!
  4. 首次登录后立即修改密码
  5. 创建项目(如gitops-demo

七、配置容器运行时访问

7.1 Docker客户端配置

1
2
3
4
5
6
7
8
9
10
# 获取Harbor CA证书
kubectl get secret harbor-tls-secret -n harbor -o jsonpath='{.data.ca\.crt}' | base64 --decode > harbor-ca.crt

# 配置Docker信任Harbor证书
sudo mkdir -p /etc/docker/certs.d/harbor.example.io
sudo cp harbor-ca.crt /etc/docker/certs.d/harbor.example.io/ca.crt
sudo systemctl restart docker

# 登录Harbor
docker login harbor.example.io -u admin -p HarborAdmin123!

7.2 Containerd配置(K3s节点)

1
2
3
4
# 配置Containerd信任Harbor证书
sudo mkdir -p /etc/containerd/certs.d/harbor.example.io
sudo cp harbor-ca.crt /etc/containerd/certs.d/harbor.example.io/ca.crt
sudo systemctl restart containerd

7.3 测试镜像推送

1
2
3
4
5
6
7
8
# 拉取测试镜像
docker pull alpine:latest

# 打标签
docker tag alpine:latest harbor.example.io/gitops-demo/alpine:latest

# 推送镜像
docker push harbor.example.io/gitops-demo/alpine:latest

八、Harbor与GitOps全链路集成

完成Harbor部署后,GitOps环境搭建系列已具备完整的端到端交付能力。以下阐述Harbor与系列中其他核心组件的联动关系。

8.1 全链路组件矩阵

组件 职责 在GitOps链路中的角色
Gitea 代码托管与版本控制 开发者推送代码的单一可信数据源
Tekton 云原生CI/CD流水线引擎 监听代码变更,构建镜像并推送至Harbor
Harbor 容器镜像仓库与安全扫描 存储签名镜像,提供可信镜像分发
ArgoCD GitOps持续部署控制平面 监听Harbor镜像Tag变化,自动同步至K3s

8.2 完整流水线联动流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────────────┐
│ GitOps 完整链路 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ① 开发者 ──push──▶ Gitea (Git仓库) │
│ │
│ ② Tekton Pipeline ──webhook触发──▶ 克隆代码 │
│ │
│ ③ Tekton Pipeline ──构建──▶ Docker镜像 │
│ │ │
│ │ docker push │
│ ▼ │
│ ④ Harbor (镜像仓库) ◀── 推送镜像 │
│ │ • 存储镜像bits │
│ │ • Trivy CVE扫描 │
│ │ • Notary镜像签名(可选) │
│ │
│ ⑤ ArgoCD Application ──监听镜像Tag变化──▶ 检测到新镜像 │
│ │ │
│ │ 更新Deployment镜像Tag │
│ ▼ │
│ ⑥ K3s集群 ──kubectl apply──▶ 新Pod以新镜像启动 │
│ │
└─────────────────────────────────────────────────────────────────┘

8.3 Harbor与Gitea、Tekton、ArgoCD联动

Harbor + Gitea(认证集成)

Harbor与Gitea可共用外部认证源(如LDAP/OIDC),实现统一身份管理:

1
2
3
4
5
6
7
8
# Harbor配置外部认证
harbor-core:
config:
auth_mode: "oidc_auth"
oidc_name: "Gitea OIDC"
oidc_endpoint: "https://gitea.example.io/oauth"
oidc_client_id: "harbor-client"
oidc_secret: "harbor-oidc-secret"

Harbor + Tekton(镜像构建推送)

Tekton Pipeline执行构建并将镜像推送至Harbor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Tekton Task: 构建并推送镜像至Harbor
spec:
steps:
- name: git-clone
image: alpine/git
script: |
git clone $(params.REPO_URL) $(params.REPO_DIR)

- name: build-image
image: docker:latest
script: |
docker build -t $(params.IMAGE):$(params.TAG) $(params.REPO_DIR)
docker tag $(params.IMAGE):$(params.TAG) \
harbor.example.io/gitops-demo/$(params.IMAGE):$(params.TAG)

- name: push-image
image: docker:latest
script: |
docker login harbor.example.io -u $(params.HARBOR_USER) -p $(params.HARBOR_PASS)
docker push harbor.example.io/gitops-demo/$(params.IMAGE):$(params.TAG)

Harbor + ArgoCD(镜像驱动部署)

ArgoCD Image Updater自动轮询Harbor镜像仓库,发现新Tag后更新配置并触发同步:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ArgoCD Application(Image Updater注解)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitops-demo-app
annotations:
argocd-image-updater.argoproj.io/image-list: |
demo=harbor.example.io/gitops-demo/demo-image
argocd-image-updater.argoproj.io/demo.update-strategy: latest
argocd-image-updater.argoproj.io/write-back-method: git
spec:
source:
repoURL: https://github.com/your-org/gitops-configs.git
path: apps/demo-app
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: gitops-demo

8.4 安全集成要点

  1. 镜像签名链路:Tekton构建 → Notary签名 → 推送Harbor → 部署时验签,全链路可信;
  2. 漏洞扫描卡点:Harbor Trivy扫描未通过的CVE镜像(Critical/High),可配置阻止推送;
  3. 认证打通:Harbor与Gitea共用OIDC认证,实现统一身份管理;
  4. 网络隔离:Harbor仅通过Traefik 443端口暴露,K3s节点通过内部网络拉取镜像。

九、服务访问方式

9.1 集群内访问

  • Web界面harbor-core.harbor.svc.cluster.local
  • Registry APIharbor-registry.harbor.svc.cluster.local
  • ChartMuseumharbor-chartmuseum.harbor.svc.cluster.local

9.2 集群外访问

  • Web界面https://harbor.example.io
  • Registryharbor.example.io(Docker push/pull)
  • Notaryhttps://notary.example.io

十、日常运维命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看Harbor状态
kubectl get all -n harbor

# 查看日志
kubectl logs -f deployment/harbor-core -n harbor
kubectl logs -f deployment/harbor-registry -n harbor
kubectl logs -f deployment/harbor-portal -n harbor

# 重启组件
kubectl rollout restart deployment -n harbor

# 备份Harbor数据
kubectl exec -n harbor $(kubectl get pod -n harbor -l component=registry -o jsonpath='{.items[0].metadata.name}') -- tar czf /tmp/registry-backup.tar.gz /storage
kubectl cp harbor/$(kubectl get pod -n harbor -l component=registry -o jsonpath='{.items[0].metadata.name}'):/tmp/registry-backup.tar.gz ./registry-backup-$(date +%Y%m%d).tar.gz

# 查看资源使用情况
kubectl top pods -n harbor

十一、常见问题修复

问题现象 排查方向 修复方案
Harbor无法启动 数据库连接失败 检查PostgreSQL连接,验证用户名密码
证书错误 证书配置/Secret 检查cert-manager状态,验证证书Secret
镜像推送失败 认证/网络 检查Docker登录状态,验证网络连通性
PVC无法绑定 存储类/磁盘空间 检查local-path存储类,确认节点有足够空间
Trivy扫描失败 网络/资源 检查Trivy网络连通性,增加资源限制
Notary服务异常 证书/配置 检查Notary证书配置,验证域名解析

十二、配置参考

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

该目录包含:

  • Harbor Helm values配置
  • 证书和路由配置
  • 数据库初始化脚本
  • 生产环境优化配置
  • 集成配置示例

总结

本文完成了Harbor在K3s集群中的标准化部署,实现了镜像仓库的完整功能。Harbor作为GitOps环境的镜像存储中枢,为自动化构建和部署提供了可靠的镜像管理能力。

部署完成后,建议配置Tekton Pipeline实现自动镜像构建和推送,配置ArgoCD实现镜像更新自动同步。至此,GitOps环境的所有核心组件已部署完成,形成了完整的自动化流水线。

一、核心定位

本文作为GitOps环境搭建系列的第八篇,聚焦Tekton CI/CD流水线的部署与配置。Tekton是云原生CI/CD框架,专为Kubernetes环境设计,提供声明式的流水线定义和任务执行能力。

在GitOps环境中,Tekton扮演”持续集成引擎”角色,作为GitOps流程的构建和测试环节,实现从代码提交到镜像构建的自动化。Tekton与Gitea、Harbor、ArgoCD协同工作,形成完整的”代码→构建→镜像→部署”自动化流水线。

二、部署前置检查

部署前需验证K3s集群状态及前序组件运行情况:

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

# 2. 验证ArgoCD运行状态
kubectl get pods -n argocd

# 3. 验证cert-manager运行状态
kubectl get pods -n cert-manager

# 4. 验证Traefik运行状态
kubectl get pods -n kube-system -l app=traefik

# 5. 验证Gitea运行状态
kubectl get pods -n gitea

# 6. 验证域名解析
nslookup tekton.example.io

前置条件检查清单:

  • K3s集群运行正常
  • ArgoCD GitOps核心可用
  • cert-manager证书管理可用
  • Traefik反向代理可用
  • Gitea代码仓库可用
  • 域名tekton.example.io已解析至K3s节点IP
  • Git仓库https://gitea.example.io/gitea_admin/devops-deploy.git已创建并包含Tekton配置

三、基于ArgoCD部署Tekton

3.1 准备Git仓库配置

在Gitea仓库devops-deploy.git中创建Tekton配置目录:

1
2
3
4
5
6
# 克隆仓库
git clone https://gitea.example.io/gitea_admin/devops-deploy.git
cd devops-deploy

# 创建Tekton配置目录
mkdir -p tekton

3.2 创建ArgoCD应用配置

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
# tekton/argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: tekton
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.example.io/gitea_admin/devops-deploy.git
path: tekton
targetRevision: HEAD
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m

3.3 创建Tekton核心部署配置

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# tekton/tekton-core.yaml
apiVersion: v1
kind: Namespace
metadata:
name: tekton-pipelines
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tekton-dashboard
namespace: tekton-pipelines
spec:
replicas: 1
selector:
matchLabels:
app: tekton-dashboard
template:
metadata:
labels:
app: tekton-dashboard
spec:
containers:
- name: dashboard
image: gcr.io/tekton-releases/github.com/tektoncd/dashboard/cmd/dashboard:v0.45.0
ports:
- containerPort: 9097
env:
- name: PORT
value: "9097"
- name: CLUSTER_NAME
value: "k3s-gitops"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: tekton-dashboard
namespace: tekton-pipelines
spec:
selector:
app: tekton-dashboard
ports:
- port: 9097
targetPort: 9097
type: ClusterIP

3.4 提交配置到Git仓库

1
2
3
4
# 添加配置文件
git add tekton/
git commit -m "feat: add Tekton deployment configuration"
git push origin main

四、配置HTTPS访问

4.1 创建Tekton证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# tekton/tekton-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tekton-cert
namespace: tekton-pipelines
spec:
secretName: tekton-tls-secret
issuerRef:
name: selfsigned-cluster-issuer
kind: ClusterIssuer
commonName: tekton.example.io
dnsNames:
- tekton.example.io
duration: 2160h
renewBefore: 360h
privateKey:
algorithm: RSA
size: 2048
usages:
- server auth

4.2 配置IngressRoute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# tekton/tekton-ingressroute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: tekton-websecure
namespace: tekton-pipelines
spec:
entryPoints:
- websecure
routes:
- match: Host(`tekton.example.io`) && PathPrefix(`/`)
kind: Rule
services:
- name: tekton-dashboard
passHostHeader: true
port: 9097
tls:
secretName: tekton-tls-secret

4.3 应用ArgoCD配置

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
# 应用ArgoCD Application配置
kubectl apply -f tekton/argocd-application.yaml

# 或直接创建Application
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: tekton
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.example.io/gitea_admin/devops-deploy.git
path: tekton
targetRevision: HEAD
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
EOF

五、验证部署结果

5.1 验证ArgoCD同步状态

1
2
3
4
5
6
7
8
9
# 查看ArgoCD应用状态
argocd app get tekton
argocd app sync tekton # 手动触发同步

# 查看同步历史
argocd app history tekton

# 查看应用资源
argocd app resources tekton

5.2 验证Tekton组件状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看Tekton命名空间资源
kubectl get all -n tekton-pipelines

# 查看Dashboard Pod状态
kubectl get pods -n tekton-pipelines -l app=tekton-dashboard

# 查看Service状态
kubectl get svc -n tekton-pipelines tekton-dashboard

# 查看证书状态
kubectl get certificate -n tekton-pipelines
kubectl describe certificate tekton-cert -n tekton-pipelines

# 查看IngressRoute状态
kubectl get ingressroute -n tekton-pipelines

5.3 测试访问功能

1
2
3
4
5
6
7
8
# 测试HTTPS访问
curl -k https://tekton.example.io

# 查看Dashboard日志
kubectl logs -n tekton-pipelines -l app=tekton-dashboard --tail=50

# 进入容器检查状态
kubectl exec -it $(kubectl get pod -n tekton-pipelines -l app=tekton-dashboard -o jsonpath='{.items[0].metadata.name}') -n tekton-pipelines -- /bin/sh

六、配置示例流水线

6.1 创建Tekton Pipeline资源

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
31
32
33
34
35
36
37
38
39
# tekton/example-pipeline.yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: build-and-deploy
namespace: tekton-pipelines
spec:
params:
- name: git-url
type: string
description: Git repository URL
- name: image-name
type: string
description: Docker image name
tasks:
- name: fetch-source
taskRef:
name: git-clone
params:
- name: url
value: $(params.git-url)
- name: revision
value: main
workspaces:
- name: output
workspace: source

- name: build-image
runAfter: [fetch-source]
taskRef:
name: kaniko
params:
- name: IMAGE
value: $(params.image-name)
workspaces:
- name: source
workspace: source
- name: dockerconfig
workspace: docker-config

6.2 创建Tekton Task资源

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# tekton/tasks.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
namespace: tekton-pipelines
spec:
workspaces:
- name: output
description: Git repository will be cloned here
params:
- name: url
description: Git repository URL
type: string
- name: revision
description: Git revision to clone
type: string
default: main
steps:
- name: clone
image: alpine/git
script: |
git clone $(params.url) $(workspaces.output.path)
cd $(workspaces.output.path)
git checkout $(params.revision)
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko
namespace: tekton-pipelines
spec:
workspaces:
- name: source
description: Source code workspace
- name: dockerconfig
description: Docker config.json workspace
params:
- name: IMAGE
description: Docker image name
type: string
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:v1.9.0
env:
- name: DOCKER_CONFIG
value: /workspace/dockerconfig
command:
- /kaniko/executor
args:
- --dockerfile=$(workspaces.source.path)/Dockerfile
- --destination=$(params.IMAGE)
- --context=$(workspaces.source.path)

七、服务访问方式

7.1 集群内访问

  • Dashboard Web界面tekton-dashboard.tekton-pipelines.svc.cluster.local:9097
  • API访问:通过Service直接访问Tekton组件

7.2 集群外访问

  • Dashboard Web界面https://tekton.example.io
  • Git Webhook配置https://tekton.example.io(用于接收Gitea webhook)

八、日常运维命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看Tekton资源
kubectl get pipelines.tekton.dev -n tekton-pipelines
kubectl get tasks.tekton.dev -n tekton-pipelines
kubectl get pipelineruns.tekton.dev -n tekton-pipelines
kubectl get taskruns.tekton.dev -n tekton-pipelines

# 查看Dashboard日志
kubectl logs -f deployment/tekton-dashboard -n tekton-pipelines

# 重启Dashboard
kubectl rollout restart deployment tekton-dashboard -n tekton-pipelines

# 查看资源使用情况
kubectl top pods -n tekton-pipelines

# 清理完成的PipelineRun
kubectl delete pipelineruns.tekton.dev --all -n tekton-pipelines --field-selector=status.conditions[0].status=True

九、常见问题修复

问题现象 排查方向 修复方案
ArgoCD同步失败 Git仓库访问权限 检查ArgoCD Repository配置,添加访问凭证
Dashboard无法访问 IngressRoute/证书 检查IngressRoute配置,验证证书Secret是否存在
Pipeline执行失败 任务配置/资源权限 检查Task定义,验证ServiceAccount权限
镜像构建失败 Docker配置/网络 检查kaniko配置,验证网络连通性
Webhook不触发 Webhook配置/网络 检查Gitea webhook配置,验证网络可达性
资源占用过高 资源限制/并发数 调整资源限制,限制并发PipelineRun数量

十、配置参考

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

该目录包含:

  • Tekton核心部署配置
  • 示例Pipeline和Task定义
  • Webhook集成配置
  • 生产环境优化配置
  • 监控和日志配置

总结

本文完成了Tekton在K3s集群中的标准化部署,基于ArgoCD实现了GitOps方式的CI/CD流水线管理。Tekton作为GitOps环境的持续集成引擎,为自动化构建和测试提供了强大的能力。

部署完成后,建议创建示例流水线验证构建功能,配置Gitea webhook实现自动触发,并设置适当的资源限制。下一篇文章将部署Harbor镜像仓库,为GitOps环境提供镜像存储和分发能力。

一、核心定位

本文作为GitOps环境搭建系列的第七篇,聚焦核心组件ArgoCD的部署与配置。ArgoCD是Argo Project开源的声明式GitOps持续部署工具,专为Kubernetes应用部署与生命周期管理设计。

在GitOps环境中,ArgoCD扮演”部署自动化中枢”角色,作为GitOps流程的核心执行引擎,实现”Git为单一可信数据源”的理念。ArgoCD自动对比Git仓库中的期望状态与K3s集群中的实际状态,完成配置同步与部署,实现从代码到部署的完整自动化。

二、部署前置检查

部署前需验证K3s集群状态及前序组件运行情况:

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

# 2. 验证Traefik运行状态
kubectl get pods -n kube-system -l app=traefik

# 3. 验证cert-manager运行状态
kubectl get pods -n cert-manager

# 4. 验证Gitea运行状态
kubectl get pods -n gitea

# 5. 验证Helm可用性
helm version --short

# 6. 验证域名解析
nslookup argocd.example.io

前置条件检查清单:

  • K3s集群运行正常
  • Traefik反向代理可用
  • cert-manager证书管理可用
  • Gitea代码仓库可用(可选,用于测试)
  • 域名argocd.example.io已解析至K3s节点IP
  • Helm工具可用

三、标准化部署ArgoCD

3.1 环境准备

3.1.1 添加ArgoCD Helm仓库

1
2
3
# 添加ArgoCD官方Helm仓库
helm repo add argo https://argoproj.github.io/argo-helm --force-update
helm repo update

3.1.2 创建命名空间

1
2
# 创建ArgoCD专属命名空间
kubectl create namespace argocd

3.2 编写配置文件

创建argocd-values.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# argocd-values.yaml
# 参考:https://gitee.com/Chemmy/kube-template/blob/master/devops/ArgoCD/argocd-values.yaml

## 全局配置
global:
# 设置访问域名为 argocd.example.io
domain: argocd.example.io

## Argo CD 核心配置
configs:
cm:
# 启用本地 admin 用户
admin.enabled: true

params:
# 禁用 Argo CD Server 的 HTTPS,让 Traefik 处理 TLS
server.insecure: "true"

## Server 配置
server:
# 启用 Ingress,由 Traefik 接管
ingress:
enabled: true
# 指定 IngressClass 为 traefik(K3s 默认)
annotations:
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.entrypoints: websecure
ingressClassName: "traefik"
hosts:
- argocd.example.io

service:
# 使用 ClusterIP,Traefik 通过 Service 发现后端
type: ClusterIP

## Redis(Argo CD 必需,保持启用)
redis:
enabled: true

## 关闭通知模块节省资源
notifications:
enabled: false

## Dex(如无需 SSO 登录,可关闭以节省资源)
dex:
enabled: false

## 其他组件保持默认
crds:
install: true
keep: true

3.3 一键部署ArgoCD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 部署ArgoCD
helm install argocd argo/argo-cd \
--namespace argocd \
--version 9.4.1 \
-f argocd-values.yaml

# 或使用在线配置
helm install argocd argo/argo-cd \
--namespace argocd \
--version 9.4.1 \
--set global.domain=argocd.example.io \
--set server.ingress.enabled=true \
--set server.ingress.ingressClassName=traefik \
--set server.ingress.hosts[0]=argocd.example.io \
--set server.insecure=true \
--set notifications.enabled=false \
--set dex.enabled=false

3.4 验证部署状态

1
2
3
4
5
6
7
8
9
10
11
# 查看ArgoCD Pod状态
kubectl get pods -n argocd -w

# 查看Ingress资源
kubectl get ingress -n argocd

# 查看ArgoCD服务状态
kubectl get svc -n argocd

# 查看部署完成状态
kubectl wait --for=condition=Ready pods -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s

四、配置HTTPS访问

4.1 创建ArgoCD证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# argocd-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: argocd-cert
namespace: argocd
spec:
secretName: argocd-tls-secret
issuerRef:
name: selfsigned-cluster-issuer
kind: ClusterIssuer
commonName: argocd.example.io
dnsNames:
- argocd.example.io
duration: 2160h
renewBefore: 360h
privateKey:
algorithm: RSA
size: 2048
usages:
- server auth

4.2 配置IngressRoute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# argocd-ingressroute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: argocd-websecure
namespace: argocd
spec:
entryPoints:
- websecure
routes:
- match: Host(`argocd.example.io`) && PathPrefix(`/`)
kind: Rule
services:
- name: argocd-server
passHostHeader: true
port: 80
tls:
secretName: argocd-tls-secret

4.3 应用HTTPS配置

1
2
3
4
5
6
7
# 应用证书和路由配置
kubectl apply -f argocd-certificate.yaml
kubectl apply -f argocd-ingressroute.yaml

# 验证证书状态
kubectl get certificate -n argocd
kubectl describe certificate argocd-cert -n argocd

五、访问与初始化ArgoCD

5.1 获取初始密码

1
2
3
4
5
6
# 获取初始管理员密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo

# 或使用更安全的方式
ARGOCD_PASSWORD=$(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)
echo "ArgoCD初始密码: $ARGOCD_PASSWORD"

5.2 访问ArgoCD Web UI

  1. 浏览器访问:https://argocd.example.io
  2. 用户名:admin
  3. 密码:使用上述获取的初始密码
  4. 首次登录后立即修改密码(User Info → Update Password)

5.3 CLI工具安装与配置(可选)

1
2
3
4
5
6
7
8
9
10
11
12
13
# Linux系统安装ArgoCD CLI
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 755 argocd-linux-amd64 /usr/local/bin/argocd
rm -f argocd-linux-amd64

# 验证安装
argocd version --client

# 登录ArgoCD
argocd login argocd.example.io --grpc-web --username admin --password $ARGOCD_PASSWORD

# 或使用token登录(更安全)
argocd account generate-token --account admin

六、验证部署结果

6.1 验证组件状态

1
2
3
4
5
6
7
8
9
10
11
# 查看所有ArgoCD组件状态
kubectl get all -n argocd

# 查看证书和路由状态
kubectl get certificate,ingressroute -n argocd

# 查看ArgoCD日志
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server --tail=50

# 测试HTTPS访问
curl -k https://argocd.example.io

6.2 测试GitOps功能

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
# 创建测试应用(使用Gitea仓库)
cat > test-application.yaml << EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: test-app
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.example.io/gitea_admin/test-repo.git
targetRevision: HEAD
path: k8s/
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
EOF

# 应用测试配置
kubectl apply -f test-application.yaml

# 查看应用状态
kubectl get application -n argocd
argocd app get test-app

6.3 清理测试资源

1
2
# 清理测试应用
kubectl delete -f test-application.yaml

七、生产环境配置建议

7.1 安全加固

1
2
3
4
5
6
7
8
9
10
# 在argocd-values.yaml中添加安全配置
server:
extraArgs:
- --insecure
- --disable-auth
- --rootpath=/argocd
ingress:
annotations:
traefik.ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/16,10.0.0.0/8"
traefik.ingress.kubernetes.io/rate-limit: "10"

7.2 资源优化

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
# 调整资源限制
controller:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

server:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

repoServer:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"

7.3 监控配置

1
2
3
4
5
6
7
8
9
10
# 启用监控
controller:
metrics:
enabled: true
serviceMonitor:
enabled: true

server:
metrics:
enabled: true

八、日常运维命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 查看ArgoCD状态
argocd version
argocd cluster list

# 管理应用
argocd app list
argocd app get <app-name>
argocd app sync <app-name>
argocd app history <app-name>
argocd app rollback <app-name> --id <revision-id>

# 管理项目
argocd proj list
argocd proj get <project-name>

# 查看日志
kubectl logs -f deployment/argocd-server -n argocd
kubectl logs -f deployment/argocd-repo-server -n argocd
kubectl logs -f deployment/argocd-application-controller -n argocd

# 重启组件
kubectl rollout restart deployment argocd-server -n argocd
kubectl rollout restart deployment argocd-repo-server -n argocd
kubectl rollout restart deployment argocd-application-controller -n argocd

九、常见问题修复

问题现象 排查方向 修复方案
无法访问Web UI 域名解析/IngressRoute 检查域名解析,验证IngressRoute配置,查看Traefik日志
证书警告或错误 证书签发/Secret 检查cert-manager状态,验证证书Secret是否存在
无法同步Git仓库 网络/认证 检查网络连通性,配置SSH密钥或访问令牌
资源同步失败 权限/资源配置 检查ServiceAccount权限,验证资源配置格式
CLI登录失败 网络/认证 检查网络代理,验证用户名密码,使用–grpc-web参数
内存占用过高 资源限制/应用数量 调整资源限制,减少监控的应用数量

十、配置参考

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

该目录包含:

  • ArgoCD Helm values配置
  • 证书和路由配置
  • 生产环境优化配置
  • 示例应用配置
  • 监控和备份脚本

总结

本文完成了ArgoCD在K3s集群中的标准化部署,实现了GitOps核心组件的完整功能。ArgoCD作为GitOps环境的核心执行引擎,为自动化部署提供了强大的能力。

部署完成后,建议创建测试应用验证同步功能,配置自动同步策略,并设置适当的资源限制。下一篇文章将部署Tekton CI流水线,为GitOps环境提供持续集成能力。

本文档基于一篇关于在 Kylin V10 上安装 NVIDIA 驱动、CUDA 和 Docker 的实践笔记整理,旨在为使用 NVIDIA GeForce RTX 3060 Ti 显卡的用户提供清晰的离线安装与配置步骤。

1. 系统环境确认

首先,确认您的操作系统版本。

1
cat /etc/kylin-release

预期输出应类似 Kylin Linux Advanced Server release V10 (Sword)

2. 安装 NVIDIA 显卡驱动

步骤 1:禁用系统自带的开源驱动 (nouveau)

  1. 编辑黑名单配置文件:
    1
    sudo vi /usr/lib/modprobe.d/dist-blacklist.conf
  2. 找到 blacklist nvidiafb 一行,在行首添加 # 将其注释掉。
  3. 在文件末尾添加以下两行内容:
    1
    2
    blacklist nouveau
    options nouveau modeset=0
  4. 保存并退出编辑器。

步骤 2:卸载开源驱动模块并重启

1
2
sudo rmmod nouveau
sudo reboot

步骤 3:安装驱动编译依赖
重启后,安装编译 NVIDIA 驱动所需的内核开发包和工具。

1
sudo dnf install gcc kernel-devel-$(uname -r) kernel-headers-$(uname -r) make elfutils-libelf-devel tar bzip2 dkms acpid wget -y

步骤 4:下载并安装官方驱动

  1. 下载驱动:访问 NVIDIA 官方驱动下载页面。选择产品类型为 GeForce RTX 3060 Ti,操作系统选择 Linux 64-bit,点击“搜索”并下载推荐的驱动版本(例如 550 或 575 系列)。将下载的 .run 文件(如 NVIDIA-Linux-x86_64-550.90.07.run)上传到服务器。
  2. 安装驱动
    1
    2
    3
    4
    # 赋予安装脚本执行权限
    chmod +x NVIDIA-Linux-x86_64-*.run
    # 运行安装程序,按照提示操作(通常选择默认选项即可)
    sudo ./NVIDIA-Linux-x86_64-*.run
  3. 验证安装:安装完成后,运行以下命令检查显卡是否被正确识别。
    1
    nvidia-smi
    如果看到显卡型号、驱动版本和 GPU 状态信息,则表示驱动安装成功。

3. 安装 CUDA 工具包

CUDA 是进行 GPU 计算的基础平台。

  1. 下载 CUDA:访问 NVIDIA CUDA 下载页面。选择操作系统为 Linux -> x86_64 -> Kylin -> 10 -> rpm (local)。页面会生成安装命令。
  2. 执行安装命令:复制页面提供的命令在终端中执行,例如:
    1
    2
    3
    4
    wget https://developer.download.nvidia.com/compute/cuda/repos/kylin10/x86_64/cuda-keyring_1.1-1_all.deb
    sudo dpkg -i cuda-keyring_1.1-1_all.deb
    sudo apt-get update
    sudo apt-get -y install cuda
    注意:实际命令请以官网生成的最新命令为准。
  3. 配置环境变量
    1
    2
    3
    echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
    echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
    source ~/.bashrc
  4. 验证安装
    1
    nvcc -V
    此命令应输出已安装的 CUDA 版本号。

4. 离线安装 Docker 并配置 GPU 支持

步骤 1:离线安装 Docker
请参考笔记 麒麟V10离线安装Docker 中详细的分架构(x86_64)离线安装步骤。该指南提供了从外网准备 RPM 包到内网服务器安装、启动和验证的完整流程。请确保按照该指南完成 Docker 的离线安装,并成功运行 docker --versiondocker ps 命令进行验证。

步骤 2:安装 NVIDIA Container Toolkit (为 Docker 添加 GPU 支持)
这是让 Docker 容器能够使用宿主 GPU 的关键步骤。

  1. 配置仓库并安装:
    1
    2
    3
    4
    distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
    curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
    curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
  2. 配置 Docker 使用 NVIDIA 作为默认运行时:
    1
    2
    sudo nvidia-ctk runtime configure --runtime=docker
    sudo systemctl restart docker
  3. 验证 Docker GPU 支持
    运行一个测试容器,检查容器内是否能识别到 GPU。
    1
    sudo docker run --rm --gpus all nvidia/cuda:12.1.1-base-ubuntu22.04 nvidia-smi
    如果此命令在容器内成功输出了与宿主机 nvidia-smi 类似的 GPU 信息,则表明 Docker 已成功配置 GPU 支持,您的 RTX 3060 Ti 现在可以在容器中用于加速计算任务(如 AI 训练、图形渲染等)。

总结

整个过程可以概括为:禁用开源驱动 -> 安装 NVIDIA 官方驱动 -> 安装 CUDA 计算平台 -> 参考专用指南离线安装 Docker 引擎 -> 为 Docker 安装 NVIDIA 容器工具包。完成这些步骤后,您的麒麟 V10 系统就具备了完整的 NVIDIA GPU 计算与容器化支持环境。

在容器化与微服务架构日益普及的今天,镜像仓库作为DevOps流程中的关键环节,承担着镜像存储、分发与管理的重任。Nexus Repository Manager(Nexus)与Harbor作为两款主流的镜像仓库解决方案,各自拥有独特的文件服务能力。本文将从功能特性、应用场景、性能优化及实践建议四个维度,深度剖析这两款工具的镜像仓库文件服务。

一、Nexus镜像仓库文件服务解析

1.1 多格式支持与存储管理

Nexus Repository Manager以其强大的多格式支持能力著称,不仅支持Docker镜像,还兼容Maven、npm、PyPI等多种包管理格式。这种多格式兼容性使得Nexus成为跨技术栈团队的首选。

在文件服务层面,Nexus通过智能存储引擎,实现了镜像与包文件的高效存储与检索。其支持分层存储,可根据文件类型、访问频率等维度自动优化存储策略,提升I/O性能。Nexus的存储架构支持多种后端存储,包括本地文件系统、S3兼容对象存储等,提供了灵活的存储选择。

1.2 安全与权限控制

安全是镜像仓库的核心考量。Nexus提供了细粒度的权限控制机制,支持基于角色(RBAC)的访问控制,可精确到仓库、组、项目等层级。管理员可以创建自定义角色,为不同团队或项目分配适当的访问权限。

同时,Nexus集成了LDAP/Active Directory等身份认证服务,便于与企业现有安全体系集成。在文件传输层面,Nexus支持HTTPS加密传输,确保镜像数据在传输过程中的安全性。此外,Nexus还支持内容验证,确保上传文件的完整性。

1.3 自动化与集成能力

Nexus通过REST API与CI/CD工具链深度集成,支持自动化镜像上传、下载与版本控制。例如,在Jenkins流水线中,可通过Nexus插件直接推送构建完成的镜像至Nexus仓库,实现构建-测试-部署的全自动化。

此外,Nexus还支持Webhook机制,可在镜像状态变更时触发自定义操作,如通知、备份等。其丰富的插件生态系统进一步扩展了功能边界,支持与各种开发工具和平台的集成。

二、Harbor镜像仓库文件服务解析

2.1 专为容器设计的文件服务

Harbor作为一款专为容器镜像设计的仓库解决方案,其文件服务紧密围绕容器生态构建。Harbor支持Docker镜像的存储、分发与签名验证,确保镜像的完整性与来源可信。

其独特的”项目”机制,允许用户按业务线、团队等维度组织镜像,提升管理效率。每个项目可以独立配置权限、存储配额和复制策略,实现了精细化的资源管理。

2.2 高级安全特性

Harbor在安全方面表现尤为突出,除了基本的权限控制与HTTPS加密外,还支持镜像签名与漏洞扫描。通过集成Clair等漏洞扫描工具,Harbor可在镜像上传时自动检测安全漏洞,阻止不安全镜像的入库。

Harbor支持内容信任(Content Trust)机制,确保只有经过签名的镜像才能被拉取和部署。此外,Harbor还支持镜像复制与同步,便于跨地域、跨云环境的镜像分发,同时保持安全策略的一致性。

2.3 性能优化与扩展性

Harbor通过分布式架构设计,实现了水平扩展能力。其支持多节点部署,可通过增加节点提升存储与处理能力。在文件服务层面,Harbor采用了缓存机制与负载均衡策略,有效降低了镜像拉取的延迟。

Harbor支持与Kubernetes等容器编排平台的深度集成,实现镜像的自动拉取与部署。其资源配额管理功能可以防止单个项目占用过多存储空间,确保资源的合理分配。

三、Nexus与Harbor的对比与选择建议

3.1 功能对比

特性维度 Nexus Repository Manager Harbor
多格式支持 支持Docker、Maven、npm、PyPI等多种格式 专注于Docker镜像
安全特性 RBAC权限控制、LDAP集成、HTTPS加密 镜像签名、漏洞扫描、内容信任
存储管理 分层存储、多后端支持 项目级存储配额、镜像复制
集成能力 丰富的REST API、插件生态系统 深度容器生态集成、Kubernetes原生支持
部署架构 单节点或集群部署 分布式架构、水平扩展
社区生态 成熟的企业级解决方案 CNCF毕业项目、活跃的社区支持

3.2 选择建议

选择Nexus的场景:

  • 团队涉及多种技术栈,需要统一管理Docker镜像、Java包、Node.js模块等多种类型的包文件
  • 企业已有Nexus作为制品仓库,希望扩展容器镜像管理功能
  • 需要与现有的Maven、npm等构建工具链深度集成
  • 对多格式包管理的统一性和一致性有较高要求

选择Harbor的场景:

  • 团队专注于容器化应用开发,对镜像安全有严格要求
  • 需要漏洞扫描、镜像签名等高级安全功能
  • 计划在Kubernetes环境中大规模部署容器应用
  • 需要跨地域、跨云的镜像复制和同步能力
  • 重视CNCF生态系统的兼容性和社区支持

混合部署方案:
对于大型企业,可以考虑Nexus与Harbor的混合部署方案。使用Nexus管理多格式的制品包,同时使用Harbor专门管理容器镜像,充分发挥两者的优势。

四、实践建议与优化策略

4.1 存储优化

定期清理策略:

  • 建立镜像生命周期管理策略,定期清理不再使用的镜像与包文件
  • 设置保留策略,如保留最近N个版本,自动删除旧版本
  • 使用标签策略管理镜像版本,避免存储空间浪费

存储配置优化:

  • 根据文件类型与访问频率,合理配置存储策略
  • 对于频繁访问的镜像,考虑使用SSD存储提升I/O性能
  • 配置适当的缓存策略,减少网络传输开销

4.2 安全加固

访问控制强化:

  • 启用多因素认证,提升账户安全性
  • 定期审计权限配置,确保最小权限原则
  • 实施网络访问控制,限制仓库的访问来源

安全扫描集成:

  • 配置自动漏洞扫描,确保所有镜像在上传时都经过安全检查
  • 建立安全策略,阻止高风险镜像的部署
  • 定期更新漏洞数据库,保持扫描的准确性

4.3 性能监控与高可用

监控体系建设:

  • 利用Prometheus、Grafana等监控工具,实时监控镜像仓库的性能指标
  • 设置关键指标告警,如存储空间使用率、请求延迟、错误率等
  • 定期分析日志文件,识别潜在的性能瓶颈与安全风险

高可用部署:

  • 对于生产环境,建议采用集群部署确保高可用性
  • 配置负载均衡,分散请求压力
  • 实施定期备份策略,确保数据安全

4.4 最佳实践总结

  1. 规划先行:在部署前明确需求,选择合适的解决方案
  2. 安全第一:始终将安全作为首要考虑因素
  3. 持续优化:定期评估和优化存储、性能和安全配置
  4. 团队培训:确保团队成员了解工具的使用方法和最佳实践
  5. 文档完善:建立完善的运维文档和应急响应流程

五、未来发展趋势

随着云原生技术的不断发展,镜像仓库技术也在持续演进。未来的发展趋势可能包括:

  1. 智能化管理:利用AI技术优化镜像存储和分发策略
  2. 边缘计算支持:更好地支持边缘场景下的镜像分发
  3. 安全增强:集成更多的安全扫描工具和策略
  4. 生态融合:与更多的云原生工具链深度集成
  5. 性能优化:针对大规模集群的进一步性能优化

结论

Nexus与Harbor作为两款主流的镜像仓库解决方案,各自拥有独特的文件服务能力。Nexus以其多格式支持和成熟的生态系统适合需要统一管理多种类型制品的团队,而Harbor则以其专注于容器镜像的安全特性和云原生集成能力在容器生态中表现出色。

开发者及企业用户应根据自身的技术栈、安全要求和运维能力,选择最适合的镜像仓库工具。通过合理的存储优化、安全加固与性能监控,可进一步提升镜像仓库的效率与可靠性,为DevOps流程提供坚实支撑。在实际应用中,也可以考虑两者的混合部署方案,充分发挥各自的优势,构建更加完善的企业级制品管理体系。

0%