Files
DevOpsLab/docs/cicd-setup.md
Сергей Антропов 3f3507e079
Some checks failed
Ansible Testing / lint (push) Has been cancelled
Ansible Testing / test (default) (push) Has been cancelled
Ansible Testing / test (minimal) (push) Has been cancelled
Ansible Testing / test (performance) (push) Has been cancelled
Ansible Testing / deploy-check (push) Has been cancelled
refactor: переименование проекта из AnsibleTemplate в AnsibleLab
- Обновлены все упоминания AnsibleTemplate на AnsibleLab
- Изменены название проекта в README.md, Makefile и документации
- Обновлены комментарии в CI/CD конфигурациях

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-10-26 01:02:21 +03:00

22 KiB
Raw Blame History

Настройка CI/CD для AnsibleLab

Автор: Сергей Антропов
Сайт: https://devops.org.ru

🚀 GitHub Actions

Базовая конфигурация

.github/workflows/ansible-test.yml:

name: Ansible Testing
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: |
          pip install ansible ansible-lint
          ansible-galaxy collection install -r requirements.yml
      - name: Run lint
        run: make role lint

  test:
    runs-on: ubuntu-latest
    needs: lint
    strategy:
      matrix:
        preset: [minimal, default, performance]
    steps:
      - uses: actions/checkout@v4
      - name: Setup Docker
        run: |
          sudo systemctl start docker
          sudo usermod -aG docker $USER
      - name: Run tests
        run: make role test ${{ matrix.preset }}

  deploy-check:
    runs-on: ubuntu-latest
    needs: [lint, test]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: Check deployment
        run: make role deploy
        env:
          ANSIBLE_HOST_KEY_CHECKING: false

Продвинутая конфигурация

.github/workflows/ansible-advanced.yml:

name: Advanced Ansible Testing
on: [push, pull_request]

env:
  ANSIBLE_FORCE_COLOR: 'true'
  DOCKER_TLS_CERTDIR: ''

jobs:
  detect-roles:
    runs-on: ubuntu-latest
    outputs:
      roles: ${{ steps.detect.outputs.roles }}
    steps:
      - uses: actions/checkout@v4
      - name: Detect new roles
        id: detect
        run: |
          echo "roles=$(find roles/ -name 'main.yml' -path '*/tasks/*' | sed 's|roles/||; s|/tasks/main.yml||' | tr '\n' ' ')" >> $GITHUB_OUTPUT

  update-playbooks:
    runs-on: ubuntu-latest
    needs: detect-roles
    steps:
      - uses: actions/checkout@v4
      - name: Update playbooks
        run: |
          chmod +x scripts/update-playbooks.sh
          ./scripts/update-playbooks.sh
      - name: Commit changes
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git add molecule/default/site.yml roles/deploy.yml
          git diff --staged --quiet || git commit -m "Auto-update playbooks for new roles"
          git push

  lint:
    runs-on: ubuntu-latest
    needs: update-playbooks
    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: |
          pip install ansible ansible-lint
          ansible-galaxy collection install -r requirements.yml
      - name: Run lint
        run: make role lint

  test:
    runs-on: ubuntu-latest
    needs: [update-playbooks, lint]
    strategy:
      matrix:
        preset: [minimal, default, performance]
    steps:
      - uses: actions/checkout@v4
      - name: Setup Docker
        run: |
          sudo systemctl start docker
          sudo usermod -aG docker $USER
      - name: Run tests
        run: make role test ${{ matrix.preset }}

  deploy-check:
    runs-on: ubuntu-latest
    needs: [lint, test]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: Check deployment
        run: make role deploy
        env:
          ANSIBLE_HOST_KEY_CHECKING: false

  notify:
    runs-on: ubuntu-latest
    needs: [lint, test, deploy-check]
    if: always()
    steps:
      - name: Notify on success
        if: needs.lint.result == 'success' && needs.test.result == 'success'
        run: |
          echo "✅ All tests passed for new roles"
          curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"✅ Ansible role tests passed for new roles"}' \
            ${{ secrets.SLACK_WEBHOOK_URL }}
      - name: Notify on failure
        if: needs.lint.result == 'failure' || needs.test.result == 'failure'
        run: |
          echo "❌ Tests failed for new roles"
          curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"❌ Ansible role tests failed for new roles"}' \
            ${{ secrets.SLACK_WEBHOOK_URL }}

