基于 Jenkins + Kubernetes(混合集群) + Argo CD 的完整 DevOps 流程记录(1) - 环境部署
一、环境准备
1.1 镜像仓库
整套 DevOps 流程使用 Harbor 作为内部镜像仓库,所有构建产物(镜像)都会推送到 Harbor,以备后续进行项目部署。Harbor 从 2.x 版本开始支持 OCI 标准镜像,如果是安装的 1.x 版本,在使用 Podman 构建镜像的时候,需要加上 --format docker
参数,以便生成 Docker 格式的镜像文件。
1.1.1 前置条件
- 配置要求: 双核 CPU,4 GB 内存, 硬盘 100 GB+
- 系统要求: Rocky Linux 8 或 CentOS 7.x
- 软件要求: Docker CE、Docker-Compose
1.1.2 安装配置
解压 tar 文件之后,会得到一个 harbor.yml 文件,里面可以对一些参数进行配置,例如监听端口与默认的密码数据。
需要进行配置的选项是 hostname
、https
、harbor_admin_password
,默认情况下, 其他的参数不需要做特殊调整。针对 https 我们默认禁用掉,因为需要有效证书才能暴露 https 给外部服务,否则后续镜像的推送会有问题。
关于 SSL 证书,必须要 全链(Full-Chain)证书 才能正常工作,可使用 amch.sh 等工具进行申请。
hostname: 10.0.0.203
# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 8088
# https related config
#https:
# https port for harbor, default is 443
# port: 443
# The path of cert and key files for nginx
# certificate: /your/certificate/path
# private_key: /your/private/key/path
harbor_admin_password: helloWorld
# ... Other info.
harbor.yml 文件配置完成之后,执行 install.sh 脚本,一切正常的话,安装完成之后,可以输入 docker ps -a
命令查看正在运行的容器信息。
安装成功之后,Harbor 会为我们创建一个 docker-compose.yml 文件,如果需要手动重启 Harbor 相关服务,可以直接安装 Docker-Compose 工具进行操作。
1.2 源代码托管
本地环境我使用的是 Gogs 作为源代码托管平台。它们的作用基本一致,都支持仓库级别的 WebHook 配置,以便后续进行流水线的自动触发工作。
1.2.1 前置条件
- 配置要求: 双核 CPU,4 GB 内存, 硬盘 100 GB+
- 系统要求: Rocky Linux 8 或 CentOS 7.x
- 软件要求: Docker CE、Docker-Compose
1.2.2 快速安装
Gogs 的安装需要外挂一个目录,用于存储具体的数据库数据和配置信息,这里我们在 docker-compose.yaml
的同目录下,建立一个 Volume
文件夹,用于存放持久化数据。需要注意的是,由于容器权限要求,必须设置对应文件夹的所有者为 1000:1000,执行 chown -R 1000:1000 ./Volume
命令进行设置。
对应的 Docker-Compose 文件内容如下:
version: '3.5'
services:
gogs:
image: gogs/gogs
container_name: gogs
volumes:
- ./Volume:/data
ports:
- 8080:3000
restart: always
文件编写完成之后,保存为 docker-compose.yaml 文件,在对应目录下指定 docker-compose -d
命令,等待镜像拉取完成之后,程序就会自动运行。
1.2.3 Gogs 配置
执行了 Docker Compose 命令之后,在浏览器输入 http://<宿主机 IP>:8080
即可对 Gogs 进行一些基本的配置,根据 UI 上面的提示配置即可。在 DEMO 环境当中,我选择的是 SQLite,免去了启动一个单独数据库实例的问题。
1.4 NFS 服务器配置
NFS 服务器主要是为了 Pod 持久化,我们需要在某台机器上部署 NFS 服务。
1.4.1 前置条件
- 配置要求: 双核 CPU,内存 4 G,硬盘 100 GB+
- 系统要求: Rocky Linux 8 或 CentOS 7.x
1.4.2 快速安装
-
在 Shell 当中执行以下命令,安装 NFS 服务所需要的相关依赖。
yum install rpcbind nfs-utils
-
将对应的服务设置为开机自启动。
systemctl start rpcbind systemctl enable rpcbind systemctl start nfs-server systemctl enable nfs-server
-
创建所需要共享的文件夹,建议每个 Deployment 分开创建,这里我以 Jenkins 为例。
mkdir -p /share/jenkins
-
编辑
/etc/exports
文件,在文件内加入以下内容。/share/jenkins *(rw,sync,no_root_squash,no_all_squash)
关于
exports
文件的内容,可以参考 里面的详细描述。 -
重载配置文件。
exportfs -rv
-
关闭防火墙,这里我为了进行 DEMO 测试,是将防火墙进行了关闭处理。
systemctl stop firewalld.service systemctl disable firewalld.service
1.5 Linux 集群初始化
目前的测试集群构成是 1 台 Master 节点,1 台工作节点,Kubernetes 混合集群的控制面都是基于 Linux 进行调度的。
1.5.1 前置条件
角色 | 操作系统 | 配置 | 硬盘 |
---|---|---|---|
Master | CentOS 7.x | 4 核 8G | 50 GB 硬盘 |
Node-1 | CentOS 7.x | 4 核 8 G | 50 GB 硬盘 |
1.5.2 安装集群
在测试 DEMO 中,我直接使用的 sealos 一键部署的 Kubernetes Linux 集群。sealos 类似于 Kubeadm,它将具体的部署细节进行了简化。
首先我们在 Master 节点,先下载 sealos 的二进制包,执行以下命令进行下载:
wget -c https://sealyun-home.oss-cn-beijing.aliyuncs.com/sealos/latest/sealos && chmod +x sealos && mv sealos /usr/bin
PS: 如果提示 -bash: wget: command not found 的话,需要运行
yum install -y wget
安装 wget 工具。
sealos 下载完成之后,需要下载对应的集群安装文件,这里我使用的是 Kubernetes 1.20.15 版本,将其上传到 /root 目录,执行以下命令即可进行安装。
sealos init --passwd 'Password for all Linux nodes' \
--master \
--node \
# Your kubernetes compressed package.
--pkg-url /root/kube1.20.15.tar.gz \
# The version of kubernetes you need to install.
--version v1.20.15
默认情况下,如果没有指定其他的安装参数,Kubectl 会使用 Calico 作为网络插件。等待 sealos 安装完成后,输入 kubectl get nodes
查询当前集群的状态,一切准备就绪后就可以开始下一步操作了。
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 69s v1.20.15
k8s-node-1 Ready 37s v1.20.15
1.5.3 网络调整
所有网络相关步骤,都是参考的 Calico 官网文档 进行操作。
-
首先要在 Master 节点下载并安装 calicoctl,以便关闭 IPIP 模式,对应的二进制文件可以访问 百度网盘下载。
-
将 calicoctl 文件上传到
/usr/local/bin/
,执行以下命令设置为可执行模式。cd /usr/local/bin/ mv calicoctl-linux-amd64 calicoctl chmod +x calicoctl
-
获取对应的 IP Pool 信息,并将其写入到 ippool.yaml 文件当中。
calicoctl --allow-version-mismatch get ipPool default-ipv4-ippool -o yaml > ippool.yaml
-
使用 VI 编辑对应的 ippool.yaml 文件,修改内容如下。
apiVersion: projectcalico.org/v3 kind: IPPool metadata: creationTimestamp: "2022-03-26T16:14:19Z" name: default-ipv4-ippool resourceVersion: "551" uid: 17ef6755-a95e-458a-96ee-27242486a5e5 spec: allowedUses: - Workload - Tunnel blockSize: 26 cidr: 100.64.0.0/10 ipipMode: Never # 修改 Always 为 Never. natOutgoing: true nodeSelector: all() vxlanMode: Never
-
应用 ippool.yaml 的变更。
calicoctl --allow-version-mismatch apply -f ippool.yaml
-
执行以下命令,继续关闭 IPIP 功能。
calicoctl --allow-version-mismatch patch felixconfiguration default -p '{"spec":{"ipipEnabled":false}}'
-
防止 Pod 分配到 Windows 的 IP 网段。
calicoctl --allow-version-mismatch ipam configure --strictaffinity=true
-
1.5.4 信任镜像仓库
集群内的其他 Linux 节点都是使用的 Container-D 作为容器引擎,它们的配置和 Docker 是不一样的。默认安装 Kubernetes 集群的时候,Container-D 也没有默认的配置文件,需要执行 mkdir -p /etc/containerd && containerd config default > /etc/containerd/config.toml
命令,将默认配置的 toml 文件输出到指定目录。在 [plugins."io.containerd.grpc.v1.cri".registry]
节附近,添加如下内容:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors.":"]
endpoint = ["http://:"]
其中 host
指代的镜像仓库的主机地址,port
指的是镜像仓库的端口号。修改完成之后,执行 systemctl restart containerd.service
重新启动 Container-D 服务。
1.5.5 NFS 客户端的安装
在 DEMO 环境当中,如果存在多个 Node 节点,就不适用 hostPath
的方式对 Pod 数据进行持久化。所以会直接采用 NFS 的方式,提供 PV 所需要的持久化卷,在前面我们针对 NFS 进行了服务器配置,不过这还不够,如果不在对应的节点安装 NFS 客户端的话,会导致 Pod 创建失败。
执行以下命令,在节点上安装 NFS 客户端:
yum install nfs-utils
执行以下命令,看是否挂载成功:
showmount -e
Example Output:
[root@k8s-node-1 containerd]# showmount -e 10.0.0.203
Export list for 10.0.0.203:
/share/Jenkins *
参考资料: https://juejin.cn/post/6943424989961928711
1.6 Windows 节点初始化
Windows 节点上 Docker EE 的 Docker in Docker 机制,并不支持挂载 Windows 宿主机上的 Docker 进程,所以不能通过 Jenkins 的 Kubernetes Cloud Node 动态生成 Slave。在 Linux 节点上能够使用的 Podman,在 Windows 容器中也 不受支持。因此只能选择直接部署一台 Windows Server Node,并在机器上安装相关工具,在 Pipeline 中通过 Powershell 的方式进行调用。
1.6.1 前置条件
- 配置要求: 4 核 CPU,8GB 内存
- 系统要求: Windows Server 2019 - 1809
1.6.2 安装 Docker EE
在执行所有操作之前,请确保 Windows Server 处在最新的版本,后续所有操作,我们都假设你处在 PowerShell(管理员模式) 当中。
-
首先我们需要为 Windows Server 安装容器功能,打开 Powershell,在其内部输入以下命令关闭防火墙设置,以防安装失败。
New-NetFireWallRule -DisplayName "Allow All Traffic" -Direction OutBound -Action Allow New-NetFireWallRule -DisplayName "Allow All Traffic" -Direction InBound -Action Allow
-
为 Windows Server 启用容器功能并重启。
Install-WindowsFeature -Name containers Restart-Computer -Force
-
访问链接 Docker EE 下载 Docker,存有 Docker EE 的二进制安装包,在
C:\Program Files\Docker
创建一个文件夹,将对应的压缩文件解压到对应目录。随后,在环境变量的 Path 节中,添加 Docker 目录,随后在 PowerShell 执行以下命令重启并设置为自动启动服务。
dockerd --register-service Set-Service -Name docker -StartupType 'Automatic' Restart-Computer -Force
-
运行
docker info
命令与docker ps -a
命令,确认 Docker EE 已经可以正常运行。PS C:\Users\Administrator> docker info Client: Context: default Debug Mode: false Plugins: app: Docker App (Docker Inc., v0.9.1-beta3) cluster: Manage Mirantis Container Cloud clusters (Mirantis Inc., v1.9.0) registry: Manage Docker registries (Docker Inc., 0.1.0) Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 20.10.9 Storage Driver: windowsfilter Windows: Logging Driver: json-file Plugins: Volume: local Network: ics internal l2bridge l2tunnel nat null overlay private transparent Log: awslogs etwlogs fluentd gcplogs gelf json-file local logentries splunk syslog Swarm: inactive Default Isolation: process Kernel Version: 10.0 17763 (17763.1.amd64fre.rs5_release.180914-1434) Operating System: Windows Server 2019 Standard Version 1809 (OS Build 17763.2746) OSType: windows Architecture: x86_64 CPUs: 4 Total Memory: 5.999GiB Name: WIN-F4GQN7VJPQP ID: Y7WJ:F3XG:XRV7:K36J:C7WU:JVGF:QLIY:AXBK:CKOH:AM2Y:7VIV:VF2K Docker Root Dir: C:\ProgramData\docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false PS C:\Users\Administrator> docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1.6.3 信任镜像仓库
针对 Windows 节点,因为是基于 Docker 引擎的,只需要在 C:\ProgramData\docker\config
创建一个 daemon.json
文件,并配置相关的仓库地址即可。这里以 10.0.0.203:8088 的仓库为例:
{
"insecure-registries": ["10.0.0.203:8088"]
}
配置完成之后,在 Windows 服务当中,重启 Docker Engine 服务即可生效。
1.6.4 Hosts 文件调整
使用 sealos 快速安装的 Kubernetes 集群,其 Kubernetes API 地址是一个伪造的域名 apiserver.cluster.local,在 Windows 节点上,如果要加入这个集群,就需要修改 Windows 节点的 Hosts 文件。(当然,最好的做法是集群内部署一台 DNS 服务器。)
apiserver.cluster.local
1.6.5 配置 Windows 服务
针对 BGP 模式,需要安装以下服务,然后重启系统。
Install-WindowsFeature RemoteAccess
Install-WindowsFeature RSAT-RemoteAccess-PowerShell
Install-WindowsFeature Routing
Restart-Computer -Force
重启完成之后,继续执行以下命令。
Install-RemoteAccess -VpnType RoutingOnly
Start-Service RemoteAccess
1.6.6 安装 Calico 网络
-
在 C 盘创建一个 k 文件夹。
mkdir c:\k
-
从 Linux 的 Master 节点上,复制
~/.kube/config
文件到 Windows 节点上的c:\k\config
。 -
下载 Calico 对应的安装脚本,准备开始安装。
Invoke-WebRequest https://projectcalico.docs.tigera.io/scripts/install-calico-windows.ps1 -OutFile c:\install-calico-windows.ps1
-
执行安装脚本,记得传入你的 Kubernetes 集群版本作为安装参数,随后等待 Calico 安装完成。
c:\install-calico-windows.ps1 -KubeVersion 1.20.15
-
执行以下命令,验证 Calico 服务安装成功。
Get-Service -Name CalicoNode Get-Service -Name CalicoFelix
-
安装 Windows 节点上的 Kubernetes 组件服务。
C:\CalicoWindows\kubernetes\install-kube-services.ps1 Start-Service -Name kubelet Start-Service -Name kube-proxy
-
验证 Kubernetes 组件服务启动成功。
Get-Service -Name kubelet Get-Service -Name kube-proxy
以上操作完成以后,执行 kubectl get nodes -o wide
命令,就可以看到集群已经准备就绪了。
[root@k8s-master .kube]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master Ready control-plane,master 54m v1.20.15 10.0.0.60 CentOS Linux 7 (Core) 3.10.0-1160.el7.x86_64 containerd://1.5.5
k8s-node-1 Ready 53m v1.20.15 10.0.0.61 CentOS Linux 7 (Core) 3.10.0-1160.el7.x86_64 containerd://1.5.5
win-f4gqn7vjpqp Ready 103s v1.20.15 10.0.0.62 Windows Server 2019 Standard 10.0.17763.2746 docker://20.10.9
1.6.7 污点设置
为了防止 Linux Pod 调度到 Windows 节点,导致容器无法运行的情况,我们需要为 Windows 节点都添加一个特殊的污点,只有当 Pod 显式制定了容忍度以后才会被调度到 Windows 节点。
kubectl taint nodes cattle.io/os=windows:NoSchedule
1.6.8 验证网络互通
以下 Manifest 文件可以启动一个 IIS 示例,运行之后我们可以通过 kubetl get pods -o wide
获得它的 Pod IP 地址。
iis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-site-windows
labels:
app: iis-site-windows
spec:
replicas: 1
selector:
matchLabels:
app: iis-site-windows
template:
metadata:
labels:
app: iis-site-windows
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: iis-site-windows
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore
ports:
- containerPort: 80
tolerations:
- key: "cattle.io/os"
operator: "Equal"
value: "windows"
effect: "NoSchedule"
? IIS-Demo kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 0 10m 100.85.249.1 linux-node
iis-site-windows-784844b499-4vccd 1/1 Running 0 87s 100.114.137.3 windows-node-1
获得 IP 地址之后,使用命令 kubectl run -it --rm --restart=Never --overrides='{"spec": { "nodeSelector": { "kubernetes.io/os": "linux" } } }' busybox --image=busybox sh
在 Linux Node 上运行一个 busybox 服务。
运行成功以后,在 busybox 的 Bash,执行 ping 100.82.16.4
命令,查看是否能够 Ping 通,如果能够 Ping 通,说明 Linux Pod -> Windows Pod 已经可以正常通讯。
后续使用 docker exec -ti
进入 Windows Pod 内部,执行 ping 100.85.249.1
命令,如果有返回值说明 ·Windows Pod -> Linux Pod 网络通讯是正常的。
最后在 Windows Pod 内部,执行 ping baidu.com
查看是否能够获取到以下内容,如果获取成功则说明 Windows Pod -> Internet 是互通的。
PS C:\> Invoke-RESTMethod http://baidu.com
最后是确认 Windows Pod 能够访问集群内部的服务,