package devopsmodules import ( "rubric/utils" ) var CicdModule = Module{ Key: "cicd", Aliases: []string{"ci", "cd", "pipeline"}, Title: "CI/CD — непрерывная интеграция и доставка", Description: "GitHub Actions, GitLab CI, Jenkins, принципы CI/CD", Run: showCicd, } func showCicd() { utils.Header("DevOps — CI/CD") utils.Section("Принципы CI/CD") utils.Code(`CI (Continuous Integration) — непрерывная интеграция: - Разработчики часто коммитят в общую ветку - Автоматически запускаются: сборка, тесты, линтинг - Быстрая обратная связь (< 10 минут) CD (Continuous Delivery) — непрерывная доставка: - Код всегда готов к деплою - Деплой в staging автоматически - В продакшн — одним кликом или автоматически Типичный пайплайн: Коммит → Lint → Test → Build → Security scan → Deploy staging → Deploy prod Метрики: Lead time — время от коммита до продакшна Deploy freq — частота деплоев MTTR — среднее время восстановления Change fail % — процент неудачных деплоев`) utils.Section("GitHub Actions") utils.Code(`# .github/workflows/ci.yml name: CI/CD on: push: branches: [main, develop] pull_request: branches: [main] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_PASSWORD: secret options: >- --health-cmd pg_isready --health-interval 10s steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.22' cache: true - name: Run tests run: go test -v -race -coverprofile=coverage.out ./... - name: Upload coverage uses: codecov/codecov-action@v4 lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: golangci/golangci-lint-action@v4 build-and-push: needs: [test, lint] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - name: Log in to registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v5 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max deploy: needs: build-and-push runs-on: ubuntu-latest environment: production # требует ручного подтверждения steps: - name: Deploy to Kubernetes uses: azure/k8s-deploy@v4 with: manifests: k8s/ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}`) utils.Println(utils.ColorBold + "GitHub Actions — ключевые концепции:" + utils.ColorReset) utils.Code(`Workflow — файл в .github/workflows/*.yml Job — набор шагов, запускается на runner Step — команда или action Runner — виртуальная машина (ubuntu/windows/macos) Action — переиспользуемый step (uses: actions/checkout@v4) Secret — зашифрованные переменные (Settings → Secrets) Environment — защищённая среда с approval (production, staging) Matrix — параллельный запуск с разными параметрами: strategy: matrix: go: ['1.21', '1.22'] os: [ubuntu-latest, macos-latest]`) utils.Section("GitLab CI/CD") utils.Code(`# .gitlab-ci.yml stages: - test - build - deploy variables: DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA test: stage: test image: golang:1.22 script: - go test ./... - go vet ./... coverage: '/coverage: \d+\.\d+%/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage.xml build: stage: build image: docker:24 services: - docker:24-dind before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - docker build -t $DOCKER_IMAGE . - docker push $DOCKER_IMAGE only: - main deploy_staging: stage: deploy script: - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE environment: name: staging url: https://staging.example.com only: - main deploy_prod: stage: deploy script: - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE environment: name: production url: https://example.com when: manual # ручной запуск only: - main`) utils.Println(utils.ColorBold + "Встроенные переменные GitLab CI:" + utils.ColorReset) utils.Code(`CI_COMMIT_SHA — полный SHA коммита CI_COMMIT_SHORT_SHA — короткий SHA CI_COMMIT_BRANCH — ветка CI_COMMIT_TAG — тег (если есть) CI_REGISTRY — адрес реестра (registry.gitlab.com) CI_REGISTRY_IMAGE — полный путь образа CI_PROJECT_NAME — имя проекта CI_ENVIRONMENT_NAME — имя окружения`) utils.Section("Jenkins") utils.Code(`// Jenkinsfile (Declarative Pipeline): pipeline { agent any environment { DOCKER_CREDS = credentials('docker-hub') KUBECONFIG = credentials('kubeconfig-prod') } stages { stage('Checkout') { steps { checkout scm } } stage('Test') { steps { sh 'go test ./...' } post { always { junit 'test-results.xml' } } } stage('Build') { steps { sh """ docker build -t myapp:${env.BUILD_NUMBER} . docker tag myapp:${env.BUILD_NUMBER} myrepo/myapp:latest """ } } stage('Push') { steps { sh """ echo $DOCKER_CREDS_PSW | docker login -u $DOCKER_CREDS_USR --password-stdin docker push myrepo/myapp:${env.BUILD_NUMBER} """ } } stage('Deploy') { when { branch 'main' } steps { input message: 'Деплоить в продакшн?' sh "kubectl set image deployment/myapp myapp=myrepo/myapp:${env.BUILD_NUMBER}" } } } post { failure { slackSend channel: '#alerts', message: "FAILED: ${env.JOB_NAME} ${env.BUILD_NUMBER}" } success { slackSend channel: '#deployments', message: "DEPLOYED: ${env.JOB_NAME} ${env.BUILD_NUMBER}" } } }`) utils.Section("ArgoCD — GitOps") utils.Code(`GitOps — Git как единственный источник истины для инфраструктуры. ArgoCD наблюдает за Git-репозиторием и синхронизирует кластер. # Установка: kubectl create namespace argocd kubectl apply -n argocd -f \ https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml # CLI: argocd login argocd.example.com # Создать приложение: argocd app create myapp \ --repo https://github.com/user/myapp \ --path k8s/ \ --dest-server https://kubernetes.default.svc \ --dest-namespace production \ --sync-policy automated \ --auto-prune argocd app list argocd app sync myapp argocd app rollback myapp 3`) utils.Footer() }