基于 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 文件,里面可以对一些参数进行配置,例如监听端口与默认的密码数据。

需要进行配置的选项是 hostnamehttpsharbor_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 快速安装

  1. 在 Shell 当中执行以下命令,安装 NFS 服务所需要的相关依赖。

    yum install rpcbind nfs-utils
    
  2. 将对应的服务设置为开机自启动。

    systemctl start rpcbind
    systemctl enable rpcbind
    
    systemctl start nfs-server
    systemctl enable nfs-server
    
  3. 创建所需要共享的文件夹,建议每个 Deployment 分开创建,这里我以 Jenkins 为例。

    mkdir -p /share/jenkins
    
  4. 编辑 /etc/exports 文件,在文件内加入以下内容。

    /share/jenkins *(rw,sync,no_root_squash,no_all_squash)
    

    关于 exports 文件的内容,可以参考 里面的详细描述。

  5. 重载配置文件。

    exportfs -rv
    
  6. 关闭防火墙,这里我为了进行 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 官网文档 进行操作。

  1. 首先要在 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(管理员模式) 当中。

  1. 首先我们需要为 Windows Server 安装容器功能,打开 Powershell,在其内部输入以下命令关闭防火墙设置,以防安装失败。

    New-NetFireWallRule -DisplayName "Allow All Traffic" -Direction OutBound -Action Allow 
    New-NetFireWallRule -DisplayName "Allow All Traffic" -Direction InBound -Action Allow
    
  2. 为 Windows Server 启用容器功能并重启。

    Install-WindowsFeature -Name containers
    Restart-Computer -Force
    
  3. 访问链接 Docker EE 下载 Docker,存有 Docker EE 的二进制安装包,在 C:\Program Files\Docker 创建一个文件夹,将对应的压缩文件解压到对应目录。

    随后,在环境变量的 Path 节中,添加 Docker 目录,随后在 PowerShell 执行以下命令重启并设置为自动启动服务。

    dockerd --register-service
    Set-Service -Name docker -StartupType 'Automatic'
    Restart-Computer -Force
    
  4. 运行 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 网络

  1. 在 C 盘创建一个 k 文件夹。

    mkdir c:\k
    
  2. 从 Linux 的 Master 节点上,复制 ~/.kube/config 文件到 Windows 节点上的 c:\k\config

  3. 下载 Calico 对应的安装脚本,准备开始安装。

    Invoke-WebRequest https://projectcalico.docs.tigera.io/scripts/install-calico-windows.ps1 -OutFile c:\install-calico-windows.ps1
    
  4. 执行安装脚本,记得传入你的 Kubernetes 集群版本作为安装参数,随后等待 Calico 安装完成。

    c:\install-calico-windows.ps1 -KubeVersion 1.20.15
    
  5. 执行以下命令,验证 Calico 服务安装成功。

    Get-Service -Name CalicoNode
    Get-Service -Name CalicoFelix
    
  6. 安装 Windows 节点上的 Kubernetes 组件服务。

    C:\CalicoWindows\kubernetes\install-kube-services.ps1
    Start-Service -Name kubelet
    Start-Service -Name kube-proxy
    
  7. 验证 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 powershell 进入 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 能够访问集群内部的服务,