Автор статьи: Рустем Галиев
Senior DevOps Engineer & Integration Architect at IBM
Привет Хабр! На связи Рустем.
Недавно я был на одном интересном воркшопе от компании iTechArt и хотел бы сегодня поделится тем, что мы там делали, а точнее писали CD Pipeline с интеграцией Docker, Kubernetes и Jenkins в Google Cloud (GCE/GKE).
В этой статье мы узнаем, как развернуть динамическое веб-приложение на GKE (Google Kubernetes Engine) с использованием Jenkins.
Тема достаточно интересная, так что давайте начнем.
Наши реквизиты: Jenkins, Kubernetes(GKE), репозиторий Github и реестр образов Dockerhub.
Прежде чем двигаться дальше, давайте получим общее представление о терминологии, используемой в этом проекте:
GCP: Google Cloud Platform — поставщик общедоступного облака, который предлагает своим пользователям вычислительные услуги через Интернет.
Docker: Docker — это программа с открытым исходным кодом, которая позволяет нам создавать, развертывать и управлять виртуализированными приложениями. Это позволяет нам отделить наше приложение от нашей инфраструктуры, поскольку мы можем создавать и запускать наше приложение в контейнерной среде.
Jenkins: это сервер автоматизации с открытым исходным кодом, который позволяет разработчикам надежно создавать, тестировать и развертывать свое программное обеспечение. Он организует цепочку действий (сборка, тестирование, развертывание) для достижения процесса непрерывной интеграции и непрерывной доставки автоматизированным способом.
-
Kubernetes: Kubernetes или K8s — это портативная, расширяемая платформа или программное обеспечение с открытым исходным кодом, которое обеспечивает возможности настройки, автоматизации и управления контейнерами, т.е. Решает вопросы оркестрации
Давайте начнем с подготовки инфраструктуры.
Шаг 1: Создадим и настроим машины
1. Создайте машину разработчика:
Откройте консоль Google Cloud Platform > Compute Engine > Create New Instance
2. Создадим новый экземпляр для сервера Jenkins и Docker Engine:
Установим Docker:
sudo apt-get update
sudo apt install docker.io
Установим Jenkins:
1) Сперва установим JDK:
sudo apt-get update
sudo apt install openjdk-11-jre-headless
2) Добавим ключ
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
3) Apt repo
sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
4) Обновим пакеты и установим Jenkins
sudo apt-get update
sudo apt-get install jenkins
Также не забудьте дать Jenkins’у привелегии администратора
Откроем файл /etc/sudoers
и добавим следующую строчку:
jenkins ALL=(ALL) NOPASSWD: ALL
3. Создадим кластер Kubernetes в GKE
Open GCP console > GKE (Kubernetes engine) > Create
Шаг 2. Настроим Jenkins
1. Откройте дэшборд Jenkins через public IP вашего инстанса по порту 8080
http://<server_publicIP>:8080
По указанному пути найдем пароль администратора, скопируем и вставим
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Теперь выберем Install suggested plugins
После установки Jenkins попросит создать аккаунт для администратора, что мы и сделаем
2. Установим следующие плагины: Git, github, Docker pipeline, Google Kubernetes Engine
Jenkins Dashboard -> Plugin Manager -> Available -> Search bar
3. Добавим реквизиты для аутентификации в GKE и Dockerhub
Загрузите ключ сервисного аккаунта Google:
Open GCP console > IAM and Admin > service account > open default one or create new one > add key > create new key (json format) and save it
Загрузим ключ в Jenkins
Jenkins Dashboard > manage Jenkins > manage credentials > Jenkins > global credentials > add credentials
Для Docker тоже добавим (где Secret - это пароль нашего аккаунта)
3. Создадим Pipeline в Jenkins:
Dashboard -> New item
Дадим любое имя, выбираем pipeline
Definition = Pipeline script from SCM
SCM = git
Repository Url: url вашего репозитория
Script Path: Jenkinsfile
Шаг 3. Настроим наш проект для сборки
Для примера давайте соберем это приложение и форкнем или склоним его: https://github.com/komarserjio/notejam
1. Напишем Dockerfile:
FROM python:2.7
RUN mkdir app
COPY django/notejam app/
COPY django/requirements.txt ./
RUN pip install -r requirements.txt
RUN pip install psycopg2
WORKDIR app/
EXPOSE 5000
2. Напишем deployment.yaml для Kubernetes
В моем случае он содержит манифест развертывания веб-приложения и его манифест его службы, а также манифест для persistent volume claim, secret, configMap, database deployment и service.
#data-db-persistentvolumeclaim.yam
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
service: data-db
name: data-db
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
#db-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
labels:
service: db
name: db-config
data:
db-name: "nj"
#db-secret
apiVersion: v1
kind: Secret
metadata:
name: notejam-credentials
type: Opaque
data:
user: YWRtaW4=
password: YWRtaW5AMTIz
#db-deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
service: db
name: db
spec:
replicas: 1
selector:
matchLabels:
service: db
template:
metadata:
labels:
service: db
tier: backend
spec:
containers:
- image: postgres
name: database
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: notejam-credentials
key: user
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: notejam-credentials
key: password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: db-config
key: db-name
ports:
- containerPort: 5432
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
volumeMounts:
- mountPath: /var/lib/mysql/data
name: data-db
restartPolicy: Always
volumes:
- name: data-db
persistentVolumeClaim:
claimName: data-db
#db-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
service: db
name: db
spec:
ports:
- name: "5432"
protocol: TCP
port: 5432
targetPort: 5432
selector:
service: db
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
service: web
name: web
spec:
replicas: 1
selector:
matchLabels:
service: web
template:
metadata:
labels:
service: web
spec:
containers:
- args:
- bash
- -c
- python manage.py syncdb --noinput && python manage.py migrate && python manage.py runserver 0.0.0.0:5000
image: arshad1914/pipeline:latest
name: notejam
ports:
- containerPort: 5000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 250Mi
restartPolicy: Always
apiVersion: v1
kind: Service
metadata:
labels:
service: web
name: web
spec:
type: LoadBalancer
ports:
- name: "5000"
port: 5000
targetPort: 5000
selector:
service: web
3. Создадим Jenkinsfile, где опишем процесс сборки и доставки
pipeline {
agent any
environment {
PROJECT_ID = 'docker'
CLUSTER_NAME = 'jenkins'
LOCATION = 'us-central-1a'
CREDENTIALS_ID = 'kubernetes'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build image') {
steps {
script {
app = docker.build("zetzo/pipeline:{env.BUILD_ID}")
}
}
}
stage('Deploy to K8s') {
steps{
echo "Deployment started ..."
sh 'ls -ltr'
sh 'pwd'
sh "sed -i 's/pipeline:latest/pipeline:class: 'KubernetesEngineBuilder',
projectId: env.PROJECT_ID,
clusterName: env.CLUSTER_NAME,
location: env.LOCATION,
manifestPattern: 'deployment.yaml',
credentialsId: env.CREDENTIALS_ID,
verifyDeployments: true])
}
}
}
}
Шаг 4. Протестируем наш пайплайн (спойлер: успешно)
Задеплоили, Вы восхитительны!
P.s.
Если хотите чтобы деплой был полностью автоматизированным (т.е. Перейти от Continuous Delivery к Continuous Deployment), то рекомендую настроить вебхук в вашем репозитории
settings > webhooks > add webhooks > url Вашего Jenkins instance
В Вашем Jenkins pipeline, заходим в конфигурацию и ставим галочку в поле здесь
На этом все. Также хочу порекомендовать всем бесплатный урок от OTUS на котором вы сможете изучить предпосылки к возникновению контейнеризации и познакомиться с устройством самого популярного "контейнеризатора" - docker.