nshvyryaev microservices repository
- Настроены репозиторий и Travis
- Использованы базовые команды для работы с контейнерами: run, start, create, commit, inspect, ps
- (*) Выполнено сравнение вывода команды inspect для контейнера и образа
- Образ запушен в Docker Hub
docker tag reddit:latest nikitagsh/otus-reddit:1.0
docker push nikitagsh/otus-reddit:1.0
- Предварительно нужно авторизовать приложения с помощью команды
gcloud auth application-default login
- Для запуска docker host в GCP выполнить команду
docker-machine create --driver google --google-machine-image https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/family/ubuntu-1604-lts --google-machine-type n1-standard-1 --google-zone europe-west1-b docker-host
- Начать использовать docker host можно командой
eval $(docker-machine env docker-host)
- Для сборки образа выполнить команду
docker build -t reddit:latest .
в папкеdockermonolith
- Для запуска контейнера из собранного образа -
docker run --name reddit -d --network=host reddit:latest
- Запустить локально из запушенного образа -
docker run --name reddit -d -p 9292:9292 --rm nikitagsh/otus-reddit:1.0
- Добавлена папка docker-monolith/infra
- С помощью Packer собран образ
docker-host
, содержащий установленный Docker - С помощью Terraform можно запустить конфигурируемое переменной количество инстансов и разрешить трафик на порт 9292
- Ansible устанавливает необходимые для своей работы с докером плагины и запускает контейнер с приложение на каждом инстансе, полученном с помощью динамического inventory.
- Инструкции по запуску инфраструктуры можно найти в infra README
- Для доступа к приложению нужно открыть порт
9292
(использовать скрипт gcloud_add_firewall_rule_puma.sh):
gcloud compute firewall-rules create reddit-app \
--allow tcp:9292 \
--target-tags=docker-machine \
--description="Allow PUMA connections" \
--direction=INGRESS
- Скопирован код микросервисов
- Созданы Dockerfile для каждого сервиса:
- Все файлы пропущены через линтер командой
docker run --rm -i hadolint/hadolint < Dockerfile
- Найденые проблемы исправлены
- Выполнена сборка образов командами
docker build -t nikitagsh/post:1.0 ./post-py
docker build -t nikitagsh/comment:1.0 ./comment
docker build -t nikitagsh/ui:1.0 ./ui
- Сборка ui началась с шага копирования Gemfile
- Запущено приложение командами, запущено приложение, проверена работоспособность
- (★) Запуск с другими алиасами:
- Остановить все контейнеры
docker kill $(docker ps -q)
docker run -d --network=reddit --network-alias=post_db_alt --network-alias=comment_db_alt mongo:latest
docker run -d --network=reddit --network-alias=post_alt -e POST_DATABASE_HOST=post_db_alt nikitagsh/post:1.0
docker run -d --network=reddit --network-alias=comment_alt -e COMMENT_DATABASE_HOST=comment_db_alt nikitagsh/comment:1.0
docker run -d --network=reddit -e POST_SERVICE_HOST=post_alt -e COMMENT_SERVICE_HOST=comment_alt -p 9292:9292 nikitagsh/ui:1.0
- Остановить все контейнеры
- Изменен образ UI, сборка началась с 1 шага, так как изменился базовый образ
- (★) Образ UI собран из ruby:alpine, понадобилось добавить build-base для сборки приложения.
- Образ на основе
FROM ruby:2.2-alpine
с удалениемbuild-base
вышел 162 Mb, но теперь установка пакетов не кэшируется (Dockerfile.1) - Образ собранный из
FROM alpine:3.11.6
без удаленияbuild-base
весит 253 Mb (Dockerfile)
- Образ на основе
- Создан Volume
docker volume create reddit_db
- Созданный volume подключен к базе с помощью флага
-v reddit_db:/data/db
. Теперь посты переживают перезапуск контейнеров.
- Команды для запуска:
docker network create reddit
docker run -d --network=reddit --network-alias=post_db --network-alias=comment_db -v reddit_db:/data/db mongo:latest
docker run -d --network=reddit --network-alias=post nikitagsh/post:1.0
docker run -d --network=reddit --network-alias=comment nikitagsh/comment:1.0
docker run -d --network=reddit -p 9292:9292 nikitagsh/ui:3.0
- Выполнить
docker-machine ls
для получени IP адреса docker-host - Зайти на
http://<docker-host-ip>:9292/
- Написать пост
-
Выполнены эксперименты с запуском docker-контейнеров в сети с драйверами none, host, bridge
-
Запуск больше одного контейнера nginx с
--network host
невозможен так как порт уже занят, возникает ошибка, в случае запуска nginx с--network none
все хорошо - каждый раз создаётся отдельный network namespace. -
Сервисы запущены через
docker run
с использование двух сетейfront_net
иback_net
, так чтобы ui не имел доступа к mongodb. При запуске докер может добавить только одну сеть, подсоединять новую надо отдельной командойdocker network connect front_net post
. -
Проведены исследования bridge-интерфейсов и сетей на docker-machine.
-
Создан файл docker-compose.yml
- Добавлен alias
comment_db
для базы, иначе сервис комментариев ее не видит. Можно так же подправить переменную окружения в docker-compose.yml для сервиса comment.
- Добавлен alias
-
Создан файл с переменными .env, docker-compose.yml параметризован
-
Созданные сущности имеют префикс
src
- название директории, в которой находится docker-compose.yml. Можно переопределить с помощью:- COMPOSE_PROJECT_NAME
- Из командной строки с ключом -p, --project-name NAME
- Примечание: ключ командной строки перебивает значение переменной.
-
(★) Создан
docker-compose.override.yml
для запуска puma в режиме debug с двумя воркерами, а также с возможностью динамического редактирования кодаdocker-compose.override.yml
ломает запуск приложения на docker-host, так как на нем нет копии нужных файлов. Локально все работает.
- docker-compose up -d
- docker-compose down
- Выполнить
docker-machine ls
для получени IP адреса docker-host - Зайти на
http://<docker-host-ip>:9292/
- Написать пост
- Запущен docker-host в GCE
- Установлен gitlab
- Запущен docker runner для проекта
- Создан Gitlab-проект и настроен для использования CI/CD. Этот репозиторий запушен в него как в дополнительный remote.
- CI/CD сконфигурирован запускать тесты, ссылаться на динамические окружения с учетом требований к веткам и других ограничений (тэги, ручной запуск).
- Выполнить скрипт запуска docker-host в GCE
- Выполнить скрипт установки Gitlab
(выполнять из папки
gitlab-ci/docker-machine/
)
- Используя docker-machine (
eval $(docker-machine env gitlab-ci)
) - Выполнить
docker run -d --name gitlab-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
- Для регистрации runner выполнить
docker exec -it gitlab-runner gitlab-runner register --run-untagged --locked=false
- После установки Gitlab на VM можно перейти по http://VM_PUBLIC_IP. (Начальная инициализация Gitlab может занять несколько минут)
- Добавленные для проекта раннеры видны тут: http://VM_PUBLIC_IP/group/project/-/settings/ci_cd
- Запущен docker-host в GCE: команды тут
- Добалвен Docker образ для Prometheus
- Собраны образы сервисов командами
bash docker_build.sh
в каждой из папокsrc/ui
,src/post-py
,src/comment
- Prometheus добавлен в docker-compose.yml
- Использован UI Prometheus для проверки состояния приложения
- Добавлен node_exporter
- Собранные образы запушены в Docker Hub
- Добавлены экспортеры:
- (★) Добавлен Makefile для сборки образов и доставки их в Docker Registry
- Создать инстанс в GCE: команды тут
- Создать правила файервола: script
- Собрать все необходимые образы командой
make b_all
- Запустить докер-инфраструктуру
cd ./docker
docker-compose -f docker-compose.yml up -d
- Запушить в Docker Registry можно командо
make p_all
- Получить IP адрес VM с запущенными сервисами
docker-machine ip docker-host
- Приложение должно быть доступно по http://docker-host-ip:9292
- Prometheus должен быть доступен по http://docker-host-ip:9090
-
Рефакторинг docker-compose файла, разбит на docker-compose.yml и docker-compose-monitoring.yml
-
Добавлены источники метрик для Prometheus:
-
cAdvisor для докер-метрик
-
сервиса post
-
-
В составе мониторинг-кластера поднята Grafanа.
-
Настроены дашборды в Grafana:
-
Импортирован дашборд для Докера
-
Дашборд для мониторинга состояния приложения
-
Дашборд для мониторинга бизнес-метрик
-
-
С помощью Alertmanager настроен алёрт в Slack-канал #nikita_shvyryaev о недоступности любого из компонентов приложения
-
Созадть GCP-инстанс
export GOOGLE_PROJECT=_your_project_ docker-machine create --driver google \ --google-machine-image https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/family/ubuntu-1604-lts \ --google-machine-type n1-standard-1 \ --google-zone europe-west1-b \ docker-host
-
Создать правила файервола для открытия наружу портов tcp 8080, 8000, 3000
-
Переключиться на докер-окружение (см. подробнее в здесь)
eval $(docker-machine env docker-host) export USER_NAME=nikitagsh
-
Запустить докер-инфраструктуру приложения и мониторинга
cd ./docker docker-compose -f docker-compose.yml up -d docker-compose -f docker-compose-monitoring.yml up -d
-
В Grafan'e создать источник данных Prometheus и импортировать дашборды
-
Получить IP адрес VM с запущенными сервисами
docker-machine ip docker-host
-
Приложение должно быть доступно по http://docker-host-ip:9292
-
Prometheus должен быть доступен по http://docker-host-ip:9000
-
cAdviser должен быть доступен по http://docker-host-ip:8080
-
Grafana должы быть доступна по http://docker-host-ip:3000
-
Метрики отдельных экспортеров доступны на их портах, если были добавлены соответствующие правила файервола.
-
Собраны образы сервисов приложения под тэгом
logging
-
Создан отдельный docker-compose-logging.yml, который запускает сервисы Fluentd, ElasticSearch, Kibana, Zipkin
ElasticSearch запускается в development & testing режиме с помощью env
discovery.type=single-node
-
Севрис post настроен отправлять логи во Fluentd, которые парсятся json-фильтром. Сервис ui настроен отправлять неструктурированные логи во Fluentd, которые парсятся regex-ами или grok-фильтрами в нужный формат.
-
В Kibana создан индекс-паттерн для наблюдения за логами.
-
В Zipkin произведен трэйсинг запросов на ui сервис
-
Создать GCP-инстанс (ссылка на gist)
-
Создать правила файервола: разрешить порты tcp:5601,9292,9411
-
Переключиться на докер-окружение
eval $(docker-machine env logging) export USER_NAME=nikitagsh
-
Запустить докер-инфраструктуру логгинга и приложения
cd ./docker docker-compose -f docker-compose-logging.yml up -d docker-compose -f docker-compose.yml up -d
-
Получить IP адрес VM с запущенными сервисами
docker-machine ip docker-host
-
Приложение должно быть доступно по http://docker-host-ip:9292
-
Kibana должна быть доступен по http://docker-host-ip:5601
-
Zipkin должен быть доступен по http://docker-host-ip:9411
-
Метрики отдельных экспортеров доступны на их портах, если были добавлены соответствующие правила файервола.
-
Kubernetes кластер развернут в GCP вручную, следуя туториалу The Hard Way
Выполненные шаги и заметки собраны здесь
-
Проверено, что в созданном K8s-кластере заготовки деплойментов (*-deployment.yml) применяются и поды создаются
-
Выполнить инстукции туториала The Hard Way
Чтобы учесть огрничение GCP в 4 IP-адресса, вместо 3 контроллеров и 3 воркеров, создаются 2 контролллера и 2 воркера. Команды из инструкции были скорректированы с учетом этого
-
Проверка работоспособности K8s-кластера выполняется шагом Smoke Test
-
Проверить запуск подов reddit-приложения можно командой
kubectl get pods
-
Reddit-приложение развернуто в локальном K8s кластере
minikube
в отдельном нэймспэйсеdev
.- По 3 реплики(пода) на каждый сервис: ui, comment, post.
- 1 реплика MongoDB с персистентным хранилищем.
- Созданы k8s-сервисы для взаимодействия между компонентами и БД
- Создан сервис типа NodePort для доступа к веб-интерфейсу всего приложения извне.
-
Создан GKE-кластер вручную.
-
Reddit-приложение развернуто в GKE k8s кластере. Шаги для запуска см. в KUBERNETES.md
-
(⭐) Создан GKE-кластер с помощью Terraform
-
(⭐) Настроено использование dashboard addon'а для кластера. Шаги по настройке см. в DASHBOARD.md
Примечание: при использовании дашборда на минимальных инстансах не хватает CPU для размещения pod'ов приложения.
-
Создать k8s кластер
-
локальный
minikube start
-
или в GKE с помощью Terrafrom. См KUBERNETES.md
cd ./kubernetes/terraform terraform init terraform plan terraforn apply
-
-
Создать нэймспэйс
kubectl apply -f ./kubernetes/reddit/dev-namespace.yml
-
Применить деплойменты и сервисы для приложения
kubectl apply -f ./kubernetes/reddit/. -n dev
-
Включить dashboard addon для кластера в GKE и настроить его использование. См. DASHBOARD.md Запустить проксирование дашборда на локалхост
kubectl proxy
-
Проверить текущий K8s контекст
kubectl config current-context
-
Проверить наличие и состояние ресурсов приложения
kubectl get all -n dev
-
Приложение должно быть доступно по
http://<node_ip>:<node_port>
, гдеnode_ip
можно получить из вывода командыkubectl get nodes -o wide
а
nodeport
- из вывода командыkubectl describe service ui -n dev | grep NodePort
-
K8s дашборд должен быть доступен по http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
-
Проведен эксперимент: Деплойменты
kube-dns-autoscaler
иkube-dns
(namespacekube-system
) проскейлены в 0 В этой конфигурации поды перестают иметь сетевой доступ друг к другу. -
Опробованы следующие способы публикации
ui
сервиса:- LoadBalancer
- Ingress
- Не удалось запустить Ingress одновременно с LoadBalancer - заработало только вместе с NodePort
- Ingress с TLS терминацией
- (⭐) Созданный tls-сертификат загружается в кластер с помощью ui-tls-secret.yml
-
Сетевой доступ к MongoDB ограничен post и comment сервисами с помощью NetworkPolicy. Для этого для кластера включается GKE-плагин network policy CALICO с помощью Terraform
-
Для хранения данных MongoDB задействован volume:
- emptyDir (удаляется при удалениик деплоймента)
- gcePersistentDisk (используется целый диск)
- PersistentVolume (используется часть диска) по запросу PersistentVolumeClaim cо Standard storage-class'ом
- динамически PersistentVolumeClaim'ом с fast (ssd) storage-class'ом
-
Создать k8s кластер в GKE с помощью Terrafrom. (Подробнее см. KUBERNETES.md)
cd ./kubernetes/terraform terraform init terraform plan terraforn apply
-
Создать namespace
kubectl apply -f ./kubernetes/reddit/dev-namespace.yml
-
Создать деплойменты, сервисы и прочие ресурсы для приложения
kubectl apply -f ./kubernetes/reddit/. -n dev
-
Выпустить TLS сертификат для Ingress
export INGRESS_IP=$(kubectl get ingress ui -n dev -o jsonpath='{.status.loadBalancer.ingress[0].ip}') openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$INGRESS_IP"
и загрузить его в кластер с помощью
kubectl apply -f ./ui-tls-secret.yml -n dev
гдеdata: tls.crt: cat ./tls.crt | base64 tls.key: cat ./tls.key | base64
-
Проверить текущий K8s контекст
kubectl config current-context
-
Проверить наличие и состояние ресурсов приложения
kubectl get all -n dev
-
Приложение должно быть доступно по
https://<ingress_ip>
, гдеingress_ip
можно получить из вывода командыkubectl get ingress ui -n dev -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
-
Развертывание kubernetes-компонентов для ui, comment, post щаблонизировано с помощью Helm. См kubernetes/Charts. Для деплоя создан общий чарт reddit, зависящий от ui, comment, post
-
Установка Helm-релиза reddit-приложения осуществлена с помощью
- Helm2 + Tiller (server side)
- Helm2 + Tiller plugin
- Helm3
Подробнее см. HELM.md
-
В Kubernetes-кластере поднят Gitlab с с помощью opensource Helm-чарта
-
Под каждую из компонент Reddit-приложения, включая деплой, создан отдельный репозиторий со своим CI/CD пайплайном
-
Для feature-веток поднимаются динамические окружения
-
Деплой всего приложения осуществяется на статические окружения: staging, production
-
Создать k8s кластер в GKE с помощью Terrafrom. (Подробнее см. KUBERNETES.md)
cd ./kubernetes/terraform terraform init terraform plan terraforn apply
-
С помощью Helm задеплоить релиз
cd kubernetes/Charts helm install --name <release-name> ./reddit
-
Установить Gitlab
helm install --name gitlab ./gitlab-omnibus -f values.yaml
-
Для доступа на Gitlab UI добавить в
/etc/hosts
IP адрес gitlab ingress'аGITLAB_IP=$(kubectl get service -n nginx-ingress nginx -o jsonpath="{.status.loadBalancer.ingress[0].ip}") echo "$GITLAB_IP gitlab-gitlab staging production" >> /etc/hosts
Поступить аналогично в случае динамических окружений feature-веток
-
Проверить текущий K8s контекст
kubectl config current-context
-
Проверить наличие и состояние ресурсов приложения
kubectl get all
-
Приложение должно быть доступно по
https://<ingress_ip>
, гдеingress_ip
можно получить из вывода командыkubectl get ingress ui -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
-
Gitlab UI должен быть доступен по
http://<gitlab_ingress_ip
kubectl get service -n nginx-ingress nginx -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
-
Запушить изменения в репозиторий, соответсвующий компоненте: ui, comment, post, reddit. Динамические и статические окружения должны быть доступны по
http://<staging|production|branch>
- Скорректирован Terraform-проект для развертывания Kubernetes кластера.
-
Из актуального Helm-чарта развернут Prometheus вместе с Alertmanager. Настройки для чарта: custom_values.yaml
-
Добавлены таргеты для Prometheus для компонент reddit-приложения: ui, comment, post. Настроен relabling
-
Из
stable/grafana
чарта развернута Grafana.В ней добавлены дашборды:
- Kubernetes cluster monitoring (via Prometheus)
- Kubernetes Deployment metrics
- а также busines metrics дашборды из предыдущего задания по Логгированию. Эти дашборды параметризованы Env-переменной, берущейся из kubernetes namepspace.
-
Создать k8s кластер в GKE с помощью Terrafrom. (Подробнее см. KUBERNETES.md)
cd ./kubernetes/terraform terraform init terraform plan terraforn apply
Дальнейшие действия описаны в MONITORING.md. А именно:
-
Задеплоить reddit приложение
cd kubernetes/Charts/ helm upgrade staging --namespace ./reddit --install
-
С помощью Helm задеплоить nginx
helm install stable/nginx-ingress --name nginx
Прописать адрес nginx в
/etc/hosts
:<IP> reddit reddit-prometheus reddit-grafana reddit-non-prod production redditkibana staging prod
-
Задеплоить Prometheus
cd kubernetes/Charts/prometheus helm upgrade prom . -f custom_values.yaml --install
-
Установить Grafana
helm upgrade --install grafana stable/grafana \ --set "adminPassword=admin" \ --set "service.type=NodePort" \ --set "ingress.enabled=true" \ --set "ingress.hosts={reddit-grafana}"
-
Проверить текущий K8s контекст
kubectl config current-context
-
Проверить наличие и состояние ресурсов приложения
kubectl get all
-
Приложение, Prometheus должны быть доступны по прописанным в
/etc/hosts
адресам по http.