Внесём изменения в уже запущенное приложение и его инфраструктуру. Продемонстрируем, как работает подход infrastructure-as-code (IaC).
Подготовка окружения
Если вы ещё не подготовили своё рабочее окружение на предыдущих этапах, сделайте это в соответствии с инструкциями статьи «Подготовка окружения».
Если ваше рабочее окружение работало, но перестало, или же последующие инструкции из этой статьи не работают — попробуйте следующее:
Запустим приложение Docker Desktop. Приложению понадобится некоторое время для того, чтобы запустить Docker. Если никаких ошибок в процессе запуска не возникло, то проверим, что Docker запущен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим приложение Docker Desktop. Приложению понадобится некоторое время для того, чтобы запустить Docker. Если никаких ошибок в процессе запуска не возникло, то проверим, что Docker запущен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим Docker:
sudo systemctl restart docker
Убедимся, что Docker запустился:
sudo systemctl status docker
Результат выполнения команды, если Docker успешно запущен:
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2021-06-24 13:05:17 MSK; 13s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 2013888 (dockerd)
Tasks: 36
Memory: 100.3M
CGroup: /system.slice/docker.service
└─2013888 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
dockerd[2013888]: time="2021-06-24T13:05:16.936197880+03:00" level=warning msg="Your kernel does not support CPU realtime scheduler"
dockerd[2013888]: time="2021-06-24T13:05:16.936219851+03:00" level=warning msg="Your kernel does not support cgroup blkio weight"
dockerd[2013888]: time="2021-06-24T13:05:16.936224976+03:00" level=warning msg="Your kernel does not support cgroup blkio weight_device"
dockerd[2013888]: time="2021-06-24T13:05:16.936311001+03:00" level=info msg="Loading containers: start."
dockerd[2013888]: time="2021-06-24T13:05:17.119938367+03:00" level=info msg="Loading containers: done."
dockerd[2013888]: time="2021-06-24T13:05:17.134054120+03:00" level=info msg="Daemon has completed initialization"
systemd[1]: Started Docker Application Container Engine.
dockerd[2013888]: time="2021-06-24T13:05:17.148493957+03:00" level=info msg="API listen on /run/docker.sock"
Теперь проверим, что Docker доступен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим кластер minikube, уже настроенный в начале статьи “Подготовка окружения”:
minikube start
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
Результат успешного выполнения команды:
😄 minikube v1.20.0 on Ubuntu 20.04
✨ Using the docker driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🎉 minikube 1.21.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.21.0
💡 To disable this notice, run: 'minikube config set WantUpdateNotification false'
🔄 Restarting existing docker container for "minikube" ...
🐳 Preparing Kubernetes v1.20.2 on Docker 20.10.6 ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/google_containers/kube-registry-proxy:0.4
▪ Using image k8s.gcr.io/ingress-nginx/controller:v0.44.0
▪ Using image registry:2.7.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎 Verifying registry addon...
🔎 Verifying ingress addon...
🌟 Enabled addons: storage-provisioner, registry, default-storageclass, ingress
🏄 Done! kubectl is now configured to use "minikube" cluster and "werf-guide-app" namespace by default
Убедитесь, что вывод команды содержит строку:
Restarting existing docker container for "minikube"
Если её нет, значит был создан новый кластер minikube вместо использования старого. В таком случае повторите установку рабочего окружения с minikube с самого начала.
Теперь запустите команду в фоновом PowerShell-терминале и не закрывайте его:
minikube tunnel --cleanup=true
Запустим кластер minikube, уже настроенный в начале статьи “Подготовка окружения”:
minikube start --namespace werf-guide-app
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
Результат успешного выполнения команды:
😄 minikube v1.20.0 on Ubuntu 20.04
✨ Using the docker driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🎉 minikube 1.21.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.21.0
💡 To disable this notice, run: 'minikube config set WantUpdateNotification false'
🔄 Restarting existing docker container for "minikube" ...
🐳 Preparing Kubernetes v1.20.2 on Docker 20.10.6 ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/google_containers/kube-registry-proxy:0.4
▪ Using image k8s.gcr.io/ingress-nginx/controller:v0.44.0
▪ Using image registry:2.7.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎 Verifying registry addon...
🔎 Verifying ingress addon...
🌟 Enabled addons: storage-provisioner, registry, default-storageclass, ingress
🏄 Done! kubectl is now configured to use "minikube" cluster and "werf-guide-app" namespace by default
Убедитесь, что вывод команды содержит строку:
Restarting existing docker container for "minikube"
Если её нет, значит был создан новый кластер minikube вместо использования старого. В таком случае повторите установку рабочего окружения с minikube с самого начала.
Если вы непреднамеренно удалили Namespace приложения, то необходимо выполнить следующие команды, чтобы продолжить прохождение руководства:
kubectl create namespace werf-guide-app
kubectl create secret docker-registry registrysecret \
--docker-server='https://index.docker.io/v1/' \
--docker-username='<ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>' \
--docker-password='<ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>'
Результат успешного выполнения команды:
namespace/werf-guide-app created
secret/registrysecret created
Если ничего не помогло, то пройдите статью «Подготовка окружения» с начала, подготовив новое окружение с нуля. Если и это не помогло, тогда, пожалуйста, расскажите о своей проблеме в нашем Telegram или оставьте Issue на GitHub, и мы обязательно вам поможем.
Подготовка репозитория
Используем уже существующий репозиторий с приложением (выполните в Bash/PowerShell):
cd ~/werf-guide/app
Возникли проблемы с репозиторием? Попробуйте инструкции на вкладке «Начинаю проходить руководство с этой статьи» выше.
Подготовим новый репозиторий с приложением:
Выполним следующий набор команд в PowerShell:
# Склонируем репозиторий с примерами в ~/werf-guide/guides, если он ещё не был склонирован.
if (-not (Test-Path ~/werf-guide/guides)) {
git clone https://github.com/werf/website $env:HOMEPATH/werf-guide/guides
}
# Скопируем файлы приложения (пока без изменений) в ~/werf-guide/app.
rm -Recurse -Force ~/werf-guide/app
cp -Recurse -Force ~/werf-guide/guides/examples/basic/002_deploy ~/werf-guide/app
# Сделаем из директории ~/werf-guide/app git-репозиторий.
cd ~/werf-guide/app
git init
git add .
git commit -m initial
Выполним следующий набор команд в Bash:
# Склонируем репозиторий с примерами в ~/werf-guide/guides, если он ещё не был склонирован.
test -e ~/werf-guide/guides || git clone https://github.com/werf/website ~/werf-guide/guides
# Скопируем файлы приложения (пока без изменений) в ~/werf-guide/app.
rm -rf ~/werf-guide/app
cp -rf ~/werf-guide/guides/examples/basic/002_deploy ~/werf-guide/app
# Сделаем из директории ~/werf-guide/app git-репозиторий.
cd ~/werf-guide/app
git init
git add .
git commit -m initial
Работаем с инфраструктурой
Сейчас попробуем некоторые команды по взаимодействию с Kubernetes-кластером, а в следующей статье — рассмотрим их более подробно.
Убедитесь, что у вас выставлен Namespace
werf-guide-app
по умолчанию. Это может быть актуально, если, например, вы перезагружали компьютер перед тем, как продолжить выполнение Руководства с этой статьи. Инструкции по запуску локального кластера minikube и выставлению Namespace по умолчанию находятся вверху страницу в главе «Перезагружали компьютер после подготовки окружения?»
Убедимся, что приложение развернуто (либо развернём его, если оно ещё не развернуто), выполнив команду:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
Ожидаемый результат:
...
Release "werf-guide-app" has been upgraded. Happy Helming!
NAME: werf-guide-app
LAST DEPLOYED: Thu Jul 22 15:32:10 2022
NAMESPACE: werf-guide-app
STATUS: deployed
REVISION: 6
TEST SUITE: None
Running time 30.27 seconds
Просмотр состояния
Чтобы посмотреть состояние запущенного приложения в Kubernetes, существует несколько команд.
Получить список запущенных Deployment’ов и Pod’ов:
kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
werf-guide-app 1/1 1 1 5m41s
kubectl get pod
NAME READY STATUS RESTARTS AGE
werf-guide-app-57f854484f-8ktqp 1/1 Running 0 7m24s
Посмотреть summary-информацию по Deployment’у werf-guide-app
:
kubectl describe deployment werf-guide-app
Name: werf-guide-app
Namespace: werf-guide-app
CreationTimestamp: Mon, 12 Jul 2021 10:30:14 +0300
Labels: app.kubernetes.io/managed-by=Helm
Annotations: deployment.kubernetes.io/revision: 1
meta.helm.sh/release-name: werf-guide-app
meta.helm.sh/release-namespace: werf-guide-app
project.werf.io/env:
project.werf.io/name: werf-guide-app
werf.io/version: v1.2.11+fix10
Selector: app=werf-guide-app
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=werf-guide-app
Containers:
app:
Image: <dockerhubuser>/werf-guide-app:e5c6ebcd2718ccfe74d01069a0d758e03d5a2554155ccdc01be0daff-1625753768312
Port: 8000/TCP
Host Port: 0/TCP
Command:
/app/start.sh
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: werf-guide-app-57f854484f (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 8m14s deployment-controller Scaled up replica set werf-guide-app-57f854484f to 1
Deployment запускает Pod’ы. Логи пишутся в Pod’ах. Получить логи одного из запущенных Pod’ов можно командой:
kubectl logs werf-guide-app-<podId>
GET /ping HTTP/1.1
Host: werf-guide-app.test
X-Request-ID: 3cdfedee7ff8f4fb27566446d587ccbd
X-Real-IP: 192.168.49.1
X-Forwarded-For: 192.168.49.1
X-Forwarded-Host: werf-guide-app.test
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Scheme: http
User-Agent: curl/7.68.0
Accept: */*
Масштабирование
Веб-сервер запущен в Deployment’е werf-guide-app
. Помотрим, сколько реплик этого Kubernetes-ресурса запущено:
kubectl get pod
NAME READY STATUS RESTARTS AGE
werf-guide-app-57f854484f-8ktqp 1/1 Running 0 7m24s
Поменяем вручную на 4 реплики. Для этого выполняем:
kubectl edit deployment werf-guide-app
… и в открывшемся редакторе выставляем spec.replicas=4
, закрываем редактор.
Снова посмотрим, сколько реплик запущено:
kubectl get pod
NAME READY STATUS RESTARTS AGE
werf-guide-app-57f854484f-2xbzl 1/1 Running 0 119m
werf-guide-app-57f854484f-8ktqp 1/1 Running 0 6h59m
werf-guide-app-57f854484f-kr9sl 1/1 Running 0 119m
werf-guide-app-57f854484f-r99j4 1/1 Running 0 118m
Мы произвели масштабирование вручную. Теперь снова запустим werf converge
:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
И снова посмотрим, сколько реплик запущено:
kubectl get pod
NAME READY STATUS RESTARTS AGE
werf-guide-app-57f854484f-2xbzl 1/1 Running 0 119m
Количество реплик изменилось: их число снова соответствует таковому в Git-репозитории. Это произошло, потому что werf привела состояние кластера к состоянию, описанному в текущем Git-коммите. Этот принцип называется гитерминизмом (giterminism).
Как же соблюсти гитерминизм и сделать всё правильно? Снова выставим тот же spec.replicas=4
, но теперь — через состояние приложения, описанное в Git:
Выполним следующий набор команд в PowerShell:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -Recurse -Force ~/werf-guide/guides/examples/basic/003_scale/* .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Выполним следующий набор команд в Bash:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -rf ~/werf-guide/guides/examples/basic/003_scale/. .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Нужное нам значение spec.replicas
теперь указано в файле .helm/templates/deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: werf-guide-app
spec:
replicas: 4
selector:
matchLabels:
app: werf-guide-app
template:
metadata:
labels:
app: werf-guide-app
spec:
imagePullSecrets:
- name: registrysecret
containers:
- name: app
image: {{ .Values.werf.image.app }}
command: ["/app/start.sh"]
ports:
- containerPort: 8000
Запустим деплой:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
Проверим, сколько реплик запущено теперь:
kubectl get pod
NAME READY STATUS RESTARTS AGE
werf-guide-app-57f854484f-2xbzl 1/1 Running 0 119m
werf-guide-app-57f854484f-8ktqp 1/1 Running 0 6h59m
werf-guide-app-57f854484f-kr9sl 1/1 Running 0 119m
werf-guide-app-57f854484f-r99j4 1/1 Running 0 118m
Их снова 4, как и требовалось! Можно вернуть состояние рабочей директории к предыдущему, т.е. с одной репликой:
Выполним следующий набор команд в PowerShell:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -Recurse -Force ~/werf-guide/guides/examples/basic/002_deploy/* .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Выполним следующий набор команд в Bash:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -rf ~/werf-guide/guides/examples/basic/002_deploy/. .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Проверим значение spec.replicas
в содержимом файла .helm/templates/deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: werf-guide-app
spec:
replicas: 1
selector:
matchLabels:
app: werf-guide-app
template:
metadata:
labels:
app: werf-guide-app
spec:
imagePullSecrets:
- name: registrysecret
containers:
- name: app
image: {{ .Values.werf.image.app }}
command: ["/app/start.sh"]
ports:
- containerPort: 8000
Запустим деплой:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
Меняем приложение
Наше приложение — это простейший эхо-сервер, который при запросе при помощи curl:
curl "http://werf-guide-app.test/ping"
… ответит словом pong
.
Внесём изменение в код приложения:
Выполним следующий набор команд в PowerShell:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -Recurse -Force ~/werf-guide/guides/examples/basic/004_modify_app/* .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Выполним следующий набор команд в Bash:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -rf ~/werf-guide/guides/examples/basic/004_modify_app/. .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
В коде приложения ответ сервера изменится на hello world
:
#!/bin/sh
RESPONSE="hello world"
while true; do
printf "HTTP/1.1 200 OK\n\n$RESPONSE\n" | ncat -lp 8000
done
Запустим деплой:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
Проверим результат:
curl "http://werf-guide-app.test/ping"
В ответе увидим hello world
.
Поздравляем, у нас всё получилось!