建立好CI/CD的流程,除了可以减少人工的操作之外,也能透过安排好的测试等排程来让专案更加的稳定。现在也有不同的服务来帮助建立CI/CD流程,例如GitLab还有今天要介绍的bitbucket pipelines

在进入大纲以前,先说明想要建立的自动化部署流程

主机在main branch中透git push将程式码push到bitbucket上bitbucket根据设置的pipelines.yml,先建立虚拟环境进行程式码的测试测试通过后,使用SSH连接到远端主机,进到专案目录根据专案目录的docker配置删除旧容器,建立新的容器完成部署而这篇文章的重点会放在bitbucket想要使用SSH操作远端主机时需要注意的地方,而不是yml本身,所以今天重点都在如何完成第一到第三步的过程

文章大纲

  • 流程说明
  • 实际操作流程
    • 远端主机配置
    • Bitbucket配置
  • 总结
  • 流程说明

    首先我们从上面的Linode部分(远端主机)来看,因为需要操作专案、使用docker建立容器与操作git,所以我们需要建立具备相关权限的群组与用户。虽然在操作docker时很常需要用到root用户,但是建立一个具有操作docker权限的用户才是更安全的做法,而建立群组的好处是能将先前具有操作专案权限的用户纳入群组中

    为了要让Bitbucket能使用用户透过SSH连到远端主机,需要在sshd_config档案配置相关参数,以及将Bitbucket建立的公钥放到远端主机的authorized_keys档案中

    接着来看下图关于Bitbucket的配置,因为需要让远端主机能够操作git,所以要将远端主机的public key放到Bitbucket的Access keys配置中。并且我们需要在Bitbucket中配置SSH密钥(不论是自己生成,还是拿本机的来用都可以)。生产或是拿来的公钥,如同上段说的要拿去远端主机的authorized_keys档案,而私钥则是之后pipeline需要用在SSH登入时验证

    最后来提及Repository variables配置的部分,因为是使用ssh_run镜像,所以需要配置SSH_USER与SERVER才能让pipeline使用SSH登入。而SSH_KEY如果在前面的步骤已经配置在Bitbucket的设定中,这边可以不用填。而其他你需要在专案中用到的环境变数,如果是已经在远端主机的档案配置中的话,这边可以不用配置,我这边配置的是要给测试阶段时,此时环境是Bitbucket的独立虚拟环境,不会有远端主机配置好的环境变数,所以还是要补上。

    以上简单的介绍一下流程,如果觉得还有哪边觉得不是很清楚的话,可以看完底下详细的步骤后,再回来把整个流程梳理一次逻辑~

    实际操作流程

    远端主机配置

    • 确认远端主机是否有docker群组

    getent group docker
    # 如果有的话会显示
    docker:x:990:

    • 建立用户并设置密码(虽然之后是使用公钥,但还是可以配置密码)

    useradd -m -s /bin/bash <username> #建立用户
    passwd <username> # 修改密码

    • 给予用户能使用docker的权限

    usermod -aG docker <username>

    用户的部分配置好了,接着要建立群组为什么要建立群组?而不是直接把所有需要的权限丢到刚刚的用户就好了?因为远端主机的专案资料,不是只有这个部署的用户要使用,因此建立群组然后让其有专案资料的权限,最后再将用户们纳入群组之下

    • 建立专门的群组

    sudo groupadd <group_name>

    • 将用户添加到群组,这边除了刚刚建立的用户,也要把之前建立专案的用户纳入

    usermod -aG <group_name> <username>

    • 修改目录的群组拥有权,同时配置读取与执行权限,以及让新建立的档案自动继承父目录的群组

    chown :<group_name> <file_path>
    chmod g+rx <file_path>
    chmod g+s <file_path>

    这边要注意:要从绝对路径开始,直到专案目录的每一层都要配置,并且要注意.git的隐藏资料夹有没有套用到配置,没有的话会部署失败

    接下来我们要确认新建立的用户能够使用SSH连线

    sudo vim /etc/ssh/sshd_config

    并且确认这些参数

    PubkeyAuthentication yes # 表示能公钥连线
    PasswordAuthentication no # 不使用输入密码的方式登入
    AllowUsers <user_name> # 确认能用ssh连线

    最后来配置SSH密钥认证时需要的档案与权限

    • 建立.ssh目录,并且配置权限,使拥有者有读+写+执行权限

    mkdir -p /<root_path>/<username>/.ssh
    chown <username>:<username> /<root_path>/<username>/.ssh
    chmod 700 /<root_path>/<username>/.ssh

    • 在.ssh内建立authorized_keys档案,储存允许登入此用户的公钥

    touch /<root_path>/<username>/.ssh/authorized_keys
    chown <username>:<username> /<root_path>/<username>/.ssh/authorized_keys
    chmod 600 /<root_path>/<username>/.ssh/authorized_keys

    同时我们也在这里建立密钥,公钥之后要给Bitbucket的Access keys来使用远程仓库(repository)的权限

    ssh-keygen -t rsa -b 4096 -C ""

    在远端主机的工作就告一段落了,我们接着来配置Bitbucket

    Bitbucket配置

    先进到Repository settings中

    将刚刚的公钥(id_rsa)放到Bitbucket中

    接着我们要来配置Repository settings中的SSH Keys

    如果pipeline中需要使用多组SSH keys,那这边可能可以跳过,直接全部配置在Repository variables上。但是我们就只有一组要认证,所以可以直接配置在这里,后面的pipelines.yml可以省略一些步骤

    我这边因为有建立了所以长这样,如果是第一次新增也会有按钮让你新增

    不过输入Private key时要注意,一定要连第一行跟最后一行都输入进去

    -----BEGIN OPENSSH PRIVATE KEY-----
    xxxxxxxx
    -----END OPENSSH PRIVATE KEY-----

    然后用远端主机的ip来建立know host

    最后就来配置Repository variables

    其中根据官方提供的ssh-run镜像,SSH_USER跟SERVER是必须,其他的变数就根据自己需求来添加

    至于pipelines.yml本身大致上的架构如下,毕竟今天重点不是在他身上,就不多做赘述,读者再根据自己需求做调整

    pipelines:
    default:
    - step:
    name: Test
    image: python:3.12-slim
    caches:
    - pip
    script:
    - apt-get update && apt-get install -y gcc python3-dev
    # 这里是相对于 repo root
    - pip install -r <root_path>/requirements.txt
    - cd <file_path>
    - pytest -v

    - step:
    name: Deploy to Production
    deployment: production
    script:
    - pipe: atlassian/ssh-run:0.8.1
    variables:
    SSH_USER: $SSH_USER
    SERVER: $SERVER
    COMMAND: >
    set -e;
    echo "当前用户信息:" && whoami && groups;

    echo "开始尝试进入目录:" &&
    cd <file_path> &&
    echo "成功进入目标目录" &&
    pwd &&

    echo "开始执行部署步骤" &&
    docker-compose ps > previous_state.txt &&
    git pull origin main &&

    docker-compose --env-file ../.env down &&
    docker-compose --env-file ../.env build &&
    docker-compose --env-file ../.env up -d &&

    if ! docker-compose ps | grep -q "web.*Up"; then
    echo "部署失败,正在回滚..." &&
    docker-compose down &&
    cat previous_state.txt &&
    exit 1;
    fi &&
    docker system prune -f --volumes &&
    echo "部署完成!"

    definitions:
    services:
    docker:
    memory: 256

    总结

    这是我第一次建立的CI/CD流程,中间失败了50次以上,主要都是卡在对于权限的配置与SSH中远端主机与Bitbucket所扮演的角色定位不够了解,以及第一次写COMMAND,不知道要用&&而是傻傻用;

    整个流程大致上如下:

    • 配置远端主机的用户与群组之相关权限
    • 使该用户能用SSH连线
    • Bitbucket上配置SSH密钥用于SSH连线与配置变数来进行SSH登入

    虽然文中是使用Bitbucket,但是了解了相关流程后,使用其他服务也是能照着相同的逻辑去处理~

    参考资料

    https://support.atlassian.com/bitbucket-cloud/docs/set-up-pipelines-ssh-keys-on-linux/https://support.atlassian.com/bitbucket-cloud/docs/configure-ssh-and-two-step-verification/https://bitbucket.org/atlassian/ssh-run/src/master/?source=post_pagehttps://dev.to/manuelbosi/bitbucket-pipelines-configure-ssh-keys-1l56?source=post_page