Telegram
+998 (71) 205-80-00

CI/CD: деплой в кластер Kubernetes serverplus

Опубликовано: 25.07.26
Поделиться

Идея

Доступ к кластеру (kubeconfig) кладётся в секреты CI, а пайплайн запускает kubectl apply при каждом пуше. Ниже — как это устроить в GitLab CI и GitHub Actions для кластера Kubernetes в serverplus, и как сделать это безопасно, не раздавая admin-доступ.

Что кладём в секреты CI

  • kubeconfig кластера — в идеале не admin, а ограниченный (от ServiceAccount, см. ниже). Кодируем в base64 и сохраняем как маскированную переменную CI (KUBE_CONFIG).
  • application credential id/secret — только если пайплайн трогает саму инфраструктуру OpenStack (например, через Terraform).
# get kubeconfig and encode it for the CI secret
openstack coe cluster config my-cluster
base64 -w0 ./config    # result -> KUBE_CONFIG variable

Никогда не коммитьте kubeconfig в репозиторий. Только маскированные секреты CI. Один файл kubeconfig — это полный доступ к кластеру.

Ограниченный доступ (ServiceAccount + RBAC)

Вместо admin-kubeconfig заведите сервис-аккаунт с правами только в одном namespace:

kubectl create namespace app
kubectl -n app create serviceaccount deployer
kubectl -n app create rolebinding deployer-edit \
  --clusterrole=edit --serviceaccount=app:deployer

# short-lived token for this account
kubectl -n app create token deployer --duration=24h

На основе этого токена и адреса кластера собирается отдельный kubeconfig для CI — он может менять только namespace app.

GitLab CI

.gitlab-ci.yml — деплой при пуше в main:

deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - echo "$KUBE_CONFIG" | base64 -d > kubeconfig
    - export KUBECONFIG=$PWD/kubeconfig
    - kubectl -n app apply -f k8s/
    - kubectl -n app rollout status deployment/web
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

KUBE_CONFIG задаётся в Settings → CI/CD → Variables как masked переменная (base64 от kubeconfig).

GitHub Actions

.github/workflows/deploy.yml:

name: deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: kubeconfig
        run: |
          echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
          echo "KUBECONFIG=$PWD/kubeconfig" >> $GITHUB_ENV
      - name: deploy
        run: |
          kubectl -n app apply -f k8s/
          kubectl -n app rollout status deployment/web

KUBE_CONFIG добавляется в Settings → Secrets and variables → Actions.

Сборка и приватный реестр

Типичный полный цикл: собрать образ, запушить в реестр, обновить деплой.

docker build -t registry.example/web:$TAG .
docker push registry.example/web:$TAG
kubectl -n app set image deployment/web web=registry.example/web:$TAG

Если реестр приватный, добавьте в кластер imagePullSecret и укажите его в манифесте деплоя.

Безопасность

  • Не admin-kubeconfig. Отдельный ServiceAccount с ролью edit в одном namespace (RBAC) — компрометация раннера не даст доступ ко всему кластеру.
  • Только маскированные секреты CI, раздельные креды на окружения (stage/prod) и их ротация.
  • Ограничьте, кто запускает деплой: protected branches и protected environments.

Частые вопросы

kubectl: connection refused / timeout из пайплайна. В kubeconfig должен быть внешний адрес control plane (floating IP), а не внутренний 10.x. Раннер CI должен иметь сетевой доступ к этому адресу.

Ошибка «forbidden». Сервис-аккаунту не хватает прав в RBAC — проверьте rolebinding и namespace.

Ошибка сертификата x509. Устаревший kubeconfig (кластер пересоздавали). Сгенерируйте заново: openstack coe cluster config my-cluster --force.

Рекомендуем
Подберём лучшее решение под ваш проект
Заполните данные и с вами свяжется менеджер для подтверждения
Номер тех. поддержки
+998 (71) 205-80-00
Email для связи
info@serverplus.uz
Часы работы
Как вам удобнее получить консультацию?
Что вас интересует? (необязательно)
Подпишитесь на нашу рассылку

Будьте одними из первых, кто узнает новости из сферы хостингов