Jenkins运维之路(Jenkins流水线改造Day02-3-容器项目)

59 阅读2分钟

上期已经将容器项目的告警补充完成,这期在补充下ansible的相关部署内容,项目我使用的是自建的运维测试项目。

1. Ansible 目录结构

# 代码目录结构
tree -L 3
.
├── Ansible # Ansible部署脚本目录
│   ├── HelloWorld-Pipeline  # 按Jenkins项目名建立playbook文件夹
│   │   ├── deploy.yml  # 部署脚本
│   │   ├── hosts # 主机清单
│   │   └── rollback.yml # 回滚脚本
│   └── Readme.md
├── Jenkinsfile
│   ├── Helloworld-Pipeline-DockerSlave.jenkinsfile
│   ├── HelloWorld-Pipeline.jenkinsfile
│   └── Readme.md
├── Readme.md
├── src
│   └── org
│       └── foo
└── vars
    └── Readme.md

2. Ansible部署脚本(deploy.yml)

---
- name: Deploy Docker container
  hosts: test
  become: yes
  vars:
    # 这些变量都会从Jenkins中传入
    new_image_name: "{{ new_image_name }}"
    container_name: "{{ container_name }}"
    docker_registry: "{{ docker_registry }}"  
    docker_username: "{{ docker_username }}" 
    docker_password: "{{ docker_password }}"
  tasks:
    - name: Login to Docker registry
      docker_login:
        registry: "{{ docker_registry }}"
        username: "{{ docker_username }}"
        password: "{{ docker_password }}"

    - name: Pull the latest Docker image
      docker_image:
        name: "{{ new_image_name }}"
        tag: latest
        source: pull

    - name: Stop and remove old container if exists
      docker_container:
        name: "{{ container_name }}"
        state: absent
      ignore_errors: yes  # 忽略错误,确保后续任务继续执行
      
    - name: Run new container
      docker_container:
        name: "{{ container_name }}"
        image: "{{ new_image_name }}"
        state: started
        restart_policy: always
        published_ports:
          - "8888:8080"  # 映射主机的8888端口到容器的8080端口
  
    - name: Remove unused Docker images
      command: docker image prune -f --filter "until=24h"  # 清理24小时内未使用的镜像,这个根据自己情况
      register: prune_result

3. Ansible部署脚本(rollback.yml)

---
- name: Deploy Docker container
  hosts: test
  become: yes
  vars:
    # 这些变量都会从Jenkins中传入
    new_image_name: "{{ rel_image_name }}"
    container_name: "{{ container_name }}"
    docker_registry: "{{ docker_registry }}"
    docker_username: "{{ docker_username }}"
    docker_password: "{{ docker_password }}"
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: Login to Docker registry
      docker_login:
        registry: "{{ docker_registry }}"
        username: "{{ docker_username }}"
        password: "{{ docker_password }}"

    - name: Pull the latest Docker image
      docker_image:
        name: "{{ rel_image_name }}"
        tag: latest
        source: pull

    - name: Stop and remove old container if exists
      docker_container:
        name: "{{ container_name }}"
        state: absent
      ignore_errors: yes
      
    - name: Run new container
      docker_container:
        name: "{{ container_name }}"
        image: "{{ rel_image_name }}"
        state: started
        restart_policy: always
        published_ports:
          - "8888:8080"
  
    - name: Remove unused Docker images
      command: docker image prune -f --filter "until=24h"
      register: prune_result

4. Hosts

[test]
192.168.1.98

5.Jenkins传入变量的代码片段(在前面2片文章有写)

pipeline {
  //.......省略
  stages {
  //.......省略
        //这里开始传入相关变量
        stage('Ansible Deploy') {
            steps {
                ansiColor('xterm') { // 启用 AnsiColor
                    echo "${PURPLE}Ansible 部署项目${RESET}"
                }
                script {
                    sh "git clone ${OPS_SHARE_LIBRARY} ./ops-share-librarya"
                    withCredentials([usernamePassword(credentialsId: 'Harbor', usernameVariable: 'HARBOR_USERNAME', passwordVariable: 'HARBOR_PASSWORD')]) {
                        def extraVars = [
                            container_name: "${CONTAINER_NAME}",
                            docker_registry: "${HARBOR_URL}",
                            docker_username: "${HARBOR_USERNAME}",
                            docker_password: "${HARBOR_PASSWORD}"
                        ].collectEntries { [(it.key): it.value] }
                
                        // 根据 BRANCH_TAG 的值添加特定的参数
                        if (!env.BRANCH_TAG.startsWith('rel-')) {
                            // 正常部署时添加的参数
                            extraVars['new_image_name'] = "${REGISTRY_URL}/${PROJECT_GROUP}/${PROJECT_NAME}:${_tag}"
                
                            // 执行正常的部署
                            ansiblePlaybook(
                                playbook: "./ops-share-librarya/Ansible/HelloWorld-Pipeline/deploy.yml",
                                inventory: "./ops-share-librarya/Ansible/HelloWorld-Pipeline/hosts",
                                extraVars: extraVars
                            )
                        } else {
                            def branchTag = env.BRANCH_TAG
                            def extractedValue = branchTag.replaceFirst(/^rel-/, '')  // 去掉前缀 "rel-"
                            println "Extracted Value: ${extractedValue}"  // 输出提取的值
                            // 回滚时添加的参数
                            extraVars['rel_image_name'] = "${REGISTRY_URL}/${PROJECT_GROUP}/${PROJECT_NAME}:${extractedValue}"
                
                            // 执行回滚
                            ansiblePlaybook(
                                playbook: "./ops-share-librarya/Ansible/HelloWorld-Pipeline/rollback.yml",
                                inventory: "./ops-share-librarya/Ansible/HelloWorld-Pipeline/hosts",
                                extraVars: extraVars
                            )
                        }
                    }
                }
            }
        }
        //.......省略
  }
}

6.部署测试

image-20250916184452063

image-20250916184452063

容器项目的相关流水线到这里基本都已经搞完了,目前完成了落项目部署和容器项目部署的流水线,但是这些也只是作为模板,后面还要优化迭代。