В этой статье мы подготовим кластер Kubernetes, container registry и локальное окружение для развертывания приложений.
Развертывание кластера
Выберите, каким образом будет развернут Kubernetes:
Установка и запуск minikube
Установим/обновим minikube, следуя инструкциям проекта. Убедимся, что у нас используется самая свежая версия minikube, доступная по приведённой ссылке.
Создаём новый Kubernetes-кластер с minikube:
# Удалим существующий minikube-кластер (если он есть).
minikube delete
# Запустим новый minikube-кластер.
minikube start --driver=docker
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
В ответ отобразится следующее:
Context "minikube" modified.
Если утилита kubectl всё ещё не установлена, то установим её, следуя инструкциям.
Теперь проверим работоспособность нового кластера Kubernetes, а точнее посмотрим список всех Pod’ов, запущенных в кластере:
kubectl get --all-namespaces pod
В ответ отобразится примерно следующее:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-558bd4d5db-8jfng 1/1 Running 0 48s
kube-system etcd-minikube 1/1 Running 0 61s
kube-system kube-apiserver-minikube 1/1 Running 0 54s
kube-system kube-controller-manager-minikube 1/1 Running 0 54s
kube-system kube-proxy-b87f2 1/1 Running 0 48s
kube-system kube-scheduler-minikube 1/1 Running 0 65s
kube-system storage-provisioner 1/1 Running 0 56s
Кластер Kubernetes запущен и работает, если оба условия выполняются:
- в 4-м столбце все Pod’ы из полученного списка находятся в состояниях
Running
илиCompleted
; - в 3-м столбце для всех Pod’ов в
Running
число слева (X
) от/
равно числу справа (Y
) в выражениях вродеX/Y
(т.е. контейнеры Pod’а успешно запустились).
Если не все Pod’ы успешно запустились, то подождите и снова выполните команду выше для получения статуса всех Pod’ов.
Установка NGINX Ingress Controller
Устанавливаем NGINX Ingress Controller:
minikube addons enable ingress
В ответ отобразится следующее:
...
🔎 Verifying ingress addon...
🌟 The 'ingress' addon is enabled
Немного подождём, после чего убедимся, что Ingress Controller успешно запустился:
kubectl -n ingress-nginx get pod
В ответ отобразится примерно следующее:
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-qrcdg 0/1 Completed 0 8m12s
ingress-nginx-admission-patch-8pw4d 0/1 Completed 0 8m12s
ingress-nginx-controller-59b45fb494-fscgf 1/1 Running 0 8m12s
Обновление файла hosts
Для доступа к приложению мы будем использовать домен werf-guide-app.test
. Для этого обновим файл hosts:
echo "$(minikube ip) werf-guide-app.test" | sudo tee -a /etc/hosts
Установка и запуск minikube
Установим/обновим minikube, следуя инструкциям проекта. Убедимся, что у нас используется самая свежая версия minikube, доступная по приведённой ссылке.
Создаём новый Kubernetes-кластер с minikube:
# Удалим существующий minikube-кластер (если он есть).
minikube delete
# Запустим новый minikube-кластер.
minikube start --driver=hyperkit
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
В ответ отобразится следующее:
Context "minikube" modified.
Если утилита kubectl всё ещё не установлена, то установим её, следуя инструкциям.
Теперь проверим работоспособность нового кластера Kubernetes, а точнее посмотрим список всех Pod’ов, запущенных в кластере:
kubectl get --all-namespaces pod
В ответ отобразится примерно следующее:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-558bd4d5db-8jfng 1/1 Running 0 48s
kube-system etcd-minikube 1/1 Running 0 61s
kube-system kube-apiserver-minikube 1/1 Running 0 54s
kube-system kube-controller-manager-minikube 1/1 Running 0 54s
kube-system kube-proxy-b87f2 1/1 Running 0 48s
kube-system kube-scheduler-minikube 1/1 Running 0 65s
kube-system storage-provisioner 1/1 Running 0 56s
Кластер Kubernetes запущен и работает, если оба условия выполняются:
- в 4-м столбце все Pod’ы из полученного списка находятся в состояниях
Running
илиCompleted
; - в 3-м столбце для всех Pod’ов в
Running
число слева (X
) от/
равно числу справа (Y
) в выражениях вродеX/Y
(т.е. контейнеры Pod’а успешно запустились).
Если не все Pod’ы успешно запустились, то подождите и снова выполните команду выше для получения статуса всех Pod’ов.
Установка NGINX Ingress Controller
Устанавливаем NGINX Ingress Controller:
minikube addons enable ingress
В ответ отобразится следующее:
...
🔎 Verifying ingress addon...
🌟 The 'ingress' addon is enabled
Немного подождём, после чего убедимся, что Ingress Controller успешно запустился:
kubectl -n ingress-nginx get pod
В ответ отобразится примерно следующее:
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-qrcdg 0/1 Completed 0 8m12s
ingress-nginx-admission-patch-8pw4d 0/1 Completed 0 8m12s
ingress-nginx-controller-59b45fb494-fscgf 1/1 Running 0 8m12s
Обновление файла hosts
Для доступа к приложению мы будем использовать домен werf-guide-app.test
. Для этого обновим файл hosts:
echo "$(minikube ip) werf-guide-app.test" | sudo tee -a /etc/hosts
Установка и запуск minikube
Установим/обновим minikube, следуя инструкциям проекта. Убедимся, что у нас используется самая свежая версия minikube, доступная по приведённой ссылке.
Создаём новый Kubernetes-кластер с minikube:
# Удалим существующий minikube-кластер (если он есть).
minikube delete
# Запустим новый minikube-кластер.
minikube start --driver=docker
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
В ответ отобразится следующее:
Context "minikube" modified.
Если утилита kubectl всё ещё не установлена, то установим её, следуя инструкциям.
Теперь проверим работоспособность нового кластера Kubernetes, а точнее посмотрим список всех Pod’ов, запущенных в кластере:
kubectl get --all-namespaces pod
В ответ отобразится примерно следующее:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-558bd4d5db-8jfng 1/1 Running 0 48s
kube-system etcd-minikube 1/1 Running 0 61s
kube-system kube-apiserver-minikube 1/1 Running 0 54s
kube-system kube-controller-manager-minikube 1/1 Running 0 54s
kube-system kube-proxy-b87f2 1/1 Running 0 48s
kube-system kube-scheduler-minikube 1/1 Running 0 65s
kube-system storage-provisioner 1/1 Running 0 56s
Кластер Kubernetes запущен и работает, если оба условия выполняются:
- в 4-м столбце все Pod’ы из полученного списка находятся в состояниях
Running
илиCompleted
; - в 3-м столбце для всех Pod’ов в
Running
число слева (X
) от/
равно числу справа (Y
) в выражениях вродеX/Y
(т.е. контейнеры Pod’а успешно запустились).
Если не все Pod’ы успешно запустились, то подождите и снова выполните команду выше для получения статуса всех Pod’ов.
Установка NGINX Ingress Controller
Устанавливаем NGINX Ingress Controller:
minikube addons enable ingress
В ответ отобразится следующее:
...
🔎 Verifying ingress addon...
🌟 The 'ingress' addon is enabled
Немного подождём, после чего убедимся, что Ingress Controller успешно запустился:
kubectl -n ingress-nginx get pod
В ответ отобразится примерно следующее:
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-qrcdg 0/1 Completed 0 8m12s
ingress-nginx-admission-patch-8pw4d 0/1 Completed 0 8m12s
ingress-nginx-controller-59b45fb494-fscgf 1/1 Running 0 8m12s
Сделаем NGINX Ingress Controller доступным на 80-м порту после запуска minikube tunnel
:
kubectl expose service -n ingress-nginx ingress-nginx-controller --name ingress-nginx-controller-lb --type LoadBalancer --port 80 --target-port http
Важно проверить, что в нашей системе не занят 80-й порт. Следующая команда, выполненная от Администратора, должна выдать пустой результат:
netstat -anb | Select-String :80
В случае если порт занят, то в ответ отобразится примерно следующее:
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
TCP [::]:80 [::]:0 LISTENING
— в этом случае необходимо найти и остановить запущенный сервер.
Теперь нам надо не забывать держать запущенным minikube tunnel
в отдельном окне PowerShell. Это необходимо для доступа с нашего хоста к ресурсам в кластере через Ingress:
minikube tunnel --cleanup=true
Обновление файла hosts
Для доступа к приложению мы будем использовать домен werf-guide-app.test
. Для этого обновим файл hosts (в PowerShell от администратора):
Add-Content "C:\Windows\System32\drivers\etc\hosts" "`n127.0.0.1 werf-guide-app.test"
Проверка
Для проверки работоспособности выполните:
curl http://werf-guide-app.test/ping
Если всё работает как надо, то NGINX Ingress Controller вернёт ошибку 404:
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
Если у вас уже поднято приложение, на которое смотрит Ingress с доменом
werf-guide-app.test
, то вместо ошибки 404 вы получите ответ от своего приложения.
Настройка container registry
Далее мы будем использовать Docker Hub container registry, но для этого руководства подойдет и любой другой Registry с TLS и аутентификацией (GitHub container registry, GitLab container registry, …).
Авторизация в Docker Hub
Регистрируемся на Docker Hub, после чего создаём приватный репозиторий с именем werf-guide-app
, в котором будем хранить собираемые образы.
С помощью werf cr login
получим доступ с текущего компьютера к новому репозиторию, введя логин и пароль от нашего пользователя на Docker Hub:
werf cr login https://index.docker.io/v1/ -u <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB> -p <ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>
В случае успеха получим ответ:
Login Succeeded
Создание Secret
Чтобы в процессе работы у нас была возможность использовать образы из приватного container registry, нам необходимо создать Secret с учетными данными пользователя. Здесь есть одна особенность — Secret должен располагаться в том же namespace, что и приложение.
Поэтому необходимо заранее создать namespace для нашего приложения:
kubectl create namespace werf-guide-app
В ответ отобразится следующее:
namespace/werf-guide-app created
Далее создадим Secret с именем registrysecret
в нашем namespace:
kubectl create secret docker-registry registrysecret \
--docker-server='https://index.docker.io/v1/' \
--docker-username='<ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>' \
--docker-password='<ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>'
Для создания Secret мы используем стандартный способ из официальной документации Kubernetes.
В ответ отобразится следующее:
secret/registrysecret created
То его нужно пересоздать, предварительно удалив уже созданный вариант командой:
kubectl delete secret registrysecret
В следующих статьях мы будем использовать Secret registrysecret
в поле imagePullSecrets
при конфигурации Pod’ов (подробнее можно почитать здесь).
Стоит обратить внимание на опцию
--docker-server
, параметр которой должен соответствовать адресу используемого registry. К примеру, для GitHub container registry необходимо иcпользоватьghcr.io
, а для Docker Hub можно обойтись без опции и использовать значение по умолчанию.
Теперь окружение для работы готово.
Также обратите внимание, что при удалении namespace или изменении правил доступов необходимо выполнить процедуру заново.
Рабочее окружение работало, но перестало
Запустим приложение 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, и мы обязательно вам поможем.