美文网首页后端砖头DevOps收藏
持续集成与部署(一)

持续集成与部署(一)

作者: JJNile | 来源:发表于2022-10-27 22:02 被阅读0次

    查看 K8s 版本,Kubeadm 初始化

    $ kubectl version
    Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.4", GitCommit:"e6c093d87ea4cbb530a7b2ae91e54c0842d8308a", GitTreeState:"clean", BuildDate:"2022-02-16T12:38:05Z", GoVersion:"go1.17.7", Compiler:"gc", Platform:"linux/amd64"}
    

    可以看到上面的版本是 1.23.4,因此下面的 kubernetes-version 需要修改为对应版本,而且 apiserver-advertise-address 修改为主机的 IP

    $ kubeadm init \
    --apiserver-advertise-address=106.55.37.123 \
    --image-repository registry.aliyuncs.com/google_containers \
    --kubernetes-version v1.23.4 \
    --service-cidr=10.1.0.0/16 \
    --pod-network-cidr=10.244.0.0/16 \
    --ignore-preflight-errors=all  \
    --v=6
    

    环境

    K8s 集群

    Jenkins

    Gitlab

    Dockerhub

    Helm

    搭建 K8s 集群

    K8s 集群部署在远程服务器部署或者使用阿里云等云平台的 K8s 集群,这里使用一台远程服务器安装的是 k3s,也可以用 kubeadm。

    安装 kubesphere

    在集群的主节点,执行以下命令开始安装:

    $ kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.2.1/kubesphere-installer.yaml
       
    $ kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.2.1/cluster-configuration.yaml
    

    检查安装日志:

    kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f
    

    等待安装完成后,通过 30880 端口和并使用默认帐户和密码 (admin/P@88w0rd) 访问 Web 控制台

    image.png

    PS:期间改了密码后面忘记了。。这里插入一个忘记密码的操作,具体也可以参考官方文档

    # <USERNAME> 和 <YOURPASSWORD> 修改为实际用户名和想要修改的密码
    $ kubectl patch users <USERNAME> -p '{"spec":{"password":"<YOURPASSWORD>"}}' --type='merge' && kubectl annotate users <USERNAME> iam.kubesphere.io/password-encrypted-
    

    下载镜像 Jenkins

    由于 Jenkins 在 dockerHub 上的官方镜像是已经废弃的,所以需要下载最新版,在本机安装

    $ docker pull jenkins/jenkins:latest
    

    创建 Jenkins 容器并启用

    $ docker run -d -p 8080:8080 --name jenkins jenkins/jenkins:latest
    

    Jenkins 安装和配置

    启动后访问 8080 端口,进入到 Jenkins 需要初始化

    • 根据提示去对应目录查看密码并复制进去,
    • 选择推荐安装插件即可,等待安装完成后
    • 创建后台账号密码
    • 地址默认

    初始化完成后,安装本地化插件

    image.png

    由于 Jenkins 重启比较慢,可以通过访问 http://localhost:8080/restart 后点击确认,手动重启服务

    之后进入 Jenkins 容器,生成密钥

    $ docker exec -it jenkins /bin/bash
    
    # 生成密钥,一路回车即可
    $ ssh-keygen
    

    需要将公钥传到 K8s 集群的 master 节点所在服务器

    # 将公钥传入 K8s 集群 Master 节点所在的服务器
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub root@106.55.37.187
    
    # 测试
    $ ssh root@106.55.37.187
    

    创建项目

    由于个人电脑装 GitLab 比较消耗资源,因此这里直接用官方的 GitLab 仓库作为测试,在 GitLab 中创建一个私有项目,也可以用 GitHub 或者 Gitee 代替,有条件可以自己搭建 GitLab 或者购买多一个服务器。

    代码仓库添加公钥

    在 GitLab 中添加【本地】和 【Jenkins 容器】的 SSH 公钥

    $ cat ~/.ssh/id_rsa.pub 
    
    image.png

    之后测试宿主机下、Jenkins 容器下、K8s 集群是否能够正常克隆,拉取以及推送:

    以下为项目所属目录,不存在则创建

    • 宿主机:任意目录

    • Jenkins:/var/jenkins_home/workspace/

    • K8s 集群:/usr/local/k8s/

    $ git clone git@gitlab.com:JeaNile/test.git
    

    测试完成后保留项目不进行删除,避免后续上传不了

    安装 rsync

    由于 scp 无法上传隐藏文件,需要指定才行,因此使用 rsync 代替,进入 Jenkins 容器进行安装

    $ apt-get update
    $ apt-get install rsync
    

    安装完成后,进程测试

    $ mkdir .a
    $ rsync -r ./* root@106.55.37.187:/usr/local/k8s/hyperf-learn
    

    保证 .a 目录能上传成功即可

    Jenkins 配置项目

    之后配置 Jenkins 项目,选择创建自由风格的项目

    image.png

    配置 Git 仓库

    image.png

    构建完成执行 shell 查看结果

    image.png

    点击构建并进入任务中

    image.png

    查看构建的 Console,可以看到构建完成后输出的 shell 脚本内容

    image.png

    测试完成后,进行说明大体流程跑通了,接下来讲项目正式构建。

    安装 nerdctl 和 buildkit

    由于使用的是 K3s,底层使用的是 containerd,不像 docker 那么方便,因此需要通过 nerdctl+buildkitd 来实现镜像构建和镜像管理,如果使用的是 docker,或者觉得麻烦的可以安装 docker 跳过此步骤。

    安装 nerdctl

    $ wget https://github.com/containerd/nerdctl/releases/download/v0.18.0/nerdctl-0.18.0-linux-amd64.tar.gz
    tar -zxvf nerdctl-0.18.0-linux-amd64.tar.gz -C /usr/local/containerd/bin/
    ln -s /usr/local/containerd/bin/nerdctl /usr/local/bin/nerdctl
    

    安装完成后查看版本,如果正常输出代表没有问题。

    $ nerdctl version
    

    安装 buildkitd

    $ wget https://github.com/moby/buildkit/releases/download/v0.10.1/buildkit-v0.10.1.linux-amd64.tar.gz
    $ tar -zxvf buildkit-v0.10.1.linux-amd64.tar.gz -C /usr/local/containerd/
    $ ln -s /usr/local/containerd/bin/buildkitd /usr/local/bin/buildkitd
    $ ln -s /usr/local/containerd/bin/buildctl /usr/local/bin/buildctl
    

    编辑保存 buildkit.socket

    $ vim /etc/systemd/system/buildkit.socket
    
    [Unit]
    Description=BuildKit
    Documentation=https://github.com/moby/buildkit
    
    [Socket]
    ListenStream=%t/buildkit/buildkitd.sock
    
    [Install]
    WantedBy=sockets.target
    

    编辑保存 buildkit.service

    $ vim /etc/systemd/system/buildkit.service
    
    [Unit]
    Description=BuildKit
    Requires=buildkit.socket
    After=buildkit.socketDocumentation=https://github.com/moby/buildkit
    
    [Service]
    ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true
    
    [Install]
    WantedBy=multi-user.target
    
    $ systemctl daemon-reload
    $ systemctl enable buildkit
    $ systemctl start buildkit
    

    如果报 FATA[0000] cannot access containerd socket "/run/containerd/containerd.sock": no such file or directory

    将 k3s 的 containerd.sock 软连接到该目录

    $ ln -s /run/k3s/containerd/containerd.sock /run/containerd/containerd.sock
    

    登录 dockerhub,并尝试拉取,之后就可以查看到对应的镜像了

    $ nerdctl login -u jeanile
    ..
    ..
    $ nerdctl pull jeanile/php:test
    docker.io/jeanile/php:test:                                                       resolved       |++++++++++++++++++++++++++++++++++++++|
    manifest-sha256:236613658a40c126080b5a2c0d71564
    ..
    ..
    $ nerdctl images
    REPOSITORY     TAG       IMAGE ID        CREATED        PLATFORM       SIZE         BLOB SIZE
    jeanile/php    test      236613658a40    2 weeks ago    linux/amd64    565.4 MiB    166.6 MiB
    

    nerdctl 和 docker 命令差不都,删除测试的镜像,然后准备下一步操作。

    helm

    在宿主机和 K8s 集群的 master 节点安装

    宿主机下进入项目中,执行创建 helm 目录

    $ mkdir .helm && cd .helm
    $ helm create hyperf-learn # hyperf-learn 为项目名称
    

    执行完成后查看目录结构

    $ tree .helm
    .helm/
    └── hyperf-learn
        ├── Chart.yaml
        ├── templates
        │   ├── deployment.yaml
        │   ├── _helpers.tpl
        │   ├── hpa.yaml
        │   ├── ingress.yaml
        │   ├── NOTES.txt
        │   ├── serviceaccount.yaml
        │   ├── service.yaml
        │   └── tests
        │       └── test-connection.yaml
        └── values.yaml
    

    其中 templates 目录下的是一些常用的 K8s 资源 yaml 模版,values.yaml 则是填写一些镜像、configMap、端口等值,values.yaml 的值会需要覆盖到 templates 目录各个 yaml 下,并且 values.yaml 可以有多个,区分不同环境。

    更改 helm 中的 yaml

    values.yaml

    replicaCount: 1
    
    image:
    - repository: 
    + repository: jeanile/hyperf-learn
      pullPolicy: Always
      # Overrides the image tag whose default is the chart appVersion.
    - tag: ""
    + tag: "8.1-alpine-sw4.8.8"
    ..
    ..
    

    将构建结果输出到 log 查看:

    $ helm upgrade --install --debug --dry-run hyperf-learn .helm/hyperf-learn > helm.log 
    

    处理集群报错

    当提示:「Error: Kubernetes cluster unreachable: Get "http://localhost:8080/version?timeout=32s": dial tcp [::1]:8080: connect: connection refused」

    原因是因为 helm v3 版本不再需要 Tiller,而是直接访问 ApiServer 来与 k8s 交互,通过环境变量 KUBECONFIG 来读取存有 ApiServre 的地址与 token 的配置文件地址,默认地址为 ~/.kube/config,因此需要进行更改 KUBECONFIG 环境变量

    $ vim/etc/profile
    # 最后一行加入
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    
    $ source /etc/profile
    

    创建命名空间

    进入集群内部创建项目的命名空间

    $ kubectl create namespace hyperf-learn
    

    构建自动化脚本

    echo "开始部署"
    projectName="hyperf-learn" # 项目名称
    branchName="main" # 分支名称
    env="release" # 发布环境
    k8sHost="106.55.37.187"  #k8s集群的master节点ip 
    k8sUser="root" # k8s集群的master节点的登录账号
    k8sDeployPath="/usr/local/k8s/" # k8s集群的部署目录
    latestCommitID=$(git rev-parse --short HEAD)  # 最近一次提交id
    workDir="${k8sDeployPath}${projectName}" # 发布操作的工作目录
    imageName="jeanile/${projectName}:${branchName}-${latestCommitID}" # 进行名
    k8sNamespace="hyperf-learn"
    helmValues="values.yaml"
    
    # 上传文件到k8s服务器
    rsync -r ./* ${k8sUser}@${k8sHost}:${workDir}
    
    ssh ${k8sUser}@${k8sHost} <<eof
    # 跳转到工作目录
    cd ${workDir}
    # 构建镜像
    nerdctl build -t ${imageName} .
    # 登录镜像并推送进行
    cat /usr/local/password/dockerhub | nerdctl login -u jeanile --password-stdin 
    #推送进行
    nerdctl push ${imageName}
    # 删除本地镜像
    nerdctl rmi ${imageName}
    # 退出登录镜像服务器
    nerdctl logout
    
    # 构建部署文件并部署
    helm upgrade --install --set image.tag=${branchName}-${latestCommitID} -n ${k8sNamespace} ${projectName} .helm/${projectName}/ --values=.helm/${projectName}/${helmValues}
    
    # 清空当前目录下的所有文件
    rm -rf *
    # 退出
    exit
    eof
    echo "部署完成"
    

    其中主要使用 helm 部署,参数解释:

    • --kube-context:

    • --set image.tag:需要部署的镜像名称

    • -n:选择命名空间

    • --values:指定部署的 values,可以有多个 values 区分环境

    部署完成后,查看对应命名空间下的资源:

    $ kubectl get all -n hyperf-learn
    NAME                                READY   STATUS    RESTARTS   AGE
    pod/hyperf-learn-67894b5886-bctjw   1/1     Running   0          9m48s
    
    NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/hyperf-learn   ClusterIP   10.43.92.237   <none>        9501/TCP   9m48s
    
    NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/hyperf-learn   1/1     1            1           9m48s
    
    NAME                                      DESIRED   CURRENT   READY   AGE
    replicaset.apps/hyperf-learn-67894b5886   1         1         1       9m48s
    

    如果都是 READY 为 1/1 说明没问题了,之前演示为了简单,没有设置对外暴漏的端口,此处可以手动暴漏端口:

    $ kubectl expose pod -n hyperf-learn hyperf-learn-67894b5886-bctjw --type=LoadBalancer --port=9501
    service/hyperf-learn-67894b5886-bctjw exposed
    

    之后通过浏览器访问:

    相关文章

      网友评论

        本文标题:持续集成与部署(一)

        本文链接:https://www.haomeiwen.com/subject/avcxtdtx.html