dapp — наша Open Source-утилита, помогающая DevOps-инженерам сопровождать процессы CI/CD (Обновлено 13 августа 2019 г.: в настоящее время проект dapp переименован в werf, его код полностью переписан на Go, а документация значительно улучшена) (подробнее о ней читайте в анонсе). В документации к ней приведён пример сборки простого приложения, а подробнее этот процесс (с демонстрацией основных возможностей dapp) был представлен в первой части статьи. Теперь, на основе того же простого приложения, покажу, как dapp работает с кластером Kubernetes.

Как и в первой статье, все дополнения для кода приложения symfony-demo есть в нашем репозитории. Но обойтись
Чтобы пройти всё по шагам, нужно начать с ветки
Теперь нужно создать кластер Kubernetes, где dapp запустит приложение. Для этого будем использовать Minikube как рекомендуемый способ запуска кластера на локальной машине.
Установка проста и заключается в скачивании Minikube и утилиты kubectl. Инструкции доступны по ссылкам:
Примечание: Читайте также наш перевод статьи «Начало работы в Kubernetes с помощью Minikube».
После установки нужно запустить
После успешного старта можно посмотреть, что есть в кластере:
Команда покажет все ресурсы в пространстве имён (namespace) по умолчанию (
Итак, мы запустили кластер Kubernetes в виртуальной машине. Что ещё понадобится для запуска приложения?
Во-первых, для этого нужно загрузить образ туда, откуда кластер сможет его получить. Можно использовать общий Docker Registry или же установить свой Registry в кластере (мы так делаем для production-кластеров). Для локальной разработки тоже лучше подойдет второй вариант, а реализовать его с dapp совсем просто — для этого есть специальная команда:
После её выполнения в списке системных процессах появляется такое перенаправление:
… а в namespace под названием
Протестируем запущенный Registry, выложив в него наш образ командой
Видно, что тег образа в Registry составлен из имени dimg и имени ветки (через дефис).
Вторая часть, необходимая для запуска приложения в кластере, — это конфигурация ресурсов. Стандартной утилитой управления кластером Kubernetes является
Однако dapp не использует напрямую
Поэтому наш следующий шаг — это установка Helm. Официальную инструкцию можно найти в документации проекта.
После установки необходимо запустить
(Здесь и далее знаком «!!!» вручную выделены строки, на которые стоит обратить внимание.)
То есть: появился Deployment под названием
Третья часть — сама конфигурация для приложения. На данном этапе нужно понять, что требуется выложить в кластер, чтобы приложение заработало.
Предлагается следующая схема:
IngressController — это дополнительный компонент кластера Kubernetes для организации веб-приложений с балансировкой нагрузки. По сути это nginx, конфигурация которого зависит от ресурсов Ingress, добавляемых в кластер. Компонент нужно ставить отдельно, а для minikube существует addon. Подробнее о нём можно почитать в этой статье на английском, а пока просто запустим установку IngressController:
… и посмотрим, что появилось в кластере:
Как проверить? IngressController в своём составе имеет
Результат положительный — приходит ответ от nginx со строкой
Теперь можно описать конфигурацию приложения. Базовую конфигурацию поможет сгенерировать команда
dapp ожидает эту структуру в директории под названием
Мы сейчас создали описание chart'а. Chart — это единица конфигурации для Helm, можно думать о нём как о неком пакете. Например, есть chart для nginx, для MySQL, для Redis. И с помощью таких chart'ов можно собрать нужную конфигурацию в кластере. Helm выкладывает в Kubernetes не отдельные образы, а именно Chart'ы (официальная документация).
Файл
Файл
Директория
Наконец, директория
Для начала опишем простой вариант Deployment для нашего приложения:
В конфигурации описано, что нам нужна пока что одна реплика, а в
Упомянутое в конфиге
Переменая
Далее опишем Service:
Этим ресурсом мы создаём DNS-запись
Эти два описания объединяются через
Теперь всё готово, чтобы запустить
Видим, что в кластере появляется под в состоянии
… и через некоторое время всё работает:
Создан ReplicaSet, Pod, Service, то есть приложение запущено. Это можно проверить «по старинке», зайдя в контейнер:
Теперь, чтобы приложение стало доступно по
Появился
В целом можно считать, что развёртывание приложения в Minikube удалось. Из запроса видно, что IngressController перебрасывает на 443-й порт и приложение отвечает, что нужно проверить
Чтобы увидеть нормальную страницу приложения, нужно развернуть приложение с другой настройкой либо для тестов закомментировать этот блок. Повторный деплой в Kubernetes (после правок в коде приложения) выглядит так:
Под пересоздался, можно зайти браузером и увидеть красивую картинку:

С помощью Minikube и Helm можно тестировать свои приложения в кластере Kubernetes, а dapp поможет в сборке, развёртывании своего Registry и самого приложения.
В статье не упомянуты секретные переменные, которые можно использовать в шаблонах для приватных ключей, паролей и прочей закрытой информации. Об этом напишем отдельно.
Читайте также в нашем блоге:

Как и в первой статье, все дополнения для кода приложения symfony-demo есть в нашем репозитории. Но обойтись
Vagrantfile в этот раз не получится: Docker и dapp придётся поставить локально.Чтобы пройти всё по шагам, нужно начать с ветки
dapp_build, куда был добавлен Dappfile в первой статье.$ git clone https://github.com/flant/symfony-demo.git $ cd symfony-demo $ git checkout dapp_build $ git checkout -b kube_test $ dapp dimg build
Запуск кластера с помощью Minikube
Теперь нужно создать кластер Kubernetes, где dapp запустит приложение. Для этого будем использовать Minikube как рекомендуемый способ запуска кластера на локальной машине.
Установка проста и заключается в скачивании Minikube и утилиты kubectl. Инструкции доступны по ссылкам:
Примечание: Читайте также наш перевод статьи «Начало работы в Kubernetes с помощью Minikube».
После установки нужно запустить
minikube setup. Minikube скачает ISO и запустит из него виртуальную машину в VirtualBox.После успешного старта можно посмотреть, что есть в кластере:
$ kubectl get all NAME READY STATUS RESTARTS AGE po/hello-minikube-938614450-zx7m6 1/1 Running 3 71d NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-minikube 10.0.0.102 <nodes> 8080:31429/TCP 71d svc/kubernetes 10.0.0.1 <none> 443/TCP 71d NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/hello-minikube 1 1 1 1 71d NAME DESIRED CURRENT READY AGE rs/hello-minikube-938614450 1 1 1 71d
Команда покажет все ресурсы в пространстве имён (namespace) по умолчанию (
default). Список всех namespaces можно посмотреть через kubectl get ns.Подготовка, шаг №1: реестр для образов
Итак, мы запустили кластер Kubernetes в виртуальной машине. Что ещё понадобится для запуска приложения?
Во-первых, для этого нужно загрузить образ туда, откуда кластер сможет его получить. Можно использовать общий Docker Registry или же установить свой Registry в кластере (мы так делаем для production-кластеров). Для локальной разработки тоже лучше подойдет второй вариант, а реализовать его с dapp совсем просто — для этого есть специальная команда:
$ dapp kube minikube setup Restart minikube [RUNNING] minikube: Running localkube: Running kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100 Starting local Kubernetes v1.6.4 cluster... Starting VM... Moving files into cluster... Setting up certs... Starting cluster components... Connecting to cluster... Setting up kubeconfig... Kubectl is now configured to use the cluster. Restart minikube [OK] 34.18 sec Wait till minikube ready [RUNNING] Wait till minikube ready [OK] 0.05 sec Run registry [RUNNING] Run registry [OK] 61.44 sec Run registry forwarder daemon [RUNNING] Run registry forwarder daemon [OK] 5.01 sec
После её выполнения в списке системных процессах появляется такое перенаправление:
username 13317 0.5 0.4 57184 36076 pts/17 Sl 14:03 0:00 kubectl port-forward --namespace kube-system kube-registry-6nw7m 5000:5000
… а в namespace под названием
kube-system создаётся Registry и прокси к нему:$ kubectl get -n kube-system all NAME READY STATUS RESTARTS AGE po/kube-addon-manager-minikube 1/1 Running 2 22m po/kube-dns-1301475494-7kk6l 3/3 Running 3 22m po/kube-dns-v20-g7hr9 3/3 Running 9 71d po/kube-registry-6nw7m 1/1 Running 0 3m po/kube-registry-proxy 1/1 Running 0 3m po/kubernetes-dashboard-9zsv8 1/1 Running 3 71d po/kubernetes-dashboard-f4tp1 1/1 Running 1 22m NAME DESIRED CURRENT READY AGE rc/kube-dns-v20 1 1 1 71d rc/kube-registry 1 1 1 3m rc/kubernetes-dashboard 1 1 1 71d NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 71d svc/kube-registry 10.0.0.142 <none> 5000/TCP 3m svc/kubernetes-dashboard 10.0.0.249 <nodes> 80:30000/TCP 71d NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/kube-dns 1 1 1 1 22m NAME DESIRED CURRENT READY AGE rs/kube-dns-1301475494 1 1 1 22m
Протестируем запущенный Registry, выложив в него наш образ командой
dapp dimg push --tag-branch :minikube. Используемый здесь :minikube — это встроенный в dapp алиас специально для Minikube, который будет преобразован в localhost:5000/symfony-demo.$ dapp dimg push --tag-branch :minikube symfony-demo-app localhost:5000/symfony-demo:symfony-demo-app-kube_test [PUSHING] pushing image `localhost:5000/symfony-demo:symfony-demo-app-kube_test` [RUNNING] The push refers to a repository [localhost:5000/symfony-demo] 0ea2a2940c53: Preparing ffe608c425e1: Preparing 5c2cc2aa6663: Preparing edbfc49bce31: Preparing 308e5999b491: Preparing 9688e9ffce23: Preparing 0566c118947e: Preparing 6f9cf951edf5: Preparing 182d2a55830d: Preparing 5a4c2c9a24fc: Preparing cb11ba605400: Preparing 6f9cf951edf5: Waiting 182d2a55830d: Waiting 5a4c2c9a24fc: Waiting cb11ba605400: Waiting 9688e9ffce23: Waiting 0566c118947e: Waiting 0ea2a2940c53: Layer already exists 308e5999b491: Layer already exists ffe608c425e1: Layer already exists edbfc49bce31: Layer already exists 5c2cc2aa6663: Layer already exists 0566c118947e: Layer already exists 9688e9ffce23: Layer already exists 182d2a55830d: Layer already exists 6f9cf951edf5: Layer already exists cb11ba605400: Layer already exists 5a4c2c9a24fc: Layer already exists symfony-demo-app-kube_test: digest: sha256:5c55386de5f40895e0d8292b041d4dbb09373b78d398695a1f3e9bf23ee7e123 size: 2616 pushing image `localhost:5000/symfony-demo:symfony-demo-app-kube_test` [OK] 0.54 sec
Видно, что тег образа в Registry составлен из имени dimg и имени ветки (через дефис).
Подготовка, шаг №2: конфигурация ресурсов (Helm)
Вторая часть, необходимая для запуска приложения в кластере, — это конфигурация ресурсов. Стандартной утилитой управления кластером Kubernetes является
kubectl. Если нужно создать новый ресурс (Deployment, Service, Ingress и т.д.) или изменить свойства существующего ресурса, то на вход утилите передаётся YAML-файл с конфигурацией.Однако dapp не использует напрямую
kubectl, а работает с так называемым пакетным менеджером — Helm, — который предоставляет шаблонизацию YAML-файлов и сам управляет выкатом в кластер.Поэтому наш следующий шаг — это установка Helm. Официальную инструкцию можно найти в документации проекта.
После установки необходимо запустить
helm init. Что она делает? Helm состоит из клиентской части, которую мы установили, и серверной. Команда helm init устанавливает серверную часть (tiller). Посмотрим, что появилось в namespace kube-system:$ kubectl get -n kube-system all NAME READY STATUS RESTARTS AGE po/kube-addon-manager-minikube 1/1 Running 2 1h po/kube-dns-1301475494-7kk6l 3/3 Running 3 1h po/kube-dns-v20-g7hr9 3/3 Running 9 71d po/kube-registry-6nw7m 1/1 Running 0 1h po/kube-registry-proxy 1/1 Running 0 1h po/kubernetes-dashboard-9zsv8 1/1 Running 3 71d po/kubernetes-dashboard-f4tp1 1/1 Running 1 1h !!! po/tiller-deploy-3703072393-bdqn8 1/1 Running 0 3m NAME DESIRED CURRENT READY AGE rc/kube-dns-v20 1 1 1 71d rc/kube-registry 1 1 1 1h rc/kubernetes-dashboard 1 1 1 71d NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 71d svc/kube-registry 10.0.0.142 <none> 5000/TCP 1h svc/kubernetes-dashboard 10.0.0.249 <nodes> 80:30000/TCP 71d !!! svc/tiller-deploy 10.0.0.196 <none> 44134/TCP 3m NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/kube-dns 1 1 1 1 1h !!! deploy/tiller-deploy 1 1 1 1 3m NAME DESIRED CURRENT READY AGE rs/kube-dns-1301475494 1 1 1 1h !!! rs/tiller-deploy-3703072393 1 1 1 3m
(Здесь и далее знаком «!!!» вручную выделены строки, на которые стоит обратить внимание.)
То есть: появился Deployment под названием
tiller-deploy с одним ReplicaSet и одним подом (Pod). Для Deployment сделан одноимённый Service (tiller-deploy), который открывает доступ через порт 44134.Подготовка, шаг №3: IngressController
Третья часть — сама конфигурация для приложения. На данном этапе нужно понять, что требуется выложить в кластер, чтобы приложение заработало.
Предлагается следующая схема:
- приложение — это Deployment. Для начала это будет один ReplicaSet из одного пода, как сделано для Registry;
- приложение отвечает на порту 8000, поэтому нужно определить Service, чтобы под смог отвечать на запросы извне;
- у нас веб-приложение, поэтому нужен способ получать пакеты от пользователей на 80-м порту. Это делается ресурсом Ingress. Для работы таких ресурсов нужно настроить IngressController.
IngressController — это дополнительный компонент кластера Kubernetes для организации веб-приложений с балансировкой нагрузки. По сути это nginx, конфигурация которого зависит от ресурсов Ingress, добавляемых в кластер. Компонент нужно ставить отдельно, а для minikube существует addon. Подробнее о нём можно почитать в этой статье на английском, а пока просто запустим установку IngressController:
$ minikube addons enable ingress ingress was successfully enabled
… и посмотрим, что появилось в кластере:
$ kubectl get -n kube-system all NAME READY STATUS RESTARTS AGE !!! po/default-http-backend-vbrf3 1/1 Running 0 2m po/kube-addon-manager-minikube 1/1 Running 2 3h po/kube-dns-1301475494-7kk6l 3/3 Running 3 3h po/kube-dns-v20-g7hr9 3/3 Running 9 72d po/kube-registry-6nw7m 1/1 Running 0 3h po/kube-registry-proxy 1/1 Running 0 3h po/kubernetes-dashboard-9zsv8 1/1 Running 3 72d po/kubernetes-dashboard-f4tp1 1/1 Running 1 3h !!! po/nginx-ingress-controller-hmvg9 1/1 Running 0 2m po/tiller-deploy-3703072393-bdqn8 1/1 Running 0 1h NAME DESIRED CURRENT READY AGE !!! rc/default-http-backend 1 1 1 2m rc/kube-dns-v20 1 1 1 72d rc/kube-registry 1 1 1 3h rc/kubernetes-dashboard 1 1 1 72d !!! rc/nginx-ingress-controller 1 1 1 2m NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE !!! svc/default-http-backend 10.0.0.131 <nodes> 80:30001/TCP 2m svc/kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 72d svc/kube-registry 10.0.0.142 <none> 5000/TCP 3h svc/kubernetes-dashboard 10.0.0.249 <nodes> 80:30000/TCP 72d svc/tiller-deploy 10.0.0.196 <none> 44134/TCP 1h NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/kube-dns 1 1 1 1 3h deploy/tiller-deploy 1 1 1 1 1h NAME DESIRED CURRENT READY AGE rs/kube-dns-1301475494 1 1 1 3h rs/tiller-deploy-3703072393 1 1 1 1h
Как проверить? IngressController в своём составе имеет
default-http-backend, который отвечает ошибкой 404 на все страницы, для которых нет обработчика. Это можно увидеть такой командой:$ curl -i $(minikube ip) HTTP/1.1 404 Not Found Server: nginx/1.13.1 Date: Fri, 14 Jul 2017 14:29:46 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 21 Connection: keep-alive Strict-Transport-Security: max-age=15724800; includeSubDomains; default backend - 404
Результат положительный — приходит ответ от nginx со строкой
default backend - 404.Описание конфигурации для Helm
Теперь можно описать конфигурацию приложения. Базовую конфигурацию поможет сгенерировать команда
helm create имя_приложения:$ helm create symfony-demo $ tree symfony-demo symfony-demo/ ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── ingress.yaml │ ├── NOTES.txt │ └── service.yaml └── values.yaml
dapp ожидает эту структуру в директории под названием
.helm (см. документацию), поэтому нужно переименовать symfony-demo в .helm.Мы сейчас создали описание chart'а. Chart — это единица конфигурации для Helm, можно думать о нём как о неком пакете. Например, есть chart для nginx, для MySQL, для Redis. И с помощью таких chart'ов можно собрать нужную конфигурацию в кластере. Helm выкладывает в Kubernetes не отдельные образы, а именно Chart'ы (официальная документация).
Файл
Chart.yaml — это описание chart'а нашего приложения. Здесь нужно указать как минимум имя приложения и версию:$ cat Chart.yaml apiVersion: v1 description: A Helm chart for Kubernetes name: symfony-demo version: 0.1.0
Файл
values.yaml — описание переменных, которые будут доступны в шаблонах. Например, в сгенерированном файле есть image: repository: nginx. Эта переменная будет доступна через такую конструкцию: {{ .Values.image.repository }}.Директория
charts пока пуста, потому что наш chart приложения пока не использует внешние chart'ы.Наконец, директория
templates — здесь хранятся шаблоны YAML-файлов с описанием ресурсов для их размещения в кластере. Сгенерированные шаблоны не сильно нужны, поэтому с ними можно ознакомиться и удалить.Для начала опишем простой вариант Deployment для нашего приложения:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: {{ .Chart.Name }}-backend spec: replicas: 1 template: metadata: labels: app: {{ .Chart.Name }}-backend spec: containers: - command: [ '/opt/start.sh' ] image: {{ tuple "symfony-demo-app" . | include "dimg" }} imagePullPolicy: Always name: {{ .Chart.Name }}-backend ports: - containerPort: 8000 name: http protocol: TCP env: - name: KUBERNETES_DEPLOYED value: "{{ now }}"
В конфигурации описано, что нам нужна пока что одна реплика, а в
template указано, какие поды нужно реплицировать. В этом описании указывается образ, который будет запускаться и порты, которые доступны другим контейнерам в поде.Упомянутое в конфиге
.Chart.Name — это значение из charts.yaml.Переменая
KUBERNETES_DEPLOYED нужна, чтобы Helm обновлял поды, если мы обновим образ без изменения тега. Это удобно для отладки и локальной разработки.Далее опишем Service:
apiVersion: v1 kind: Service metadata: name: {{ .Chart.Name }}-srv spec: type: ClusterIP selector: app: {{ .Chart.Name }}-backend ports: - name: http port: 8000 protocol: TCP
Этим ресурсом мы создаём DNS-запись
symfony-demo-app-srv, по которой другие Deployments смогут получать доступ к приложению. Эти два описания объединяются через
--- и записываются в .helm/templates/backend.yaml, после чего можно разворачивать приложение!Первый деплой
Теперь всё готово, чтобы запустить
dapp kube deploy (Обновлено 13 августа 2019 г.: подробнее см. в документации werf):$ dapp kube deploy :minikube --image-version kube_test Deploy release symfony-demo-default [RUNNING] Release "symfony-demo-default" has been upgraded. Happy Helming! LAST DEPLOYED: Fri Jul 14 18:32:38 2017 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE symfony-demo-app-backend 1 1 1 0 7s ==> v1/Service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE symfony-demo-app-srv 10.0.0.173 <none> 8000/TCP 7s Deploy release symfony-demo-default [OK] 7.02 sec
Видим, что в кластере появляется под в состоянии
ContainerCreating:po/symfony-demo-app-backend-3899272958-hzk4l 0/1 ContainerCreating 0 24s
… и через некоторое время всё работает:
$ kubectl get all NAME READY STATUS RESTARTS AGE po/hello-minikube-938614450-zx7m6 1/1 Running 3 72d !!! po/symfony-demo-app-backend-3899272958-hzk4l 1/1 Running 0 47s NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc/hello-minikube 10.0.0.102 <nodes> 8080:31429/TCP 72d svc/kubernetes 10.0.0.1 <none> 443/TCP 72d !!! svc/symfony-demo-app-srv 10.0.0.173 <none> 8000/TCP 47s NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE deploy/hello-minikube 1 1 1 1 72d deploy/symfony-demo-app-backend 1 1 1 1 47s NAME DESIRED CURRENT READY AGE rs/hello-minikube-938614450 1 1 1 72d !!! rs/symfony-demo-app-backend-3899272958 1 1 1 47s
Создан ReplicaSet, Pod, Service, то есть приложение запущено. Это можно проверить «по старинке», зайдя в контейнер:
$ kubectl exec -ti symfony-demo-app-backend-3899272958-hzk4l bash root@symfony-demo-app-backend-3899272958-hzk4l:/# curl localhost:8000
Открываем доступ
Теперь, чтобы приложение стало доступно по
$(minikube ip), добавим ресурс Ingress. Для этого опишем его в .helm/templates/backend-ingress.yaml так:apiVersion: extensions/v1beta1 kind: Ingress metadata: name: {{ .Chart.Name }} annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - http: paths: - path: / backend: serviceName: {{ .Chart.Name }}-srv servicePort: 8000
serviceName должно совпадать с именем Service, которое было объявлено в backend.yaml. Разворачиваем приложение ещё раз:$ dapp kube deploy :minikube --image-version kube_test Deploy release symfony-demo-default [RUNNING] Release "symfony-demo-default" has been upgraded. Happy Helming! LAST DEPLOYED: Fri Jul 14 19:00:28 2017 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE symfony-demo-app-srv 10.0.0.173 <none> 8000/TCP 27m ==> v1beta1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE symfony-demo-app-backend 1 1 1 1 27m ==> v1beta1/Ingress NAME HOSTS ADDRESS PORTS AGE symfony-demo-app * 192.168.99.100 80 2s Deploy release symfony-demo-default [OK] 3.06 sec
Появился
v1beta1/Ingress! Попробуем обратиться к приложению через IngressController. Это можно сделать через IP кластера:$ curl -Lik $(minikube ip) HTTP/1.1 301 Moved Permanently Server: nginx/1.13.1 Date: Fri, 14 Jul 2017 16:13:45 GMT Content-Type: text/html Content-Length: 185 Connection: keep-alive Location: https://192.168.99.100/ Strict-Transport-Security: max-age=15724800; includeSubDomains; HTTP/1.1 403 Forbidden Server: nginx/1.13.1 Date: Fri, 14 Jul 2017 16:13:45 GMT Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Host: 192.168.99.100 X-Powered-By: PHP/7.0.18-0ubuntu0.16.04.1 Strict-Transport-Security: max-age=15724800; includeSubDomains; You are not allowed to access this file. Check app_dev.php for more information.
В целом можно считать, что развёртывание приложения в Minikube удалось. Из запроса видно, что IngressController перебрасывает на 443-й порт и приложение отвечает, что нужно проверить
app_dev.php. Это уже специфика выбранного приложения (symfony), потому что в файле web/app_dev.php легко заметить:// This check prevents access to debug front controllers that are deployed by // accident to production servers. Feel free to remove this, extend it, or make // something more sophisticated. if (isset($_SERVER['HTTP_CLIENT_IP']) || isset($_SERVER['HTTP_X_FORWARDED_FOR']) || !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', 'fe80::1', '::1']) || php_sapi_name() === 'cli-server') ) { header('HTTP/1.0 403 Forbidden'); exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); }
Чтобы увидеть нормальную страницу приложения, нужно развернуть приложение с другой настройкой либо для тестов закомментировать этот блок. Повторный деплой в Kubernetes (после правок в коде приложения) выглядит так:
$ dapp dimg build ... Git artifacts: latest patch ... [OK] 1.86 sec signature: dimgstage-symfony-demo:13a2487a078364c07999d1820d4496763c2143343fb94e0d608ce1a527254dd3 Docker instructions ... [OK] 1.46 sec signature: dimgstage-symfony-demo:e0226872a5d324e7b695855b427e8b34a2ab6340ded1e06b907b165589a45c3b instructions: EXPOSE 8000 $ dapp dimg push --tag-branch :minikube ... symfony-demo-app-kube_test: digest: sha256:eff826014809d5aed8a82a2c5cfb786a13192ae3c8f565b19bcd08c399e15fc2 size: 2824 pushing image `localhost:5000/symfony-demo:symfony-demo-app-kube_test` [OK] 1.16 sec localhost:5000/symfony-demo:symfony-demo-app-kube_test [OK] 1.41 sec $ dapp kube deploy :minikube --image-version kube_test $ kubectl get all !!! po/symfony-demo-app-backend-3438105059-tgfsq 1/1 Running 0 1m
Под пересоздался, можно зайти браузером и увидеть красивую картинку:

Итог
С помощью Minikube и Helm можно тестировать свои приложения в кластере Kubernetes, а dapp поможет в сборке, развёртывании своего Registry и самого приложения.
В статье не упомянуты секретные переменные, которые можно использовать в шаблонах для приватных ключей, паролей и прочей закрытой информации. Об этом напишем отдельно.
P.S.
Читайте также в нашем блоге:
- Первая часть статьи: «Практика с dapp. Часть 1: Сборка простых приложений»;
- «werf — наш инструмент для CI/CD в Kubernetes (обзор и видео доклада)» (Дмитрий Столяров; 27 мая 2019 на DevOpsConf);
- «Официально представляем dapp — DevOps-утилиту для сопровождения CI/CD»;
- «Сборка проектов с dapp. Часть 1: Java»;
- «Сборка проектов с dapp. Часть 2: JavaScript (frontend)»;
- «Сборка и дeплой приложений в Kubernetes с помощью dapp и GitLab CI»;
- «Собираем Docker-образы для CI/CD быстро и удобно вместе с dapp (обзор и видео с доклада)»;
- «Начало работы в Kubernetes с помощью Minikube» (перевод);
- «Наш опыт с Kubernetes в небольших проектах» (видео доклада, включающего в себя знакомство с техническим устройством Kubernetes.
