Deploy to k8s with Spinnaker. Часть 1: Установка
Jan 24, 2019 11:59 · 1120 words · 6 minute read
Spinnaker - мультиоблачная платформа для непрерывной доставки (continuous delivery) с открытым исходным кодом (open-source) от разработчиков Netflix. Платформа предназначена для управления и деплоя приложений в AWS EC2, Kubernetes, GCE, GKE, GAE, Microsoft Azure и Openstack. Давайте разберемся!
Устанавливать Spinnaker будем в Kubernetes кластер с помощью утилиты Halyard (рекомендуемый способ установки). Для начала установим Halyard на локальный компьютер или VM (с Ubuntu 14.04/16.04, Debian, или macOS).
Примечание. Это также может быть docker-контейнер, но данный вариант установки рассматривать не будем.
В моем случае используется macOS (10.14.2 Mojave). Скачиваем последнюю версию установщика Halyard с помощью команды:
curl -O https://raw.githubusercontent.com/spinnaker/halyard/master/install/macos/InstallHalyard.sh
Устанавливаем утилиту:
sudo bash InstallHalyard.sh
Проверить корректность установки можно так:
hal -v
1.14.0-20190117020510
Примечание. Если команда завершается с ошибкой, убедитесь, что путь к исполняемому файлу hal
присутствует в переменной $PATH
.
Обновление Halyard можно вызвать командой:
sudo update-halyard
При необходимости удалить Halyard можно так:
sudo ~/.hal/uninstall.sh
Для установки Spinnaker далее следует определиться с облачным провайдером - все доступные варианты можно посмотреть тут, в моем случае будет использоваться вторая версия Kubernetes (Kubernetes Provider V2 (Manifest Based)). Сам Kubernetes кластер запущен на GKE (Google Kubernetes Engine).
Если у вас нет кластера на GKE, его необходимо создать с помощью консольной утилиты gcloud
или Cloud Console как описано в официальной документации. Также для этих целей можно использовать сторонние инструменты, например Terraform
.
Далее необходимо загрузить учетные данные для доступа к кластеру Kubernetes, например, как написано здесь.
Создаем отдельный сервис-аккаунт для Spinnaker и сгенерируем ему токен для доступа к кластеру Kubernetes:
CONTEXT=$(kubectl config current-context)
# This service account uses the ClusterAdmin role -- this is not necessary,
# more restrictive roles can by applied.
kubectl apply --context ${CONTEXT} \
-f https://spinnaker.io/downloads/kubernetes/service-account.yml
TOKEN=$(kubectl get secret --context ${CONTEXT} \
$(kubectl get serviceaccount spinnaker-service-account \
--context ${CONTEXT} \
-n spinnaker \
-o jsonpath='{.secrets[0].name}') \
-n spinnaker \
-o jsonpath='{.data.token}' | base64 --decode)
kubectl config set-credentials ${CONTEXT}-token-user --token ${TOKEN}
kubectl config set-context ${CONTEXT} --user ${CONTEXT}-token-user
По желанию также можно настроить RBAC (Role-Based Access Control) для сервис-аккаунта Spinnaker, например, создав файл spinnaker-role.yaml
с таким содержимым:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: spinnaker-role
rules:
- apiGroups: [""]
resources: ["namespaces", "configmaps", "events", "replicationcontrollers", "serviceaccounts", "pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods", "services", "secrets"]
verbs: ["create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["list", "get"]
- apiGroups: ["apps"]
resources: ["controllerrevisions", "statefulsets"]
verbs: ["list"]
- apiGroups: ["extensions", "apps"]
resources: ["deployments", "replicasets", "ingresses"]
verbs: ["create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"]
# These permissions are necessary for halyard to operate. We use this role also to deploy Spinnaker itself.
- apiGroups: [""]
resources: ["services/proxy", "pods/portforward"]
verbs: ["create", "delete", "deletecollection", "get", "list", "patch", "update", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: spinnaker-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: spinnaker-role
subjects:
- namespace: spinnaker
kind: ServiceAccount
name: spinnaker-service-account
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: spinnaker-service-account
namespace: spinnaker
и применив его с помощью команды:
kubectl apply -f spinnaker-role.yaml
Теперь можем в настройках Spinnaker’а включить поддержку Kubernetes V2 провайдера и добавить аккаунт(ы):
hal config provider kubernetes enable
CONTEXT=$(kubectl config current-context)
hal config provider kubernetes account add k8s-account \
--namespaces default \
--provider-version v2 \
--context ${CONTEXT}
Примечание. В терминологии Spinnaker аккаунт (account) соответствует контексту (context) Kubernetes кластера; имя аккаунта может отличаться от имени контекста.
В примере выше для взаимодействия с Kubernetes кластерами будет использоваться дефолтный kubeconfig - ~/.kube/config
. Можно явно указать путь к kubeconfig
с помощью параметра --kubeconfig-file
.
Также нужно включить поддержку артефактов:
hal config features edit --artifacts true
Особенно нас интересует возможность использования артефактов с GitHub (в моем примере артефакт - это манифест для k8s в формате .yaml
). Для доступа к репозиториям на GitHub Spinnaker’у понадобится токен, который можно сгенерировать здесь. Токену необходимы права доступа repo scope.
hal config artifact github enable
TOKEN=b82c0b5201e5........8d3f1288cb
echo ${TOKEN} | hal config artifact github account add spinnaker-github-token --token
Для хранения персистентных данных (настройки пайплайнов / приложений) Spinnaker’у требуется внешнее хранилище. Доступные варианты хранилищ можно посмотреть здесь, в моем же случае будет использоваться GCS (Google Cloud Storage).
Считаем, что у вас уже создан проект на GCP (Google Cloud Platform) и установлена утилита gcloud
.
Для аутентификации Spinnaker’а на GCP создадим сервис-аккаунт с включенной ролью roles/storage.admin
с помощью следующих команд:
SERVICE_ACCOUNT_NAME=spinnaker-gcs-account
SERVICE_ACCOUNT_DEST=~/.gcp/gcs-account.json
gcloud iam service-accounts create \
${SERVICE_ACCOUNT_NAME} \
--display-name ${SERVICE_ACCOUNT_NAME}
SA_EMAIL=$(gcloud iam service-accounts list \
--filter="displayName:${SERVICE_ACCOUNT_NAME}" \
--format='value(email)')
PROJECT=$(gcloud info --format='value(config.project)')
gcloud projects add-iam-policy-binding ${PROJECT} \
--role roles/storage.admin --member serviceAccount:${SA_EMAIL}
mkdir -p $(dirname ${SERVICE_ACCOUNT_DEST})
gcloud iam service-accounts keys create ${SERVICE_ACCOUNT_DEST} \
--iam-account ${SA_EMAIL}
Настраиваем внешнее хранилище для Spinnaker:
BUCKET_LOCATION=europe-west1
hal config storage gcs edit \
--project ${PROJECT} \
--bucket-location ${BUCKET_LOCATION} \
--bucket my-spinnaker-bucket \
--json-path ${SERVICE_ACCOUNT_DEST}
Включим и настроим поддержку docker-registry (необязательный шаг). В моем случае будут использоваться приватные docker-репозитории организации (Docker Private Organization Repository), и мне необходимо настроить триггер, который бы запускал пайплайн при появлении нового docker-образа в репозитории:
hal config provider docker-registry enable
PASS=Very$tr0ngPaS$
echo ${PASS} | hal config provider docker-registry account add private-dockerhub \
--provider-version v2 \
--address index.docker.io \
--repositories orgname/reponame-1 orgname/reponame-2 orgname/reponame-3 \
--username admin \
--password
Примечание. Так как Docker Hub не предоставляет ендпоинта catalog для автоматического получения списка docker репозиториев, их необходимо вручную указать с помощью параметра --repositories
.
Больше опций для более тонкой настройки docker registry можно найти здесь.
Стоит отметить, что при большом количестве тэгов в репозиториях docker registry (>1000) можно столкнуться с проблемой - микросервис igor
(подробнее о архитектуре Spinnaker можно узнать здесь) не будет видеть новые тэги и не сможет тригеррить пайплайны. В логах это будет выглядеть примерно так:
...
2019-01-22 12:59:55.923 INFO 1 --- [RxIoScheduler-3] c.n.s.i.d.service.ClouddriverService : ---> HTTP GET http://spin-clouddriver.spinnaker:7002/dockerRegistry/images/find?account=private-dockerhub
2019-01-22 12:59:55.992 INFO 1 --- [RxIoScheduler-3] c.n.s.i.d.service.ClouddriverService : <--- HTTP 200 http://spin-clouddriver.spinnaker:7002/dockerRegistry/images/find?account=private-dockerhub (68ms)
2019-01-22 12:59:56.034 INFO 1 --- [RxIoScheduler-3] c.n.spinnaker.igor.docker.DockerMonitor : Found 5546 new images for private-dockerhub
2019-01-22 12:59:56.034 ERROR 1 --- [RxIoScheduler-3] c.n.spinnaker.igor.docker.DockerMonitor : Number of items (5546) to cache exceeds upper threshold (1000) in monitor=DockerMonitor partition=private-dockerhub
...
Исправить ситуацию можно создав файл ~/.hal/default/profiles/igor-local.yml
следующего содержания:
dockerRegistry:
itemUpperThreshold: 10000
Двигаемся дальше. Указываем тип установки для Spinnaker (в моем примере это будет distributed) и ранее созданный Kubernetes-аккаунт (в какой кластер устанавливать):
hal config deploy edit --type distributed --account-name k8s-account
Далее следует выбрать версию Spinnaker для установки. Список доступных версий можно просмотреть командой:
hal version list
Указываем нужную версию:
hal config version edit --version 1.10.12
Деплой (или обновление настроек) Spinnaker’а выполняется командой:
hal deploy apply
Далее можно выполнить команду (по сути, port-forward):
hal deploy connect
После чего перейти по адресу localhost:9000 для дальнейшей настройки (создания приложений / пайплайнов) Spinnaker - для теста вполне сойдет. Но если вы планируете полноценно использовать Spinnaker для деплоя / управления приложениями, то необходимо настроить субдомены для Spinnaker API и UI серверов (считаем, что домен существует):
DOMAIN=example.org
hal config security ui edit \
--override-base-url http://spinnaker.${DOMAIN}
hal config security api edit \
--override-base-url http://spinnaker-api.${DOMAIN}
После чего обновить настройки Spinnaker:
hal deploy apply
Также весьма полезно будет настроить авторизацию/аутентификацию, пример с использованием OAuth2.0 можно увидеть здесь.