🏢 Azure DevOps

Базовая конфигурация

azure-pipelines.yml:

trigger:
- main
- develop

pool:
  vmImage: 'ubuntu-latest'

variables:
  ANSIBLE_FORCE_COLOR: 'true'
  DOCKER_TLS_CERTDIR: ''

stages:
- stage: Lint
  displayName: 'Lint Stage'
  jobs:
  - job: LintJob
    displayName: 'Run Lint'
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.11'
    - script: |
        pip install ansible ansible-lint
        ansible-galaxy collection install -r requirements.yml
        make role lint
      displayName: 'Run Ansible Lint'

- stage: Test
  displayName: 'Test Stage'
  dependsOn: Lint
  jobs:
  - job: TestJob
    displayName: 'Run Tests'
    strategy:
      matrix:
        minimal:
          preset: minimal
        default:
          preset: default
        performance:
          preset: performance
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.11'
    - script: |
        pip install ansible ansible-lint
        ansible-galaxy collection install -r requirements.yml
        make role test $(preset)
      displayName: 'Run Molecule Tests'
      env:
        PRESET: $(preset)

- stage: Deploy
  displayName: 'Deploy Stage'
  dependsOn: Test
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  jobs:
  - job: DeployJob
    displayName: 'Check Deployment'
    steps:
    - script: make role deploy
      displayName: 'Check Deployment'
      env:
        ANSIBLE_HOST_KEY_CHECKING: false

Продвинутая конфигурация

azure-pipelines-advanced.yml:

trigger:
- main
- develop

pool:
  vmImage: 'ubuntu-latest'

variables:
  ANSIBLE_FORCE_COLOR: 'true'
  DOCKER_TLS_CERTDIR: ''

stages:
- stage: Detect
  displayName: 'Detect Roles'
  jobs:
  - job: DetectJob
    displayName: 'Detect New Roles'
    steps:
    - script: |
        echo "##vso[task.setvariable variable=roles;isOutput=true]$(find roles/ -name 'main.yml' -path '*/tasks/*' | sed 's|roles/||; s|/tasks/main.yml||' | tr '\n' ' ')"
      displayName: 'Detect Roles'
      name: detect

- stage: Update
  displayName: 'Update Playbooks'
  dependsOn: Detect
  jobs:
  - job: UpdateJob
    displayName: 'Update Playbooks'
    steps:
    - script: |
        chmod +x scripts/update-playbooks.sh
        ./scripts/update-playbooks.sh
      displayName: 'Update Playbooks'
    - script: |
        git config --local user.email "action@azure.com"
        git config --local user.name "Azure DevOps"
        git add molecule/default/site.yml deploy.yml
        git diff --staged --quiet || git commit -m "Auto-update playbooks for new roles"
        git push
      displayName: 'Commit Changes'

- stage: Lint
  displayName: 'Lint Stage'
  dependsOn: Update
  jobs:
  - job: LintJob
    displayName: 'Run Lint'
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.11'
    - script: |
        pip install ansible ansible-lint
        ansible-galaxy collection install -r requirements.yml
        make role lint
      displayName: 'Run Ansible Lint'

- stage: Test
  displayName: 'Test Stage'
  dependsOn: [Update, Lint]
  jobs:
  - job: TestJob
    displayName: 'Run Tests'
    strategy:
      matrix:
        minimal:
          preset: minimal
        default:
          preset: default
        performance:
          preset: performance
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '3.11'
    - script: |
        pip install ansible ansible-lint
        ansible-galaxy collection install -r requirements.yml
        make role test $(preset)
      displayName: 'Run Molecule Tests'
      env:
        PRESET: $(preset)

