mirror of
https://github.com/Dannecron/netology-devops.git
synced 2025-12-25 15:22: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.3. работа с kubectl](/src/homework/13-kubernates-config/13.3)
|
||||
* [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