Merge pull request #29 from Slurmio/cicd1

cicd1
This commit is contained in:
Sergey
2021-12-09 17:32:09 +03:00
committed by GitHub
26 changed files with 25 additions and 1210 deletions
@@ -1,70 +0,0 @@
# Подготовка кластера
## 1. Создаем ns и RBAC
Для этого запускаем скрипт `setup.sh`, перед запуском `<Ваш номер логина> меняем на свой номер студента!!`.
```bash
bash ~/slurm/practice/14.ci-cd/1.1.prepare_cluster/setup.sh s<Ваш номер логина>-xpaste production
```
В конце своего выполнения скрипт выдаст нам токен, который необходимо сохранить.
## 2. Создание variables в gitlab
Для доступа из Gitlab в Kubernetes нам необходимо добавить в Gitlab переменную, в которой будет содержаться токен с предыдущего шага.
* Переходим в Gitlab
Для этого открываем в браузере свой форк xpaste. `<Ваш номер логина> меняем на свой номер студента`:
```bash
https://gitlab.slurm.io/s<Ваш номер логина>/xpaste
```
* Добавляем переменную
Для этого в левом меню находим `Settings -> CI/CD -> Variables` и нажимаем Expand. Жмем кнопку `Add Variable` и в поле `Key` вводим имя переменной:
```bash
K8S_CI_TOKEN
```
В поле `Value` вводим скопированный токен из вывода команды setup.sh (пункт 1) и нажимаем `Add Variable`.
## 3. Создаем token для доступа в registry
Для этого переходим в раздел `Settings -> Repository -> Deploy tokens` и нажимаем Expand.
В поле `Name` вводим
```bash
k8s-pull-token
```
Cтавим галочку рядом с `read_registry`. Все остальные поля оставляем пустыми. Нажимаем `Create deploy token`.
```!!НЕ ЗАКРЫВАЕМ ОКНО БРАУЗЕРА!!```
## 4. Создаем secret в kubernetes
Создаем secret, который будет использоваться для image pull. Для этого возвращаемся на первый master и выполняем команду:
Вносим нужные данные в скрипт `docker_pull_secret.sh` и запускаем его:
Соответственно подставляя на место `<>` нужные параметры, которые получили на `шаге 3`.
```bash
vim docker_pull_secret.sh
./docker_pull_secret.sh
```
## 6. Создание секрета для приложения
Создаем секрет, из которого при деплое будут взяты значения для переменных окружения, таких как доступы к БД и секретный ключ.
Вносим нужные данные в скрипт xpaste_secret.sh и запускаем его:
```bash
vim xpaste_secret.sh
./xpaste_secret.sh
```
`secret-key-base xxxxxxxxxxxxx` это не плэйсхолдер. Можно так и оставить.
@@ -1,12 +0,0 @@
#!/bin/bash
NS=s<Ваш номер логина>-xpaste-production
kubectl delete secret xpaste-gitlab-registry --namespace "$NS"
kubectl create secret docker-registry xpaste-gitlab-registry \
--docker-server registry.slurm.io \
--docker-email 'student@slurm.io' \
--docker-username '<первая строчка из окна создания токена в gitlab>' \
--docker-password '<вторая строчка из окна создания токена в gitlab>' \
--namespace "$NS"
@@ -1,95 +0,0 @@
#!/bin/bash
CI_PROJECT_PATH_SLUG=$1
CI_ENVIRONMENT_NAME=$2
GREEN='\033[0;32m'
NC='\033[0m'
usage() {
echo "Usage: $0 CI_PROJECT_PATH_SLUG CI_ENVIRONMENT_NAME"
}
base64_decode_key() {
if [[ "$OSTYPE" == "linux"* ]]; then
echo "-d"
elif [[ "$OSTYPE" == "darwin"* ]]; then
echo "-D"
else
echo "--help"
fi
}
if [ -z "$CI_PROJECT_PATH_SLUG" ] || [ -z "$CI_ENVIRONMENT_NAME" ]; then
usage
exit 1
fi
NS="$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME"
SA="$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME"
ROLE="$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME"
ROLEBIND="$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME"
if kubectl get ns "$NS"; then
echo -e "${GREEN}namespace for project already exists${NC}"
else
echo -e "${GREEN}creating namespace for project${NC}"
kubectl create namespace "$NS"
echo
fi
if kubectl -n "$NS" get sa "$SA"; then
echo -e "${GREEN}serviceaccount for project already exists${NC}"
else
echo
echo -e "${GREEN}creating CI serviceaccount for project${NC}"
kubectl create serviceaccount \
--namespace "$NS" \
"$SA"
echo
fi
if kubectl -n "$NS" get role "$ROLE"; then
echo -e "${GREEN}role for project already exists${NC}"
else
echo -e "${GREEN}creating CI role for project${NC}"
cat << EOF | kubectl apply --namespace $NS -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: "$ROLE"
rules:
- apiGroups: ["", "extensions", "apps", "batch", "events", "certmanager.k8s.io", "cert-manager.io", "monitoring.coreos.com"]
resources: ["*"]
verbs: ["*"]
EOF
echo
fi
if kubectl -n "$NS" get rolebinding "$ROLEBIND"; then
echo -e "${GREEN}rolebinding for project already exists${NC}"
else
echo -e "${GREEN}creating CI rolebinding for project${NC}"
kubectl create rolebinding \
--namespace "$NS" \
--serviceaccount "$NS":"$SA" \
--role "$ROLE" \
"$ROLEBIND"
echo
fi
echo -e "${GREEN}access token for new CI user:${NC}"
kubectl get secret \
--namespace "$NS" \
$( \
kubectl get serviceaccount \
--namespace "$NS" \
"$SA" \
-o jsonpath='{.secrets[].name}'\
) \
-o jsonpath='{.data.token}' | base64 $(base64_decode_key)
echo
@@ -1,11 +0,0 @@
#!/bin/bash
NS=s<Ваш номер логина>-xpaste-production
kubectl delete secret slurm-xpaste --namespace "$NS"
kubectl create secret generic slurm-xpaste \
--from-literal secret-key-base=xxxxxxxxxxxxxxxxxxxxxxxxx \
--from-literal db-user='s<Ваш номер логина>' \
--from-literal db-password='<Ваш пароль от логина>' \
--namespace "$NS"
@@ -1,65 +0,0 @@
variables:
K8S_API_URL: https://172.20.100.2:6443
stages:
- build
- test
- cleanup
- push
- deploy
build:
stage: build
script:
- docker build -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID .
test:
stage: test
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose
-p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID"
up
--abort-on-container-exit
--exit-code-from app
--quiet-pull
cleanup:
stage: cleanup
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose -p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID" down
when: always
push:
stage: push
before_script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
script:
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
deploy:
stage: deploy
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
resource_group: deploy_production
script:
- kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=$K8S_API_URL
- kubectl config set-credentials ci --token=$K8S_CI_TOKEN
- kubectl config set-context ci --cluster=k8s --user=ci
- kubectl config use-context ci
- helm upgrade --install $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--debug
--namespace $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME
only:
- master
-108
View File
@@ -1,108 +0,0 @@
# Добавляем конфиг CI/CD в Gitlab
В этой части добавляем последний шаг - конфиг для Gitlab CI/CD для сборки, тестирования и деплоя приложения в кластер k8s. Деплой производится с использованием утилиты Helm v3.
Gitlab CI/CD описывается в файле `.gitlab-ci.yml` в формате `yaml`. По умолчанию Gitlab ищет этот файл в корне проекта, путь до файла может быть переопределен в настройках проекта.
## 1. Подготавливаем CI/CD
Для этого скопируем заранее подготовленный шаблон `.gitlab-ci.yml` в проект `xpaste`, выполнив команду:
```bash
cp ~/slurm/practice/14.ci-cd/1.2.deploy/.gitlab-ci.yml ~/xpaste/
```
## 2. Адрес Kubernetes API
В файле `.gitlab-ci.yml` указан IP-адрес нашего общего kube api.
## 3. Настройка базы данных
Сервер базы данных общий для всех студентов, каждому студенту выделена своя база данных.
Логин и пароль для доступа к БД мы указывали при создании секрета, а в параметрах чарта укажен название БД.
Для этого откроем `values.yaml`:
```bash
vi ~/xpaste/.helm/values.yaml
```
В начале файла необходимо заменить строку `<Ваш номер логина> - меняем на свой номер студента!!`:
```diff
- DB_NAME: <номер своего логина>_xpaste
+ DB_NAME: s000001_xpaste
```
## 3. Настройка ingress
Доступ к приложению будет осуществляться через ingress. Ingress устанавливается вместе с приложением, но для его корректной работы необходимо прописать ему адрес.
Для этого откроем `values.yaml`:
```bash
vi ~/xpaste/.helm/values.yaml
```
В конце файла необходимо заменить строку `<Ваш номер логина> - меняем на свой номер студента!!`:
```diff
- host: xpaste.s<Ваш номер логина>.mcs.slurm.io
+ host: xpaste.s000001.mcs.slurm.io
```
Сохраняем все изменения и пушим их в gitlab. Для этого необходимо выполнить команды:
```bash
cd ~/xpaste
git add .
git commit -am "Add CI/CD config"
git push
```
## 4. Переключаемся в namespace приложения
До сих пор мы работали в неймспейсе кластера Kubernetes с названием `s<номер_студента>`
Но наше приложение xpaste устанавливается в другой namespace `s<номер_студента>-xpaste-production`.
Для удобства работы, чтобы не набирать каждый раз опцию `--namespace` изменим namespace, который kubectl использует по умолчанию:
```bash
kubectl config set-context --current --namespace=s<номер_студента>-xpaste-production
```
## 5. Проверка результата
Для проверки результата необходимо перейти в Gitlab в раздел `ci/cd -> pipelines` форка проекта xpaste.
Можно воспользоваться прямой ссылкой: `https://gitlab.slurm.io/sXXXXXX/xpaste/pipelines`. `sXXXXXX` необходимо заменить на номер своего студента.
В результате все job должны закончиться без ошибок.
## 6.Открываем приложение в браузере
В браузере открываем URL: http://xpaste.s<Ваш номер логина>.mcs.slurm.io. `<Ваш номер логина>` необходимо заменить на номер своего студента. Открывать нужно в режиме `инкогнито`.
Если вы увидели `503` ошибку, значит практику выполнили верно.
## 7. Самостоятельная работа
Самостоятельная работа продолжительностью 5 минут. Во время самостоятельной работы надо попробовать ответить на вопросы:
* Почему деплой закончился успешно, а приложение недоступно?
* Что надо исправить в CI/CD ?
* Что надо исправить в приложении или его настройках ?
Ошибку пока исправлять не надо.
## 8. Доработка CI/CD
* Для корректировки поведения CI/CD необходимо внести изменения в ci/cd, описанные в [snippet](https://gitlab.slurm.io/-/snippets/107)
Удаляем установленный релиз helm чарта:
```bash
helm delete s<номер_студента>-xpaste
```
Далее пушим изменения и смотрим за процессом CI/CD.
После внесения изменений процесс деплоя должен завершиться с ошибкой.
-70
View File
@@ -1,70 +0,0 @@
variables:
K8S_API_URL: https://172.20.100.2:6443
stages:
- build
- test
- cleanup
- push
- deploy
build:
stage: build
script:
- docker build -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID .
test:
stage: test
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose
-p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID"
up
--abort-on-container-exit
--exit-code-from app
--quiet-pull
cleanup:
stage: cleanup
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose -p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID" down
when: always
push:
stage: push
before_script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
script:
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
deploy:
stage: deploy
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
resource_group: deploy_production
script:
- kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=$K8S_API_URL
- kubectl config set-credentials ci --token=$K8S_CI_TOKEN
- kubectl config set-context ci --cluster=k8s --user=ci
- kubectl config use-context ci
- helm upgrade --install $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--timeout 180s
--atomic
--debug
--namespace $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME
after_script:
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME logs -lcomponent=atomiclog --tail=-1
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME delete job -lcomponent=atomiclog
only:
- master
-38
View File
@@ -1,38 +0,0 @@
# Добавляем helm hook
## 1. Добавляем манифест job
```bash
cp job.yaml ~/xpaste/.helm/templates/job.yaml
cd ~/xpaste
```
## 2. Добавляем просмотр результатов работы job в CI/CD
Добавляем в `.gitlab-ci.yml` в шаг `deploy:` раздел `after_script:`
```yaml
deploy:
...
after_script:
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME logs -lcomponent=atomiclog --tail=-1
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME delete job -lcomponent=atomiclog
```
## 3. Пушим, смотрим в вывод CI/CD
```
git add -A
git commit -am "Add job template for getting k8s logs if deploy has failed"
git push
```
## 4. Исправление настроек приложения
Ищем ошибку в выводе логов пода.
* Для исправления ошибки в работе приложения необходимо внести изменения в `values.yml` чарта, описанные в [snippet](https://gitlab.slurm.io/-/snippets/83)
Для проверки открываем в браузере URL: `http://xpaste.s<Ваш номер логина>.mcs.slurm.io`. `<Ваш номер логина>` необходимо заменить на номер своего студента. Открывать нужно в режиме `инкогнито`. Теперь приложение должно быть доступно.
-43
View File
@@ -1,43 +0,0 @@
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-atomiclog"
annotations:
"helm.sh/hook": pre-delete,pre-rollback
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": before-hook-creation
labels:
app: {{ .Chart.Name }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
component: atomiclog
spec:
activeDeadlineSeconds: 100
template:
metadata:
labels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: atomiclog
spec:
containers:
- name: atomiclog
image: centosadmin/kubernetes-helm:3.3.4
imagePullPolicy: IfNotPresent
command:
- /bin/bash
args:
- /usr/local/bin/hooklog.sh
- {{ .Release.Namespace }}
- {{ .Release.Name }}
resources:
limits:
cpu: 50m
memory: 256Mi
requests:
cpu: 50m
memory: 128Mi
dnsPolicy: ClusterFirst
restartPolicy: Never
serviceAccountName: {{ .Release.Namespace }}
@@ -1,111 +0,0 @@
#!/bin/bash
set -u
#
# file: https://galaxy.southbridge.io/templates/antools/-/blob/master/scripts/hooklog.sh
# version: 0.1.0
#
# Use this script with Helm pre-rollback hook for logs and events printing.
#
# Nikolay Mesropyan and Southbridge LLC team, 2020 A.D.
#
_main() {
local fn=${FUNCNAME[0]}
trap '_except $LINENO' ERR
if [[ "${1:-NOP}" != NOP ]]; then
local ns="$1"
else
_help; exit 0
fi
if [[ "${2:-NOP}" != NOP ]]; then
local release="$2"
else
_help; exit 0
fi
printf '\033[1;31m%s\033[1;35m' "Get pods status: "
printf -- '-%.0s' {1..130}
printf '\033[0m\n'
kubectl -n "$ns" get po -lrelease="$release" -o wide | grep -Fv atomiclog
printf '\033[1;31m%s\033[1;35m' "Tail of overall 'Warning' events: "
printf -- '-%.0s' {1..108}
printf '\033[0m\n'
kubectl -n "$ns" get events --field-selector type=Warning --sort-by='.metadata.creationTimestamp' | tail
local -a Daemonsets=() Deployments=() Jobs=() Statefulsets=()
mapfile -t Daemonsets < <( kubectl -n "$ns" get daemonset -lrelease="$release" --no-headers -o custom-columns=":metadata.name" )
mapfile -t Deployments < <( kubectl -n "$ns" get deployment -lrelease="$release" --no-headers -o custom-columns=":metadata.name" )
mapfile -t Jobs < <( kubectl -n "$ns" get job -lrelease="$release" --no-headers -o custom-columns=":metadata.name" )
mapfile -t Statefulsets < <( kubectl -n "$ns" get statefulset -lrelease="$release" --no-headers -o custom-columns=":metadata.name" )
for (( i = 0; i < ${#Daemonsets[@]}; i++ )); do
__not_ready DaemonSet "${Daemonsets[i]}"
done
for (( i = 0; i < ${#Deployments[@]}; i++ )); do
__not_ready Deployment "${Deployments[i]}"
done
for (( i = 0; i < ${#Jobs[@]}; i++ )); do
__not_ready Job "${Jobs[i]}"
done
for (( i = 0; i < ${#Statefulsets[@]}; i++ )); do
__not_ready StatefulSet "${Statefulsets[i]}"
done
exit 0
}
__not_ready() {
local not_ready_pod=""
local text="of the first not-ready pod"
not_ready_pod=$(kubectl -n "$ns" get po -lrelease="$release" --no-headers | grep "^$2" \
| gawk -F' *|/' '$4 !~ "Completed|Evicted" { print $0 }' \
| gawk -F' *|/' '$2 != $3 || $4 != "Running" { print $1; exit }')
if [[ -n "$not_ready_pod" ]]; then
__events "$@"
__logs "$@"
fi
}
__events() {
printf '\033[1;31m%s\033[1;35m' "$1 ${2}: events ${text}: "
printf -- '-%.0s' {1..76}
printf '\033[0m\n'
kubectl -n "$ns" get events --field-selector involvedObject.name="$not_ready_pod" || :
}
__logs() {
local -a Containers=()
mapfile -t Containers < <( kubectl -n "$ns" get po "$not_ready_pod" --no-headers -o jsonpath="{.spec.containers[*].name}" | sed 's/\s\+/\n/g' )
for (( i = 0; i < ${#Containers[@]}; i++ )); do
printf '\033[1;31m%s\033[1;35m' "$1 ${2}: logs ${text}, container '${Containers[i]}': "
printf -- '-%.0s' {1..56}
printf '\033[0m\n'
kubectl -n "$ns" logs "$not_ready_pod" "${Containers[i]}" --ignore-errors=true --tail=-1 || :
done
}
_except() {
local ret=$?
local no=${1:-no_line}
echo "error occured in function '$fn' near line ${no}, exit code ${ret}. Continuing..."
}
_help() {
echo "Usage: $0 <metadata.namespace> <metadata.labels.release>" >&2
}
_main "$@"
@@ -1,94 +0,0 @@
variables:
K8S_API_URL: https://172.20.100.2:6443
stages:
- linter
- build
- test
- cleanup
- push
- template
- deploy
build:
stage: build
script:
- docker build -t $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID .
test:
stage: test
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose
-p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID"
up
--abort-on-container-exit
--exit-code-from app
--quiet-pull
cleanup:
stage: cleanup
image:
name: docker/compose:1.27.4
entrypoint: [""]
script:
- docker-compose -p "$CI_PROJECT_NAME"_"$CI_PIPELINE_ID" down
when: always
push:
stage: push
before_script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
script:
- docker push $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
deploy:
stage: deploy
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
resource_group: deploy_production
script:
- kubectl config set-cluster k8s --insecure-skip-tls-verify=true --server=$K8S_API_URL
- kubectl config set-credentials ci --token=$K8S_CI_TOKEN
- kubectl config set-context ci --cluster=k8s --user=ci
- kubectl config use-context ci
- helm upgrade --install $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--timeout 180s
--atomic
--namespace $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME
after_script:
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME logs -lcomponent=atomiclog --tail=-1
- kubectl -n $CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_NAME delete job -lcomponent=atomiclog
only:
- master
helm_lint:
stage: linter
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
script:
- helm lint .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
template:
stage: template
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
script:
- helm template $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
@@ -1,56 +0,0 @@
# Ещё больше улучшений в конфиге CI/CD
## 1. Добавляем helm linter и вывод манифестов.
Добавляем новые шаги:
```
helm_lint:
stage: linter
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
script:
- helm lint .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
```
```
template:
stage: template
image: centosadmin/kubernetes-helm:3.3.4
environment:
name: production
script:
- helm template $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
```
Заносим их в список стейджей
```
stages:
- linter
- build
- test
- cleanup
- push
- template
- deploy
```
Или копируем готовый файл `.gitlab-ci.yml` в репозиторий xpaste.
Пушим, смотрим результат.
## 2. Самостоятельная работа
Исправляем Error в выводе линтера, Warning можно пропустить.
PS: В принципе можно убрать ключ `--debug` из шага deploy.
@@ -1,25 +0,0 @@
# Запускаем приложение в несколько реплик
## 1. Копируем манифест deployment
```
cp deployment.yaml ~/xpaste/.helm/templates/
```
## 2. Пушим, ждем запуска, рассматриваем
```
cd ~/xpaste
git add .helm/templates/deployment.yaml
git commit -m "Run app with nginx in separate containers"
git push
```
## 3. Смотрим описание пода, список запущенных процессов
```
kubectl describe pod ...
kubectl exec -it ...
ps ax
```
@@ -1,120 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ .Chart.Name }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
component: app
name: {{ .Release.Name }}
spec:
progressDeadlineSeconds: 180
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
revisionHistoryLimit: 5
template:
metadata:
creationTimestamp: null
labels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: app
spec:
containers:
- name: nginx
command: ["/usr/sbin/nginx"]
args: ["-g", "daemon off;"]
image: {{ .Values.image }}:{{ .Values.imageTag }}
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/run
name: socket
ports:
- containerPort: {{ .Values.service.port }}
name: http
protocol: TCP
readinessProbe:
failureThreshold: 30
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
livenessProbe:
initialDelaySeconds: 90
failureThreshold: 3
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
resources:
limits:
cpu: 100m
memory: 256Mi
requests:
cpu: 100m
memory: 256Mi
- env:
{{- range $key, $val := .Values.env }}
- name: {{ $key | quote }}
value: {{ $val | quote }}
{{- end }}
{{- range $key, $val := .Values.envSecret }}
- name: {{ $key | quote }}
valueFrom:
secretKeyRef:
key: {{ $key | lower | replace "_" "-" }}
name: {{ $val }}
{{- end }}
image: {{ .Values.image }}:{{ .Values.imageTag}}
imagePullPolicy: IfNotPresent
name: app
command: ["/bin/sh"]
args: ["-c","bundle exec rake db:migrate && exec bundle exec puma -b unix:///var/run/puma.sock -e $RAILS_ENV config.ru"]
volumeMounts:
- mountPath: /var/run
name: socket
readinessProbe:
failureThreshold: 30
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
livenessProbe:
initialDelaySeconds: 90
failureThreshold: 3
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
resources:
{{ toYaml .Values.resources | indent 12 }}
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 20
imagePullSecrets:
- name: {{ .Values.imagePullSecret }}
volumes:
- name: socket
emptyDir: {}
@@ -1,18 +0,0 @@
# Добавляем pre-install hook с миграцией БД
## 1. Копируем манифест deployment и job.migrate
```
cp job.migrate.yaml ~/xpaste/.helm/templates/
cp deployment.yaml ~/xpaste/.helm/templates/
```
## 2. Пушим, ждем запуска, рассматриваем
```
cd ~/xpaste
git add .helm/templates/job.migrate.yaml
git add .helm/templates/deployment.yaml
git commit -m "Add migrate job"
git push
```
@@ -1,120 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ .Chart.Name }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
component: app
name: {{ .Release.Name }}
spec:
progressDeadlineSeconds: 180
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
revisionHistoryLimit: 5
template:
metadata:
creationTimestamp: null
labels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: app
spec:
containers:
- name: nginx
command: ["/usr/sbin/nginx"]
args: ["-g", "daemon off;"]
image: {{ .Values.image }}:{{ .Values.imageTag }}
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /var/run
name: socket
ports:
- containerPort: {{ .Values.service.port }}
name: http
protocol: TCP
readinessProbe:
failureThreshold: 30
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
livenessProbe:
initialDelaySeconds: 90
failureThreshold: 3
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
resources:
limits:
cpu: 100m
memory: 256Mi
requests:
cpu: 100m
memory: 256Mi
- env:
{{- range $key, $val := .Values.env }}
- name: {{ $key | quote }}
value: {{ $val | quote }}
{{- end }}
{{- range $key, $val := .Values.envSecret }}
- name: {{ $key | quote }}
valueFrom:
secretKeyRef:
key: {{ $key | lower | replace "_" "-" }}
name: {{ $val }}
{{- end }}
image: {{ .Values.image }}:{{ .Values.imageTag}}
imagePullPolicy: IfNotPresent
name: app
command: ["/bin/sh"]
args: ["-c","exec bundle exec puma -b unix:///var/run/puma.sock -e $RAILS_ENV config.ru"]
volumeMounts:
- mountPath: /var/run
name: socket
readinessProbe:
failureThreshold: 30
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
livenessProbe:
initialDelaySeconds: 90
failureThreshold: 3
httpGet:
path: /
port: {{ .Values.service.port }}
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
resources:
{{ toYaml .Values.resources | indent 12 }}
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 20
imagePullSecrets:
- name: {{ .Values.imagePullSecret }}
volumes:
- name: socket
emptyDir: {}
@@ -1,56 +0,0 @@
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-dbmigrate"
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": before-hook-creation
labels:
app: {{ .Chart.Name }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
component: dbmigrate
spec:
activeDeadlineSeconds: 180
template:
metadata:
labels:
app: {{ .Chart.Name }}
release: {{ .Release.Name }}
component: dbmigrate
spec:
containers:
- name: dbmigrate
image: {{ .Values.image }}:{{ .Values.imageTag }}
imagePullPolicy: IfNotPresent
command:
- bundle
args:
- exec
- rake
- db:migrate
env:
{{- range $key, $val := .Values.env }}
- name: {{ $key | quote }}
value: {{ $val | quote }}
{{- end }}
{{- range $key, $val := .Values.envSecret }}
- name: {{ $key | quote }}
valueFrom:
secretKeyRef:
key: {{ $key | lower | replace "_" "-" }}
name: {{ $val }}
{{- end }}
resources:
limits:
cpu: 50m
memory: 128Mi
requests:
cpu: 50m
memory: 128Mi
dnsPolicy: ClusterFirst
restartPolicy: Never
imagePullSecrets:
- name: {{ .Values.imagePullSecret }}
+1 -1
View File
@@ -15,7 +15,7 @@ helm repo add gitlab https://charts.gitlab.io
Как вы уже поняли, для установки мы пойдем знакомым путём Helm, выполнив команды:
```bash
helm upgrade -i gitlab-runner gitlab/gitlab-runner -f values.yaml
helm upgrade -i gitlab-runner gitlab/gitlab-runner -f values.yaml -n gitlab-runner --create-namespace
```
## 3. Проверка регистрации раннера
@@ -1,7 +1,7 @@
## The GitLab Server URL (with protocol) that want to register the runner against
## ref: https://docs.gitlab.com/runner/commands/README.html#gitlab-runner-register
##
gitlabUrl: http://gitlab.com/
gitlabUrl: https://gitlab.com/
## The Registration Token for adding new Runners to the GitLab Server. This must
## be retrieved from your GitLab Instance.
@@ -14,7 +14,7 @@ runners:
[[runners]]
[runners.kubernetes]
image = "alpine:3.14"
cpu_request = "1000m"
cpu_request = "100m"
cpu_limit = "1000m"
memory_limit = "2048Mi"
memory_request = "1024Mi"
@@ -30,7 +30,7 @@ rbac:
## Use the following Kubernetes Service Account name if RBAC is disabled in this Helm chart (see rbac.create)
##
serviceAccountName: s<номер_студента>
# serviceAccountName: gitlabrunnersa
## Use podSecurity Policy
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/
+1 -1
View File
@@ -5,7 +5,7 @@
Postgres мы устанавливаем в kubernetes кластер, делается это исключительно в учебных целях. Для установки будет использована утилита helm. Для установки необходимо выполнить следующую команду, заменив `<Ваш номер логина>` на номер своего студента:
```bash
helm install postgresql postgresql --namespace xpaste --atomic --timeout 120s
helm install postgresql postgresql --namespace xpaste-development --atomic --timeout 120s --create-namespace
```
Postrgesql будет установлен с логином и паролем, указанными в values.yaml чарта.
+1 -1
View File
@@ -62,7 +62,7 @@ else
metadata:
name: "$ROLE"
rules:
- apiGroups: ["", "extensions", "apps", "batch", "events", "certmanager.k8s.io", "cert-manager.io", "monitoring.coreos.com"]
- apiGroups: ["", "extensions", "apps", "batch", "events", "networking.k8s.io", "certmanager.k8s.io", "cert-manager.io", "monitoring.coreos.com"]
resources: ["*"]
verbs: ["*"]
EOF
+3 -3
View File
@@ -20,9 +20,9 @@ build:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- |
/kaniko/executor --context $CI_PROJECT_DIR \
--cache=true --cache-repo=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME \
--cache=true --cache-repo=$CI_REGISTRY_IMAGE \
--dockerfile $CI_PROJECT_DIR/Dockerfile \
--destination $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--destination ${CI_REGISTRY_IMAGE}:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
deploy:dev:
stage: deploy
@@ -35,7 +35,7 @@ deploy:dev:
- kubectl config set-context ci --cluster=k8s --user=ci
- kubectl config use-context ci
- helm upgrade --install xpaste .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--debug
--atomic
+9 -55
View File
@@ -9,31 +9,12 @@ Gitlab CI/CD описывается в файле `.gitlab-ci.yml` в форма
Для этого скопируем заранее подготовленный шаблон `.gitlab-ci.yml` в проект `xpaste`, выполнив команду:
```bash
cp ~/slurm/practice/14.ci-cd/1.2.deploy/.gitlab-ci.yml ~/xpaste/
cp .gitlab-ci.yml ~/xpaste/
```
## 2. Адрес Kubernetes API
В файле `.gitlab-ci.yml` указан IP-адрес нашего общего kube api.
## 3. Настройка базы данных
Сервер базы данных общий для всех студентов, каждому студенту выделена своя база данных.
Логин и пароль для доступа к БД мы указывали при создании секрета, а в параметрах чарта укажен название БД.
Для этого откроем `values.yaml`:
```bash
vi ~/xpaste/.helm/values.yaml
```
В начале файла необходимо заменить строку `<Ваш номер логина> - меняем на свой номер студента!!`:
```diff
- DB_NAME: <номер своего логина>_xpaste
+ DB_NAME: s000001_xpaste
```
В файле `.gitlab-ci.yml` указан адрес kube api. Так как runner запущен внутри кластера кубернтес, можем указать название сервиса kubernetes.default
## 3. Настройка ingress
@@ -44,11 +25,11 @@ vi ~/xpaste/.helm/values.yaml
vi ~/xpaste/.helm/values.yaml
```
В конце файла необходимо заменить строку `<Ваш номер логина> - меняем на свой номер студента!!`:
В переменной host необходимо указать DNS название, которое вы выдали сайту xpaste:
```diff
- host: xpaste.s<Ваш номер логина>.mcs.slurm.io
+ host: xpaste.s000001.mcs.slurm.io
- host: xpaste.s<Ваш номер логина>.edu.slurm.io
+ host: xpaste.s000001.edu.slurm.io
```
Сохраняем все изменения и пушим их в gitlab. Для этого необходимо выполнить команды:
@@ -62,47 +43,20 @@ git push
## 4. Переключаемся в namespace приложения
До сих пор мы работали в неймспейсе кластера Kubernetes с названием `s<номер_студента>`
Но наше приложение xpaste устанавливается в другой namespace `s<номер_студента>-xpaste-production`.
Наше приложение xpaste устанавливается в другой namespace `xpaste-development`.
Для удобства работы, чтобы не набирать каждый раз опцию `--namespace` изменим namespace, который kubectl использует по умолчанию:
```bash
kubectl config set-context --current --namespace=s<номер_студента>-xpaste-production
kubectl config set-context --current --namespace=xpaste-development
```
## 5. Проверка результата
Для проверки результата необходимо перейти в Gitlab в раздел `ci/cd -> pipelines` форка проекта xpaste.
Можно воспользоваться прямой ссылкой: `https://gitlab.slurm.io/sXXXXXX/xpaste/pipelines`. `sXXXXXX` необходимо заменить на номер своего студента.
Можно воспользоваться прямой ссылкой: `https://gitlab.com/sXXXXXX/xpaste/pipelines`. `sXXXXXX` необходимо заменить на свой каталог в гитлабе.
В результате все job должны закончиться без ошибок.
## 6.Открываем приложение в браузере
В браузере открываем URL: http://xpaste.s<Ваш номер логина>.mcs.slurm.io. `<Ваш номер логина>` необходимо заменить на номер своего студента. Открывать нужно в режиме `инкогнито`.
Если вы увидели `503` ошибку, значит практику выполнили верно.
## 7. Самостоятельная работа
Самостоятельная работа продолжительностью 5 минут. Во время самостоятельной работы надо попробовать ответить на вопросы:
* Почему деплой закончился успешно, а приложение недоступно?
* Что надо исправить в CI/CD ?
* Что надо исправить в приложении или его настройках ?
Ошибку пока исправлять не надо.
## 8. Доработка CI/CD
* Для корректировки поведения CI/CD необходимо внести изменения в ci/cd, описанные в [snippet](https://gitlab.slurm.io/-/snippets/107)
Удаляем установленный релиз helm чарта:
```bash
helm delete s<номер_студента>-xpaste
```
Далее пушим изменения и смотрим за процессом CI/CD.
После внесения изменений процесс деплоя должен завершиться с ошибкой.
В браузере открываем URL: http://xpaste.s<Ваш номер логина>.edu.slurm.io. Открывать нужно в режиме `инкогнито`.
@@ -22,9 +22,9 @@ build:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- |
/kaniko/executor --context $CI_PROJECT_DIR \
--cache=true --cache-repo=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME \
--cache=true --cache-repo=$CI_REGISTRY_IMAGE \
--dockerfile $CI_PROJECT_DIR/Dockerfile \
--destination $CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--destination ${CI_REGISTRY_IMAGE}:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
deploy:dev:
stage: deploy
@@ -37,7 +37,7 @@ deploy:dev:
- kubectl config set-context ci --cluster=k8s --user=ci
- kubectl config use-context ci
- helm upgrade --install xpaste .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
--debug
--atomic
@@ -45,7 +45,6 @@ deploy:dev:
--namespace $NAMESPACE-$CI_ENVIRONMENT_SLUG
only:
- master
helm_lint:
stage: linter
image: centosadmin/kubernetes-helm:3.6.3
@@ -53,7 +52,7 @@ helm_lint:
name: production
script:
- helm lint .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
@@ -65,7 +64,7 @@ template:
name: production
script:
- helm template $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
@@ -12,7 +12,7 @@ helm_lint:
name: production
script:
- helm lint .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
@@ -26,7 +26,7 @@ template:
name: production
script:
- helm template $CI_PROJECT_PATH_SLUG .helm
--set image=$CI_REGISTRY/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME
--set image=$CI_REGISTRY_IMAGE
--set imageTag=$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
only:
- master
-26
View File
@@ -1,26 +0,0 @@
# CI/CD в Kubernetes с помощью Gitlab
## Список практик
[1.1 Prepare Cluster](1.1.prepare_cluster/README.md)
[1.2 Deploy](1.2.deploy/README.md)
[1.3 Show Logs](1.3.logs/README.md)
[1.4 Improvement_cicd](1.4.improvement_cicd/README.md)
[1.5 Two containers/](1.5.two_containers//README.md)
[1.6 Job for migration](1.6.job.migration/README.md)
## Форк проекта
> Открываем в браузере репозиторий xpaste. Он находится по адресу
https://github.com/Slurmio/xpaste
> Справа на одной линии с названием проекта видим кнопку fork. Нажимаем ее.
> И дожидаемся окончания процесса форка.
> Последним шагом клонируем получившийся форк к себе.