- stage: Deploy
  displayName: 'Deploy Stage'
  dependsOn: [Lint, Test]
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  jobs:
  - job: DeployJob
    displayName: 'Check Deployment'
    steps:
    - script: make role deploy
      displayName: 'Check Deployment'
      env:
        ANSIBLE_HOST_KEY_CHECKING: false

- stage: Notify
  displayName: 'Notification Stage'
  dependsOn: [Lint, Test, Deploy]
  condition: always()
  jobs:
  - job: NotifyJob
    displayName: 'Send Notifications'
    steps:
    - script: |
        if [ "$(Lint.result)" == "Succeeded" ] && [ "$(Test.result)" == "Succeeded" ]; then
          echo "✅ All tests passed for new roles"
          curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"✅ Ansible role tests passed for new roles"}' \
            $(SLACK_WEBHOOK_URL)
        else
          echo "❌ Tests failed for new roles"
          curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"❌ Ansible role tests failed for new roles"}' \
            $(SLACK_WEBHOOK_URL)
        fi
      displayName: 'Send Notifications'
      env:
        SLACK_WEBHOOK_URL: $(SLACK_WEBHOOK_URL)

🏭 Jenkins

Базовая конфигурация

Jenkinsfile:

pipeline {
    agent any
    
    environment {
        ANSIBLE_FORCE_COLOR = 'true'
        DOCKER_TLS_CERTDIR = ''
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Install Dependencies') {
            steps {
                sh '''
                    pip install --upgrade pip
                    pip install ansible ansible-lint
                    ansible-galaxy collection install -r requirements.yml
                '''
            }
        }
        
        stage('Lint') {
            steps {
                sh 'make role lint'
            }
        }
        
        stage('Test') {
            parallel {
                stage('Test Minimal') {
                    steps {
                        sh 'make role test minimal'
                    }
                }
                stage('Test Default') {
                    steps {
                        sh 'make role test default'
                    }
                }
                stage('Test Performance') {
                    steps {
                        sh 'make role test performance'
                    }
                }
            }
        }
        
        stage('Deploy Check') {
            when {
                branch 'main'
            }
            steps {
                sh 'make role deploy'
            }
        }
    }
    
    post {
        always {
            archiveArtifacts artifacts: 'molecule/**/.molecule/**/*', allowEmptyArchive: true
        }
        
        success {
            echo 'Pipeline completed successfully!'
        }
        
        failure {
            echo 'Pipeline failed!'
        }
    }
}

Продвинутая конфигурация

Jenkinsfile-advanced:

pipeline {
    agent any
    
    environment {
        ANSIBLE_FORCE_COLOR = 'true'
        DOCKER_TLS_CERTDIR = ''
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Detect Roles') {
            steps {
                script {
                    env.ROLES = sh(
                        script: 'find roles/ -name "main.yml" -path "*/tasks/*" | sed "s|roles/||; s|/tasks/main.yml||" | tr "\\n" " "',
                        returnStdout: true
                    ).trim()
                }
                echo "Detected roles: ${env.ROLES}"
            }
        }
        
        stage('Update Playbooks') {
            steps {
                sh '''
                    chmod +x scripts/update-playbooks.sh
                    ./scripts/update-playbooks.sh
                '''
                sh '''
                    git config --local user.email "jenkins@example.com"
                    git config --local user.name "Jenkins"
                    git add molecule/default/site.yml roles/deploy.yml
                    git diff --staged --quiet || git commit -m "Auto-update playbooks for new roles"
                    git push
                '''
            }
        }
        
        stage('Install Dependencies') {
            steps {
                sh '''
                    pip install --upgrade pip
                    pip install ansible ansible-lint
                    ansible-galaxy collection install -r requirements.yml
                '''
            }
        }
        
        stage('Lint') {
            steps {
                sh 'make role lint'
            }
        }
        
        stage('Test') {
            parallel {
                stage('Test Minimal') {
                    steps {
                        sh 'make role test minimal'
                    }
                }
                stage('Test Default') {
                    steps {
                        sh 'make role test default'
                    }
                }
                stage('Test Performance') {
                    steps {
                        sh 'make role test performance'
                    }
                }
            }
        }
        
        stage('Deploy Check') {
            when {
                branch 'main'
            }
            steps {
                sh 'make role deploy'
            }
        }
    }
    
    post {
        always {
            archiveArtifacts artifacts: 'molecule/**/.molecule/**/*', allowEmptyArchive: true
        }
        
        success {
            echo 'Pipeline completed successfully!'
            script {
                if (env.SLACK_WEBHOOK_URL) {
                    sh '''
                        curl -X POST -H 'Content-type: application/json' \
                          --data '{"text":"✅ Ansible role tests passed for new roles"}' \
                          ${SLACK_WEBHOOK_URL}
                    '''
                }
            }
        }
        
        failure {
            echo 'Pipeline failed!'
            script {
                if (env.SLACK_WEBHOOK_URL) {
                    sh '''
                        curl -X POST -H 'Content-type: application/json' \
                          --data '{"text":"❌ Ansible role tests failed for new roles"}' \
                          ${SLACK_WEBHOOK_URL}
                    '''
                }
            }
        }
    }
}

