mirror of
https://github.com/Dannecron/netology-devops.git
synced 2025-12-25 23:32:37 +03:00
homework 13.5: complete all tasks
This commit is contained in:
@@ -66,3 +66,4 @@
|
|||||||
* [13.2. разделы и монтирование](/src/homework/13-kubernates-config/13.2)
|
* [13.2. разделы и монтирование](/src/homework/13-kubernates-config/13.2)
|
||||||
* [13.3. работа с kubectl](/src/homework/13-kubernates-config/13.3)
|
* [13.3. работа с kubectl](/src/homework/13-kubernates-config/13.3)
|
||||||
* [13.4. инструменты для упрощения написания конфигурационных файлов. Helm и Jsonnet](/src/homework/13-kubernates-config/13.4)
|
* [13.4. инструменты для упрощения написания конфигурационных файлов. Helm и Jsonnet](/src/homework/13-kubernates-config/13.4)
|
||||||
|
* [13.5. поддержка нескольких окружений на примере Qbec](/src/homework/13-kubernates-config/13.5)
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
local p = import '../params.libsonnet';
|
||||||
|
local params = p.components.backend;
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "backend"
|
||||||
|
},
|
||||||
|
"name": "backend",
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"replicas": params.replicas,
|
||||||
|
"selector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "backend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "backend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"image": "dannecron/netology-devops-k8s-app:backend-latest",
|
||||||
|
"imagePullPolicy": "Always",
|
||||||
|
"name": "netology-backend",
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"name": "DATABASE_URL",
|
||||||
|
"value": "postgresql://db_user:db_passwd@postgres:5432/news"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"containerPort": 9000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminationGracePeriodSeconds": 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": {
|
||||||
|
"name": "backend",
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 9000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selector": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "backend"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
local p = import '../params.libsonnet';
|
||||||
|
local params = p.components.database;
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": {
|
||||||
|
"name": "postgres-config",
|
||||||
|
"labels": {
|
||||||
|
"app": "postgres"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"POSTGRES_DB": "news",
|
||||||
|
"POSTGRES_USER": "db_user",
|
||||||
|
"POSTGRES_PASSWORD": "db_passwd",
|
||||||
|
"PGDATA": "/var/lib/postgresql/data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "PersistentVolume",
|
||||||
|
"metadata": {
|
||||||
|
"name": params.pvName,
|
||||||
|
"labels": {
|
||||||
|
"type": "local",
|
||||||
|
"app": "postgres"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"storageClassName": "manual",
|
||||||
|
"capacity": {
|
||||||
|
"storage": "1Gi"
|
||||||
|
},
|
||||||
|
"accessModes": [
|
||||||
|
"ReadWriteMany"
|
||||||
|
],
|
||||||
|
"hostPath": {
|
||||||
|
"path": params.pvPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "PersistentVolumeClaim",
|
||||||
|
"metadata": {
|
||||||
|
"name": "postgres-pv-claim",
|
||||||
|
"labels": {
|
||||||
|
"app": "postgres"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"storageClassName": "manual",
|
||||||
|
"accessModes": [
|
||||||
|
"ReadWriteMany"
|
||||||
|
],
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"storage": "1Gi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "StatefulSet",
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "database",
|
||||||
|
"db-kind": "postgresql"
|
||||||
|
},
|
||||||
|
"name": "db",
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"selector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "database",
|
||||||
|
"db-kind": "postgresql"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serviceName": "postgres",
|
||||||
|
"replicas": 1,
|
||||||
|
"podManagementPolicy": "Parallel",
|
||||||
|
"updateStrategy": {
|
||||||
|
"type": "RollingUpdate"
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "database",
|
||||||
|
"db-kind": "postgresql"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"terminationGracePeriodSeconds": 60,
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "postgres",
|
||||||
|
"image": "postgres:13-alpine",
|
||||||
|
"imagePullPolicy": "IfNotPresent",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "postgresql",
|
||||||
|
"containerPort": 5432,
|
||||||
|
"protocol": "TCP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"envFrom": [
|
||||||
|
{
|
||||||
|
"configMapRef": {
|
||||||
|
"name": "postgres-config"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumeMounts": [
|
||||||
|
{
|
||||||
|
"mountPath": "/var/lib/postgresql/data",
|
||||||
|
"name": "postgredb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "postgredb",
|
||||||
|
"persistentVolumeClaim": {
|
||||||
|
"claimName": "postgres-pv-claim"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": {
|
||||||
|
"name": "postgres"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"type": "ClusterIP",
|
||||||
|
"clusterIP": "None",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "postgresql",
|
||||||
|
"port": 5432,
|
||||||
|
"targetPort": "postgresql",
|
||||||
|
"protocol": "TCP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selector": {
|
||||||
|
"service": "database",
|
||||||
|
"db-kind": "postgresql"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
local p = import '../params.libsonnet';
|
||||||
|
local params = p.components.frontend;
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "frontend"
|
||||||
|
},
|
||||||
|
"name": "frontend",
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"replicas": params.replicas,
|
||||||
|
"selector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "frontend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "frontend"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"image": "dannecron/netology-devops-k8s-app:frontend-latest",
|
||||||
|
"imagePullPolicy": "Always",
|
||||||
|
"name": "netology-frontend",
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"name": "BASE_URL",
|
||||||
|
"value": "http://backend:9000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"containerPort": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminationGracePeriodSeconds": 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": {
|
||||||
|
"name": "frontend"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"port": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selector": {
|
||||||
|
"app": "app",
|
||||||
|
"service": "frontend"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Endpoints",
|
||||||
|
"metadata": {
|
||||||
|
"name": "local-google",
|
||||||
|
},
|
||||||
|
"subsets": [
|
||||||
|
{
|
||||||
|
"addresses": [
|
||||||
|
{
|
||||||
|
"ip": "173.194.220.100"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"port": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
// this file has the baseline default parameters
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
backend: {
|
||||||
|
replicas: 1
|
||||||
|
},
|
||||||
|
frontend: {
|
||||||
|
replicas: 1
|
||||||
|
},
|
||||||
|
database: {
|
||||||
|
"pvName": "postgres-pv",
|
||||||
|
"pvPath": "/mnt/postgres/data"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
// this file has the param overrides for the default environment
|
||||||
|
local base = import './base.libsonnet';
|
||||||
|
|
||||||
|
base {
|
||||||
|
components +: {
|
||||||
|
backend: {
|
||||||
|
replicas: 3,
|
||||||
|
},
|
||||||
|
frontend: {
|
||||||
|
replicas: 3,
|
||||||
|
},
|
||||||
|
database: {
|
||||||
|
"pvName": "postgres-pv-production",
|
||||||
|
"pvPath": "/mnt/postgres/production/data"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
// this file has the param overrides for the default environment
|
||||||
|
local base = import './base.libsonnet';
|
||||||
|
|
||||||
|
base {
|
||||||
|
components +: {
|
||||||
|
database: {
|
||||||
|
"pvName": "postgres-pv-stage",
|
||||||
|
"pvPath": "/mnt/postgres/stage/data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
// this file returns the params for the current qbec environment
|
||||||
|
local env = std.extVar('qbec.io/env');
|
||||||
|
local paramsMap = import 'glob-import:environments/*.libsonnet';
|
||||||
|
local baseFile = if env == '_' then 'base' else env;
|
||||||
|
local key = 'environments/%s.libsonnet' % baseFile;
|
||||||
|
|
||||||
|
if std.objectHas(paramsMap, key)
|
||||||
|
then paramsMap[key]
|
||||||
|
else error 'no param file %s found for environment %s' % [key, env]
|
||||||
15
src/homework/13-kubernates-config/13.5/project/qbec.yaml
Normal file
15
src/homework/13-kubernates-config/13.5/project/qbec.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: qbec.io/v1alpha1
|
||||||
|
kind: App
|
||||||
|
metadata:
|
||||||
|
name: project
|
||||||
|
spec:
|
||||||
|
environments:
|
||||||
|
stage:
|
||||||
|
defaultNamespace: "default"
|
||||||
|
server: https://51.250.85.245:6443
|
||||||
|
excludes:
|
||||||
|
- local_google
|
||||||
|
production:
|
||||||
|
defaultNamespace: "production"
|
||||||
|
server: https://51.250.85.245:6443
|
||||||
|
vars: {}
|
||||||
132
src/homework/13-kubernates-config/13.5/readme.md
Normal file
132
src/homework/13-kubernates-config/13.5/readme.md
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
Выполнение [домашнего задания](https://github.com/netology-code/devkub-homeworks/blob/main/13-kubernetes-config-05-qbec.md)
|
||||||
|
по теме "13.5. поддержка нескольких окружений на примере Qbec"
|
||||||
|
|
||||||
|
## Q/A
|
||||||
|
|
||||||
|
> Приложение обычно существует в нескольких окружениях. Для удобства работы следует использовать соответствующие инструменты, например, Qbec.
|
||||||
|
|
||||||
|
### Задание 1
|
||||||
|
|
||||||
|
Подготовить приложение для работы через qbec.
|
||||||
|
|
||||||
|
> Приложение следует упаковать в qbec. Окружения должно быть 2: stage и production.
|
||||||
|
|
||||||
|
> Требования:
|
||||||
|
> * stage окружение должно поднимать каждый компонент приложения в одном экземпляре;
|
||||||
|
> * production окружение — каждый компонент в трёх экземплярах;
|
||||||
|
> * для production окружения нужно добавить endpoint на внешний адрес.
|
||||||
|
|
||||||
|
Для начала необходимо установить две утилиты: `jsonnet` и `qbec`.
|
||||||
|
|
||||||
|
Для простоты оригинальная утилита [jsonnet](https://github.com/google/jsonnet) будет заменена на её [официальную реализацию на языке go](https://github.com/google/go-jsonnet).
|
||||||
|
Установка:
|
||||||
|
|
||||||
|
* Скачать последний релиз с `github`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -LO https://github.com/google/go-jsonnet/releases/download/v0.19.1/go-jsonnet_0.19.1_Linux_x86_64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
* Распаковать архив
|
||||||
|
|
||||||
|
```shell
|
||||||
|
tar -zxf go-jsonnet_0.19.1_Linux_x86_64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
* Переместить файлы `jsonnet` и `jsonnetfmt` в директорию с исполняемыми файлами (н-р, `~/.local/bin`)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mv jsonnet ~/.local/bin && mv jsonnetfmt ~/.local/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
* Не забыть удалить оставшиеся файлы
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -f LICENSE README.md go-jsonnet_0.19.1_Linux_x86_64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Для установки `qbec`:
|
||||||
|
|
||||||
|
* Скачать последний релиз с `github`
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -OL https://github.com/splunk/qbec/releases/download/v0.15.2/qbec-linux-amd64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
* Распаковать архив
|
||||||
|
|
||||||
|
```shell
|
||||||
|
tar -zxf qbec-linux-amd64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
* Переместить файл `qbec` в директорию с исполняемыми файлами (н-р, `~/.local/bin`)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mv qbec ~/.local/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
* Не забыть удалить оставшиеся файлы
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -f CHANGELOG.md LICENSE README.md jsonnet-qbec licenselint.sh qbec-linux-amd64.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Конфигурация `qbec` расположена в директории [project](./project). Конфигурация состоит из 4-х компонентов:
|
||||||
|
|
||||||
|
* [backend](./project/components/backend.jsonnet): Deployment и Service для backend части приложения
|
||||||
|
* [frontend](./project/components/frontend.jsonnet): Deployment и Service для frontend части приложения
|
||||||
|
* [database](./project/components/database.jsonnet): StatefulSet базы данных вместе с некоторыми дополнительными компонентами (ConfigMap, PV, PVC)
|
||||||
|
* [local_google](./project/components/local_google.jsonnet): Endpoint для одного из ip-адресов `google.com`
|
||||||
|
|
||||||
|
Чтобы убедится, что конфигурация в порядке, можно провести валидацию:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
qbec validate stage
|
||||||
|
qbec validate production
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем нужно приступить к деплою приложения на окружение `stage`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
qbec apply stage --show-details
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем нужно убедиться, что деплой прошёл успешно:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get po
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
backend-5b6584cddb-2sbvw 1/1 Running 0 60s
|
||||||
|
db-0 1/1 Running 0 59s
|
||||||
|
frontend-7b79b7d798-l6khv 1/1 Running 0 60s
|
||||||
|
```
|
||||||
|
|
||||||
|
Аналогично необходимо развернуть приложение на окружение `production`, но перед этим необходимо создать namespace с именем `production`:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl create namespace production
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
qbec apply production
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка, что все поды запущены штатно:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl --namespace=production get po
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
NAME READY STATUS RESTARTS AGE
|
||||||
|
backend-5b6584cddb-lpp4p 1/1 Running 0 42s
|
||||||
|
backend-5b6584cddb-t8nzc 1/1 Running 0 42s
|
||||||
|
backend-5b6584cddb-w79xl 1/1 Running 0 42s
|
||||||
|
db-0 1/1 Running 0 41s
|
||||||
|
frontend-7b79b7d798-b4ct4 1/1 Running 0 42s
|
||||||
|
frontend-7b79b7d798-blnft 1/1 Running 0 42s
|
||||||
|
frontend-7b79b7d798-rbssh 1/1 Running 0 42s
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user