Задача: используя Minikube запустить контейнер с CMS Grav.
Шаги:
- собрать Docker образ с NGINX + PHP-FPM и кодом приложения
- запушить его в DockerHub
- запустить контейнер с приложением в Kubernetes кластере
Установка и запуск Minikube описаны тут>>>.
Содержание
Проверка Grav
Т.к. эту CMS ещё не использовал – сначала попробуем запустить её вручную, и посмотреть как она стартует.
На Arch для проверки устанавливаем PHP и php-gd
:
[simterm]
$ sudo pacman -S php
$ sudo pacman -S php-gd
[/simterm]
Используем NGINX + PHP-FPM из DockerHub:
[simterm]
$ sudo docker pull richarvey/nginx-php-fpm:latest
[/simterm]
Качаем сам Grav:
[simterm]
$ cd /tmp
$ git clone https://github.com/getgrav/grav.git
$ cd grav/
[/simterm]
Запускаем контейнер, монтируем каталог со скачанным Grav:
[simterm]
$ sudo docker run -ti -p 80:80 -v /tmp/grav/:/var/www/html richarvey/nginx-php-fpm:latest bash
bash-4.3#
[/simterm]
Проверяем файлы и выполняем установку зависимостей:
[simterm]
bash-4.3# cd /var/www/html/ bash-4.3# ls -l total 248 -rw-r--r-- 1 1000 1000 87315 Jun 12 10:50 CHANGELOG.md -rw-r--r-- 1 1000 1000 6417 Jun 12 10:50 CONTRIBUTING.md ... drwxr-xr-x 8 1000 1000 160 Jun 12 10:50 user drwxr-xr-x 2 1000 1000 160 Jun 12 10:50 webserver-configs bash-4.3# bin/grav install Preparing to install vendor dependencies... Do not run Composer as root/super user! See https://getcomposer.org/root for details Loading composer repositories with package information Installing dependencies from lock file Package operations: 27 installs, 0 updates, 0 removals - Installing antoligy/dom-string-iterators (v1.0.0): Downloading (100%) ... - Installing twig/twig (v1.33.2): Downloading (100%) ... SUCCESS cloned https://github.com/getgrav/grav-theme-antimatter -> /var/www/html/user/themes/antimatter
[/simterm]
Запускаем NGINX:
[simterm]
bash-4.3# /start.sh Do not run Composer as root/super user! See https://getcomposer.org/root for details Loading composer repositories with package information Installing dependencies from lock file Nothing to install or update Generating autoload files 2017-06-12 10:55:51,000 CRIT Set uid to user 0 2017-06-12 10:55:51,230 INFO RPC interface 'supervisor' initialized 2017-06-12 10:55:51,230 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2017-06-12 10:55:51,231 INFO supervisord started with pid 194 2017-06-12 10:55:52,236 INFO spawned: 'php-fpm' with pid 204 2017-06-12 10:55:52,241 INFO spawned: 'nginx' with pid 205 2017-06-12 10:55:53,724 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2017-06-12 10:55:53,724 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[/simterm]
С другой консоли проверяем:
[simterm]
$ curl localhost <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Home | Grav</title> <meta name="generator" content="GravCMS" /> <meta name="description" content="Grav is an easy to use, yet powerful, open source flat-file CMS" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link rel="icon" type="image/png" href="/user/themes/antimatter/images/favicon.png" /> <link rel="canonical" href="http://localhost" />
[/simterm]
ОК, всё работает – переходим к сборке образа.
Сборка Grav в Docker образ
В будущем сборка будет выполняться в Jenkins, а пока готовим свой репозиторий и Dockerfile
.
Готовим репозиторий:
[simterm]
$ git clone https://github.com/setevoy2/keygrav.git Cloning into 'keygrav'... remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. $ git clone https://github.com/getgrav/grav.git Cloning into 'grav'... remote: Counting objects: 32074, done. remote: Compressing objects: 100% (55/55), done. remote: Total 32074 (delta 33), reused 54 (delta 20), pack-reused 31990 Receiving objects: 100% (32074/32074), 10.91 MiB | 213.00 KiB/s, done. Resolving deltas: 100% (18767/18767), done. $ rsync -av --progress grav/ keygrav/ --exclude .git $ ls -l keygrav/ total 292 drwxr-xr-x 2 setevoy setevoy 4096 Jun 12 14:00 assets drwxr-xr-x 2 setevoy setevoy 4096 Jun 12 14:00 backup drwxr-xr-x 2 setevoy setevoy 4096 Jun 12 14:00 bin ... drwxr-xr-x 8 setevoy setevoy 4096 Jun 12 14:00 user drwxr-xr-x 2 setevoy setevoy 4096 Jun 12 14:00 webserver-configs $ cd keygrav/ $ git add -A && git commit -m "grav init"
[/simterm]
CMS небольшая:
[simterm]
$ du -sh .
11M .
[/simterm]
Поэтому можно весь код собрать прямо в образ, по аналогии со сборкой образов NodeJS.
Устанавливаем зависимости:
[simterm]
$ php bin/grav install
[/simterm]
Создаём Dockerfile
:
FROM richarvey/nginx-php-fpm COPY . /var/www/html EXPOSE 443 80 CMD ["/start.sh"]
Пробуем собрать его:
[simterm]
$ sudo docker build -t keygrav . Sending build context to Docker daemon 7.426MB Step 1/5 : FROM richarvey/nginx-php-fpm ---> d1db840b1d7d Step 2/5 : COPY . /var/www/html ---> 00b95aff170c ... Step 5/5 : CMD /start.sh ---> Running in ec169fdc37e5 ---> c8c8da1b26b5 Removing intermediate container ec169fdc37e5 Successfully built c8c8da1b26b5 Successfully tagged keygrav:latest
[/simterm]
Запускаем:
[simterm]
$ sudo docker run -ti -p 80:80 keygrav Do not run Composer as root/super user! See https://getcomposer.org/root for details Loading composer repositories with package information Installing dependencies from lock file Nothing to install or update Generating autoload files 2017-06-12 12:13:49,649 CRIT Set uid to user 0 2017-06-12 12:13:50,046 INFO RPC interface 'supervisor' initialized 2017-06-12 12:13:50,047 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2017-06-12 12:13:50,047 INFO supervisord started with pid 1 2017-06-12 12:13:51,052 INFO spawned: 'php-fpm' with pid 16 2017-06-12 12:13:51,057 INFO spawned: 'nginx' with pid 17 2017-06-12 12:13:52,582 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2017-06-12 12:13:52,582 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[/simterm]
Проверяем:
[simterm]
$ curl localhost <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Home | Grav</title> <meta name="generator" content="GravCMS" /> <meta name="description" content="Grav is an easy to use, yet powerful, open source flat-file CMS" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link rel="icon" type="image/png" href="/user/themes/antimatter/images/favicon.png" /> <link rel="canonical" href="http://localhost" /> ...
[/simterm]
Работает.
Собираем ещё раз, и пушим в DockerHub:
[simterm]
$ sudo docker build -t setevoy/keygrav . $ sudo docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: setevoy Password: Login Succeeded $ sudo docker push setevoy/keygrav
[/simterm]
Последний шаг – создать деплоймент для Kubernetes.
Kubernetes deployment
Создаём deployment файл для K8n:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: keygrav spec: replicas: 1 template: metadata: labels: app: nginx-php-grav spec: containers: - name: keygrav image: setevoy/keygrav:latest ports: - containerPort: 80
Запускаем Minikube:
[simterm]
$ minikube start Starting local Kubernetes cluster... Starting VM... SSH-ing files into VM... Setting up certs... Starting cluster components... Connecting to cluster... Setting up kubeconfig... Kubectl is now configured to use the cluster.
[/simterm]
Создаём деплоймент:
[simterm]
$ kubectl create -f keygrav.yml deployment "keygrav" created
[/simterm]
Проверяем:
[simterm]
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE keygrav 1 1 1 1 2m
[/simterm]
Запускаем сервис:
[simterm]
$ kubectl expose deployment keygrav --type=NodePort service "keygrav" exposed
[/simterm]
Проверяем:
[simterm]
$ kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE keygrav 10.0.0.216 <none> 80/TCP 14s
[/simterm]
Находим URL (т.к. Kubernetes работает в Virtualbox-е):
[simterm]
$ minikube service keygrav --url Waiting, endpoint for service is not ready yet... http://192.168.99.100:30872
[/simterm]
Проверяем:
[simterm]
$ curl http://192.168.99.100:30872 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Home | Grav</title> <meta name="generator" content="GravCMS" /> <meta name="description" content="Grav is an easy to use, yet powerful, open source flat-file CMS" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link rel="icon" type="image/png" href="/user/themes/antimatter/images/favicon.png" /> <link rel="canonical" href="http://192.168.99.100" />
[/simterm]
Работает.
Jenkins pipeline
И ещё один последний шаг – набросать билд-деплой в Jenkins.
Деплоя не будет, т.к. это Proof of Concept и полноценного кластера Kubernetes нет.
Запускаем EC2, запускаем там Jenkins:
[simterm]
# docker run -u root -tid -p 80:8080 -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v /usr/lib/x86_64-linux-gnu/libltdl.so.7.3.0:/usr/lib/x86_64-linux-gnu/libltdl.so.7 –name jenkins jenkins
[/simterm]
Опять таки – это не продакшен решение, workspaces Jenkins-а и все созданные пайплайны после остановки контейнера будут удалены.
Запуск Jenkins с workspaces на отдельном разделе описан в посте Azure: Azure Resource Manager provisioning и Jenkins в Docker.
Создаём джобу:
Создаём билд-файл:
[simterm]
$ mkdir ci $ cd ci/
[/simterm]
Содержимое файла jenkins.groovy
, с функциями:
#!/usr/bin/env groovy def dockerBuild () { stage ('Docker build') { sh 'apt-get update && apt-get -y install php5 php5-gd php5-curl' sh '/usr/bin/php5 bin/grav install' withDockerRegistry(registry: [credentialsId: 'setevoy-docker-hub']){ docker.build("setevoy/keygrav:${env.BUILD_NUMBER}").push() } } } def kuberDeploy () { stage ('Deploy') { /* As this is PoC and we have no Dev/QA/etc environments - deploy wasn't done. Possible soultions 1: - update keygrav.yml in repo with new :tag - copy to the Master host - kubectl apply -f keygrav.yml 2: - SSH to the Master host and exec `kubectl set image deployment/keygrav keygrav=setevoy/keygrav:${env.BUILD_NUMBER}` */ } } return this
И скрипт самого билда keybuild.groovy
:
#!/usr/bin/env groovy node { git branch: "${BRANCH}", url: "${BUILDREPOURL}" def build = load 'ci/jenkins.groovy' build.dockerBuild() // build.kuberDeploy() }
Билдим:
Готово.