🦊 GitLab CI

Базовая конфигурация

.gitlab-ci.yml:

stages:
  - lint
  - test
  - deploy

variables:
  ANSIBLE_FORCE_COLOR: "true"
  DOCKER_TLS_CERTDIR: ""

lint:
  stage: lint
  image: python:3.11
  before_script:
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role lint

test:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_TLS_CERTDIR: ""
  before_script:
    - apk add --no-cache make python3 py3-pip
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role test $PRESET
  parallel:
    matrix:
      - PRESET: [minimal, default, performance]

deploy:
  stage: deploy
  image: python:3.11
  only:
    - main
  before_script:
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role deploy
  variables:
    ANSIBLE_HOST_KEY_CHECKING: "false"

Продвинутая конфигурация

.gitlab-ci-advanced.yml:

stages:
  - detect
  - update
  - lint
  - test
  - deploy
  - notify

variables:
  ANSIBLE_FORCE_COLOR: "true"
  DOCKER_TLS_CERTDIR: ""

detect-roles:
  stage: detect
  image: alpine:latest
  script:
    - echo "ROLES=$(find roles/ -name 'main.yml' -path '*/tasks/*' | sed 's|roles/||; s|/tasks/main.yml||' | tr '\n' ' ')" >> build.env
  artifacts:
    reports:
      dotenv: build.env

update-playbooks:
  stage: update
  image: alpine:latest
  script:
    - apk add --no-cache make bash
    - chmod +x scripts/update-playbooks.sh
    - ./scripts/update-playbooks.sh
    - git config --local user.email "gitlab@example.com"
    - git config --local user.name "GitLab CI"
    - git add molecule/default/site.yml deploy.yml
    - git diff --staged --quiet || git commit -m "Auto-update playbooks for new roles"
    - git push
  only:
    - main
    - develop

lint:
  stage: lint
  image: python:3.11
  before_script:
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role lint

test:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_TLS_CERTDIR: ""
  before_script:
    - apk add --no-cache make python3 py3-pip
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role test $PRESET
  parallel:
    matrix:
      - PRESET: [minimal, default, performance]

deploy:
  stage: deploy
  image: python:3.11
  only:
    - main
  before_script:
    - pip install ansible ansible-lint
    - ansible-galaxy collection install -r requirements.yml
  script:
    - make role deploy
  variables:
    ANSIBLE_HOST_KEY_CHECKING: "false"

