Kubernetes: запуск Gravl в Minikube

Автор: | 06/12/2017
 

Задача: используя Minikube запустить контейнер с CMS Grav.

Шаги:

  1. собрать Docker образ с NGINX + PHP-FPM и кодом приложения
  2. запушить его в DockerHub
  3. запустить контейнер с приложением в Kubernetes кластере

Установка и запуск Minikube описаны тут>>>.

Проверка Grav

Т.к. эту CMS ещё не использовал — сначала попробуем запустить её вручную, и посмотреть как она стартует.

На Arch для проверки устанавливаем PHP и php-gd:

sudo pacman -S php
sudo pacman -S php-gd

Используем NGINX + PHP-FPM из DockerHub:

sudo docker pull richarvey/nginx-php-fpm:latest

Качаем сам Grav:

cd /tmp
git clone https://github.com/getgrav/grav.git
cd grav/

Запускаем контейнер, монтируем каталог со скачанным Grav:

sudo docker run -ti -p 80:80 -v /tmp/grav/:/var/www/html  richarvey/nginx-php-fpm:latest bash
bash-4.3#

Проверяем файлы и выполняем установку зависимостей:

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

Запускаем NGINX:

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)

С другой консоли проверяем:

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" />

ОК, всё работает — переходим к сборке образа.

Сборка Grav в Docker образ

В будущем сборка будет выполняться в Jenkins, а пока готовим свой репозиторий и Dockerfile.

Готовим репозиторий:

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"

CMS небольшая:

du -sh .
11M     .

Поэтому можно весь код собрать прямо в образ, по аналогии со сборкой образов NodeJS.

Устанавливаем зависимости:

php bin/grav install

Создаём Dockerfile:

FROM richarvey/nginx-php-fpm
COPY . /var/www/html
EXPOSE 443 80
CMD ["/start.sh"]

Пробуем собрать его:

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

Запускаем:

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)

Проверяем:

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" />
...

Работает.

Собираем ещё раз, и пушим в DockerHub:

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

Последний шаг — создать деплоймент для 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:

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.

Создаём деплоймент:

kubectl create -f keygrav.yml
deployment "keygrav" created

Проверяем:

kubectl get deployments
NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
keygrav   1         1         1            1           2m

Запускаем сервис:

kubectl expose deployment keygrav --type=NodePort
service "keygrav" exposed

Проверяем:

kubectl get services
NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
keygrav      10.0.0.216   <none>        80/TCP    14s

Находим URL (т.к. Kubernetes работает в Virtualbox-е):

minikube service keygrav --url
Waiting, endpoint for service is not ready yet...
http://192.168.99.100:30872

Проверяем:

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" />

Работает.

Jenkins pipeline

И ещё один последний шаг — набросать билд-деплой в Jenkins.

Деплоя не будет, т.к. это Proof of Concept и полноценного кластера Kubernetes нет.

Запускаем EC2, запускаем там Jenkins:

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

Опять таки — это не продакшен решение, workspaces Jenkins-а и все созданные пайплайны после остановки контейнера будут удалены.

Запуск Jenkins с workspaces на отдельном разделе описан в посте Azure: Azure Resource Manager provisioning и Jenkins в Docker.

Создаём джобу:

Создаём билд-файл:

mkdir ci
cd ci/

Содержимое файла 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()
}

Билдим:

Готово.