# Настройка CI/CD для AnsibleLab **Автор:** Сергей Антропов **Сайт:** https://devops.org.ru ## 🚀 GitHub Actions ### Базовая конфигурация **`.github/workflows/ansible-test.yml`:** ```yaml 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`:** ```yaml 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`:** ```yaml 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`:** ```yaml 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`:** ```groovy 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`:** ```groovy 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`:** ```yaml 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`:** ```yaml 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 уведомления ```yaml # .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 уведомления ```yaml # .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 ### Метрики производительности ```yaml # .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 }}" ``` ### Отчеты о тестировании ```yaml # .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 ```bash # Настройка секретов в 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 ```yaml # azure-pipelines.yml variables: - group: ansible-secrets - name: SLACK_WEBHOOK_URL value: $(SLACK_WEBHOOK_URL) ``` ### Jenkins Credentials ```groovy // Jenkinsfile pipeline { agent any environment { SLACK_WEBHOOK_URL = credentials('slack-webhook-url') } // ... остальная конфигурация } ``` ## 🚀 Автоматизация ### Автоматическое создание скриптов ```bash #!/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