notify:
  stage: notify
  image: alpine:latest
  script:
    - |
      if [ "$CI_JOB_STATUS" == "success" ]; then
        echo "✅ All tests passed for new roles"
        curl -X POST -H 'Content-type: application/json' \
          --data '{"text":"✅ Ansible role tests passed for new roles"}' \
          ${SLACK_WEBHOOK_URL}
      else
        echo "❌ Tests failed for new roles"
        curl -X POST -H 'Content-type: application/json' \
          --data '{"text":"❌ Ansible role tests failed for new roles"}' \
          ${SLACK_WEBHOOK_URL}
      fi
  when: always
  variables:
    SLACK_WEBHOOK_URL: $SLACK_WEBHOOK_URL

🔔 Настройка уведомлений

Slack уведомления

# .github/workflows/notifications.yml
name: Notifications
on: [workflow_run]

jobs:
  notify:
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Notify Slack
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          channel: '#ansible'
          webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}

Teams уведомления

# .github/workflows/teams-notifications.yml
name: Teams Notifications
on: [workflow_run]

jobs:
  notify:
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Notify Teams
        uses: skitionek/notify-microsoft-teams@master
        with:
          webhook_url: ${{ secrets.TEAMS_WEBHOOK_URL }}
          status: ${{ job.status }}
          title: 'Ansible Role Tests'

📊 Мониторинг CI/CD

Метрики производительности

# .github/workflows/metrics.yml
name: CI/CD Metrics
on: [workflow_run]

jobs:
  metrics:
    runs-on: ubuntu-latest
    steps:
      - name: Collect Metrics
        run: |
          echo "Build time: $(date)"
          echo "Commit: ${{ github.sha }}"
          echo "Branch: ${{ github.ref }}"
          echo "Actor: ${{ github.actor }}"

Отчеты о тестировании

# .github/workflows/reports.yml
name: Test Reports
on: [workflow_run]

jobs:
  reports:
    runs-on: ubuntu-latest
    steps:
      - name: Generate Report
        run: |
          echo "## Test Results" >> $GITHUB_STEP_SUMMARY
          echo "- Lint: ✅ Passed" >> $GITHUB_STEP_SUMMARY
          echo "- Test: ✅ Passed" >> $GITHUB_STEP_SUMMARY
          echo "- Deploy: ✅ Passed" >> $GITHUB_STEP_SUMMARY

🔧 Настройка секретов

GitHub Secrets

# Настройка секретов в GitHub
gh secret set SLACK_WEBHOOK_URL --body "https://hooks.slack.com/services/..."
gh secret set TEAMS_WEBHOOK_URL --body "https://outlook.office.com/webhook/..."

Azure DevOps Variables

# azure-pipelines.yml
variables:
  - group: ansible-secrets
  - name: SLACK_WEBHOOK_URL
    value: $(SLACK_WEBHOOK_URL)

Jenkins Credentials

// Jenkinsfile
pipeline {
    agent any
    environment {
        SLACK_WEBHOOK_URL = credentials('slack-webhook-url')
    }
    // ... остальная конфигурация
}

🚀 Автоматизация

Автоматическое создание скриптов

#!/bin/bash
# scripts/setup-cicd.sh
# Автоматическая настройка CI/CD

echo "🔧 Настройка CI/CD для AnsibleLab..."

# Создание директории .github/workflows
mkdir -p .github/workflows

# Создание базового workflow
cat > .github/workflows/ansible-test.yml << 'EOF'
name: Ansible Testing
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: make role test
EOF

# Создание Azure DevOps pipeline
cat > azure-pipelines.yml << 'EOF'
trigger:
- main
pool:
  vmImage: 'ubuntu-latest'
stages:
- stage: Test
  jobs:
  - job: TestJob
    steps:
    - script: make role test
EOF

# Создание Jenkinsfile
cat > Jenkinsfile << 'EOF'
pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'make role test'
            }
        }
    }
}
EOF

# Создание GitLab CI
cat > .gitlab-ci.yml << 'EOF'
stages:
  - test
test:
  stage: test
  script:
    - make role test
EOF

echo "✅ CI/CD настроен"

Автор: Сергей Антропов
Сайт: https://devops.org.ru