Thank you for reading this post, don't forget to subscribe!
1.POD
2.REPLICASET
3.DEPLOYMENT
4.readinessProbe и livenessProbe
5.LIMITS
6.SERVICE
7.INGRESS
8.CONFIGMAP
9.Deployment apache
10.log-nfs-server
11. Dynamic NFS provision
12.Nginx apache nfs-dinamic provision
13.Helm
14.Helm практика
15.Autoscaling
16.ci/cd gitlab
Дошли руки до разбора и практического запуска. Имеется установленный миникуб на нём рассмотрим практический запуск от простейщей сущности пода до более сложных
и так для начала запустим pod в котором будет 1 контейнер nginx
Но для начала настроим автозаполнение, чтобы пользоваться табом, для этого выполним:
yum install bash-completion
[root@minikub ~]# kubectl completion -h | grep bash
Output shell completion code for the specified shell (bash or zsh). The shell code must be evaluated to provide interactive completion of kubectl commands. This can be done by sourcing it from the .bash _profile.
# Installing bash completion on macOS using homebrew
brew install bash-completion
brew install bash-completion@2
kubectl completion bash > $(brew --prefix)/etc/bash_completion.d/kubectl
# Installing bash completion on Linux
## If bash-completion is not installed on Linux, please install the 'bash-completion' package
## Load the kubectl completion code for bash into the current shell
source <(kubectl completion bash)
## Write bash completion code to a file and source if from .bash_profile
kubectl completion bash > ~/.kube/completion.bash.inc
source '$HOME/.kube/completion.bash.inc'
" >> $HOME/.bash_profile
source $HOME/.bash_profile
[root@minikub ~]# kubectl completion bash > ~/.kube/completion.bash.inc
[root@minikub ~]# source '/root/.kube/completion.bash.inc'
[root@minikub ~]# cat pod.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 |
--- apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 |
[/codesyntax]
[root@minikub ~]# kubectl create -f pod.yaml
1 2 3 |
[root@minikub ~]# <strong>kubectl get pod</strong> NAME READY STATUS RESTARTS AGE my-pod 1/1 Running 0 69s |
======================================
теперь запустим несколько контейнеров через replicaset
[root@minikub ~]# cat replicaset.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
--- apiVersion: apps/v1 kind: ReplicaSet metadata: name: my-replicaset spec: replicas: 3 selector: matchLabels: app: my-app ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 |
[/codesyntax]
[root@minikub ~]# kubectl create -f replicaset.yaml
replicaset.apps/my-replicaset created
проверяем, как мы видим replicaset успешно запущена, смотрим поды, есть наш старый под с именем my-pod и 3 пода запущенные репликасетом, с именем my-replicaset-(id)
1 2 3 4 5 6 7 8 9 10 |
[root@minikub ~]# kubectl get rs NAME DESIRED CURRENT READY AGE my-replicaset 3 3 3 14s [root@minikub ~]# kubectl get pod NAME READY STATUS RESTARTS AGE my-pod 1/1 Running 0 24m my-replicaset-26lht 1/1 Running 0 22s my-replicaset-4pvr2 1/1 Running 0 22s my-replicaset-9vwqc 1/1 Running 0 22s |
=========================
теперь запустим деплоймент который дальше всегда и будем использовать
[root@minikub ~]# cat deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 4 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 |
[/codesyntax]
[root@minikub ~]# kubectl create -f deployment.yaml
deployment.apps/my-deployment created
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[root@minikub ~]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 4/4 4 4 27s видим что автоматически создался и репликасет с именем my-deployment [root@minikub ~]# kubectl get replicaset NAME DESIRED CURRENT READY AGE my-deployment-6cb88665b 4 4 4 50s my-replicaset 3 3 3 27m а также поды с именем my-deployment [root@minikub ~]# kubectl get pod NAME READY STATUS RESTARTS AGE my-deployment-6cb88665b-4q79q 1/1 Running 0 59s my-deployment-6cb88665b-74qv4 1/1 Running 0 59s my-deployment-6cb88665b-w2xlm 1/1 Running 0 59s my-deployment-6cb88665b-wslkl 1/1 Running 0 59s my-pod 1/1 Running 0 52m my-replicaset-26lht 1/1 Running 0 27m my-replicaset-4pvr2 1/1 Running 0 27m my-replicaset-9vwqc 1/1 Running 0 27m |
===================================================
Теперь добавим проверки на доступность, а именно readinessProbe и livenessProbe
[root@minikub ~]# cat deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 4 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд |
[/codesyntax]
чтобы применить изменения, необходимо выполнить команду:
[root@minikub ~]# kubectl apply -f deployment.yaml
deployment.apps/my-deployment configured
==================================================
Теперь добавим лимиты
Limits - количество ресурсов которые pod может использовать(верхняя граница)
Requies - количество ресурсов которые резервируются для pod на ноде (не делятся с другими подами на ноде)
[root@minikub ~]# cat deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 5 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi |
[/codesyntax]
проверяем,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[root@minikub ~]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 5/5 5 5 126m время деплоймента 126 минут, посмотрим время подов, оно изменится потому что поды будут пересозданы из-за изменения лимитов: [root@minikub ~]# kubectl get pod NAME READY STATUS RESTARTS AGE my-deployment-7c88b95897-bcbsw 1/1 Running 0 49s my-deployment-7c88b95897-bxb9b 1/1 Running 0 49s my-deployment-7c88b95897-s72f5 1/1 Running 0 51s my-deployment-7c88b95897-wjlrk 1/1 Running 0 60s my-deployment-7c88b95897-x5bb8 1/1 Running 0 60s my-pod 1/1 Running 0 177m my-replicaset-26lht 1/1 Running 0 153m my-replicaset-4pvr2 1/1 Running 0 153m my-replicaset-9vwqc 1/1 Running 0 153m |
посмотрим по логам что там внутри одного из контейнеров:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[root@minikub ~]# kubectl get pod NAME READY STATUS RESTARTS AGE my-deployment-7c88b95897-bcbsw 1/1 Running 0 6m2s my-deployment-7c88b95897-bxb9b 1/1 Running 0 6m2s my-deployment-7c88b95897-s72f5 1/1 Running 0 6m4s my-deployment-7c88b95897-wjlrk 1/1 Running 0 6m13s my-deployment-7c88b95897-x5bb8 1/1 Running 0 6m13s my-pod 1/1 Running 0 3h2m my-replicaset-26lht 1/1 Running 0 158m my-replicaset-4pvr2 1/1 Running 0 158m my-replicaset-9vwqc 1/1 Running 0 158m как ниже видим, проверки успешно проходят [root@minikub ~]# kubectl logs my-deployment-7c88b95897-bcbsw 172.17.0.1 - - [03/May/2020:09:06:25 +0000] "GET / HTTP/1.1" 200 612 "-" "kube-probe/1.18" "-" 172.17.0.1 - - [03/May/2020:09:06:35 +0000] "GET / HTTP/1.1" 200 612 "-" "kube-probe/1.18" "-" 172.17.0.1 - - [03/May/2020:09:06:42 +0000] "GET / HTTP/1.1" 200 612 "-" "kube-probe/1.18" "-" 172.17.0.1 - - [03/May/2020:09:06:45 +0000] "GET / HTTP/1.1" 200 612 "-" "kube-probe/1.18" "-" |
посмотрим подробное описание пода:
[root@minikub ~]# kubectl describe pod my-deployment-7c88b95897-bcbsw
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
Name: my-deployment-7c88b95897-bcbsw Namespace: default Priority: 0 PriorityClassName: <none> Node: minikub/192.168.1.120 Start Time: Sun, 03 May 2020 15:06:22 +0600 Labels: app=my-app pod-template-hash=7c88b95897 Annotations: <none> Status: Running IP: 172.17.0.16 Controlled By: ReplicaSet/my-deployment-7c88b95897 Containers: nginx: Container ID: docker://1f30faff8bc2f64513eb081837f33eb2103ba7d55013a6bfbf3a5b54f427e5cd Image: nginx:1.12 Image ID: docker-pullable://nginx@sha256:72daaf46f11cc753c4eab981cbf869919bd1fee3d2170a2adeac12400f494728 Port: 80/TCP Host Port: 0/TCP State: Running Started: Sun, 03 May 2020 15:06:23 +0600 Ready: True Restart Count: 0 Limits: cpu: 100m memory: 100Mi Requests: cpu: 50m memory: 100Mi Liveness: http-get http://:80/ delay=10s timeout=1s period=10s #success=1 #failure=3 Readiness: http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=3 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-vqkds (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-vqkds: Type: Secret (a volume populated by a Secret) SecretName: default-token-vqkds Optional: false QoS Class: Burstable Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned default/my-deployment-7c88b95897-bcbsw to minikub Normal Pulled 10m kubelet, minikub Container image "nginx:1.12" already present on machine Normal Created 10m kubelet, minikub Created container nginx Normal Started 10m kubelet, minikub Started container nginx |
[/codesyntax]
===================================================
Теперь опишем service
Сервис по меткам(лейблам) даёт указания, что надо отправлять трафик на pod-ы
[root@minikub ~]# cat service.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: my-service # имя сервиса spec: ports: - port: 80 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: my-app #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
[root@minikub ~]# kubectl apply -f service.yaml
service/my-service created
проверяем что сервис стартанул:
1 2 3 4 5 6 7 8 9 10 |
[root@minikub ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 33d my-service ClusterIP 10.96.34.113 <none> 80/TCP 79s смотрим endpoints, т.е. куда my-service будет отправлять запросы [root@minikub ~]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.1.120:8443 33d my-service 172.17.0.10:80,172.17.0.11:80,172.17.0.12:80 + 5 more… 3m44s |
ну а чтобы отправить трафик на my-service используется INGRESS
===================================================
INGRESS
Данная сущность необходима чтобы зарулить запросы из интернета в наш кластер. т.е. ингрес берёт информацию из сервиса и минуя его отправляет трафик сразу на поды.
[root@minikub ~]# cat ingress.yml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-ingress spec: rules: - host: test.ru #тут указывается наш домен http: paths: #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service) - backend: serviceName: my-service #тут указывается наш сервис на который servicePort: 80 #порт на котором сервис слушает # path: / все запросы на корень '/' будут уходить на наш сервис |
[/codesyntax]
[root@minikub ~]# kubectl apply -f ingress.yml
ingress.extensions/my-ingress created
проверяем:
1 2 3 |
[root@minikub ~]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE my-ingress <none> test.ru 192.168.1.120 80 57s |
видим что ингресс создан и обращения на домен test.ru, на 80 порт, будут уходить на наш сервис my-service, это можем увидеть если посмотрим describe
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[root@minikub ~]# kubectl describe ingress my-ingress Name: my-ingress Namespace: default Address: 192.168.1.120 Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- test.ru my-service:80 (<none>) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"my-ingress","namespace":"default"},"spec":{"rules":[{"host":"test.ru","http":{"paths":[{"backend":{"serviceName":"my-service","servicePort":80}}]}}]}} Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 3m5s nginx-ingress-controller Ingress default/my-ingress Normal UPDATE 2m16s nginx-ingress-controller Ingress default/my-ingress [root@minikub ~]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE my-ingress <none> test.ru 192.168.1.120 80 3m36s |
[/codesyntax]
==================================================
Configmap
Добавим к нашему nginx конфиг файл, который будет проксировать все запросы на наш деплоймент с apache.
[root@minikub my-project]# cat nginx-configmap.conf
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: my-app.conf: | server { listen 80; server_name _; location / { proxy_pass http://my-service-apache:80; # А вот сюда пишем название сервиса отвечающего за апач } } |
[/codesyntax]
создаём конфигмап
[root@minikub my-project]# kubectl create -f nginx-configmap.conf
configmap/nginx-conf created
проверяем:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[root@minikub my-project]# kubectl get configmap NAME DATA AGE nginx-conf 1 27s [root@minikub my-project]# kubectl describe configmap nginx-conf Name: nginx-conf Namespace: default Labels: <none> Annotations: <none> Data ==== my-app.conf: ---- server { listen 80; server_name _; location / { proxy_pass http://my-service-apache:80; # А вот сюда пишем название сервиса отвечающего за апач } } Events: <none> |
[/codesyntax]
и поправим деплоймент у nginx чтобы он мог подтащить новый конфигмап
[root@minikub my-project]# cat deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 1 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: nginx-conf #имя нашего конфигмапа, созданного ранее. mountPath: /etc/nginx/conf.d/ # путь по которому мы будем монтировать наш конфиг volumes: #(описывает тома) должен располагаться под spec - name: nginx-conf configMap: name: nginx-conf |
[/codesyntax]
применим новые изменения:
[root@minikub my-project]# kubectl apply -f deployment.yaml
=====================================================
Теперь запустим deployment с apache
[root@minikub my-project]# cat deployment-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment-apache spec: replicas: 1 selector: matchLabels: app: apache # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: apache # по вот этому лейблу репликасет цепляет под spec: containers: - image: httpd:2.4.43 name: apache ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 60m memory: 200Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 120m memory: 300Mi |
[/codesyntax]
[root@minikub my-project]# kubectl apply -f deployment-apache.yaml
deployment.apps/my-deployment-apache created
а также запустим сервис который будет проксировать всё с nginx на apache
[root@minikub my-project]# cat service-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: my-service-apache # имя сервиса spec: ports: - port: 80 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: apache #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
my-service-apache - вот на это имя и нужно проксировать запросы с нашего nginx
[root@minikub my-project]# kubectl apply -f service-apache.yaml
service/my-service-apache created
проверяем что всё запущено:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[root@minikub my-project]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 1/1 1 1 5m25s my-deployment-apache 1/1 1 1 4m6s [root@minikub my-project]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 35d my-service ClusterIP 10.100.200.137 <none> 80/TCP 5m4s my-service-apache ClusterIP 10.110.166.198 <none> 80/TCP 3m16s [root@minikub my-project]# kubectl get pod NAME READY STATUS RESTARTS AGE my-deployment-58d476c5c8-mrstm 1/1 Running 5 5m40s my-deployment-apache-859486bd8c-vxnbk 1/1 Running 0 4m21s [root@minikub my-project]# kubectl get configmap NAME DATA AGE nginx-conf 1 12m [root@minikub my-project]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE my-ingress <none> test.ru 192.168.1.120 80 26h |
проверим что запросы действительно долетают до апача.
Смотрим на каком ip висит наш pod с nginx
1 2 3 4 |
[root@minikub my-project]# <strong>kubectl get pod -o wide</strong> NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-deployment-58d476c5c8-mrstm 1/1 Running 5 9m12s <strong>172.17.0.6</strong> minikub <none> <none> my-deployment-apache-859486bd8c-vxnbk 1/1 Running 0 7m53s 172.17.0.7 minikub <none> <none> |
отправим пару запросов по домену test.ru указанному в ingress
[root@minikub my-project]# curl -I test.ru/TEEEEST
HTTP/1.1 404 Not Found
Server: openresty/1.15.8.2
Date: Mon, 04 May 2020 12:39:20 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Vary: Accept-Encoding
теперь смотрим лог пода apache
[root@minikub my-project]# kubectl log my-deployment-apache-859486bd8c-vxnbk | grep TEEEEST
log is DEPRECATED and will be removed in a future version. Use logs instead.
172.17.0.6 - - [04/May/2020:12:39:18 +0000] "HEAD /TEEEEST HTTP/1.0" 404 -
как видим всё ок, запрошенного урла нету, апач ответил 404, и запрос прилетел с ip 172.17.0.6
==================================================
Теперь прокинем директории для логов и файлов сайта на nfs сервер.
у нас установлен отдельный nfs сервер 192.168.1.82 который примонтирован к нашему миникубу в директории:
/nfs-client
1 2 |
[root@minikub ~]# df -h | grep nfs 192.168.1.82:/nfs 20G 45M 19G 1% /nfs-client |
создаём PersistentVolume на 2 гига в директории:
/nfs-client/test
[root@minikub ~]# cat pv.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
kind: PersistentVolume apiVersion: v1 metadata: name: research-vol labels: type: local spec: capacity: storage: 2Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain hostPath: path: "/nfs-client/test" |
[/codesyntax]
также создаём PersistentVolumeClaim - это запрос на PersistentVolume (на 1 гигабайт) с типом
ReadWriteMany – том может быть смонтирован к множеству подов в режиме чтения и записи.
[root@minikub ~]# cat pvc.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
--- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: research-pvc spec: accessModes: - ReadWriteMany storageClassName: "" volumeName: research-vol resources: requests: storage: 1Gi |
[/codesyntax]
применим
1 2 3 |
kubectl apply -f pv.yaml |
1 |
kubectl apply -f pvc.yaml |
проверим:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 |
[root@minikub ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE research-vol 2Gi RWX Retain Bound default/research-pvc 2d22h [root@minikub ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE research-pvc Bound research-vol 2Gi RWX 2d22h |
[/codesyntax]
теперь подключим этот pv к нашему деплойменту:
[root@minikub ~]# cat my-project/deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 2 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: nginx-conf #имя нашего конфигмапа, созданного ранее. mountPath: /etc/nginx/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: research-vol # это имя взято из лейбла pv mountPath: /var/log/nginx/ # тут указываем какую директорию мы прокидываем в pv volumes: #(описывает тома) должен располагаться под spec - name: nginx-conf configMap: name: nginx-conf #тут указываем pvc - наш запрос на pv - name: research-vol # это имя взято из лейбла pv persistentVolumeClaim: claimName: research-pvc # это имя взято из лейбла pvс |
[/codesyntax]
применим изменения:
[root@minikub ~]# kubectl apply -f my-project/deployment.yaml
подождём когда поды обновятся и проверим:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
[root@minikub ~]# kubectl get pod NAME READY STATUS RESTARTS AGE my-deployment-575b6c74bf-qn2hf 1/1 Running 3 2d22h my-deployment-575b6c74bf-sh6zt 1/1 Running 3 2d22h my-deployment-apache-859486bd8c-d5pq5 1/1 Running 3 5d my-deployment-apache-859486bd8c-ql4zd 1/1 Running 3 5d my-deployment-apache-859486bd8c-tdt96 1/1 Running 3 5d my-deployment-apache-859486bd8c-vxnbk 1/1 Running 3 5d1h [root@minikub ~]# kubectl describe pod my-deployment-575b6c74bf-qn2hf Name: my-deployment-575b6c74bf-qn2hf Namespace: default Priority: 0 PriorityClassName: <none> Node: minikub/192.168.1.120 Start Time: Wed, 06 May 2020 20:47:56 +0600 Labels: app=my-app pod-template-hash=575b6c74bf Annotations: <none> Status: Running IP: 172.17.0.10 Controlled By: ReplicaSet/my-deployment-575b6c74bf Containers: nginx: Container ID: docker://b76f1205841a7fb962aab584419fea9cf0365f1aa320ac440706884ec53a2541 Image: nginx:1.12 Image ID: docker-pullable://nginx@sha256:72daaf46f11cc753c4eab981cbf869919bd1fee3d2170a2adeac12400f494728 Port: 80/TCP Host Port: 0/TCP State: Running Started: Sat, 09 May 2020 17:18:20 +0600 Last State: Terminated Reason: Error Exit Code: 1 Started: Sat, 09 May 2020 17:17:59 +0600 Finished: Sat, 09 May 2020 17:17:59 +0600 Ready: True Restart Count: 3 Limits: cpu: 100m memory: 100Mi Requests: cpu: 50m memory: 100Mi Liveness: http-get http://:80/ delay=10s timeout=1s period=10s #success=1 #failure=3 Readiness: http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=3 Environment: <none> Mounts: /etc/nginx/conf.d/ from nginx-conf (rw) <strong>/var/log/nginx/ from research-vol (rw)</strong> /var/run/secrets/kubernetes.io/serviceaccount from default-token-vqkds (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: nginx-conf: Type: ConfigMap (a volume populated by a ConfigMap) Name: nginx-conf Optional: false research-vol: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: research-pvc ReadOnly: false default-token-vqkds: Type: Secret (a volume populated by a Secret) SecretName: default-token-vqkds Optional: false QoS Class: Burstable Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: <none> |
[/codesyntax]
запись
/var/log/nginx/ from research-vol (rw)
говорит нам, что наш том успешно прокинулся внутрь пода.
====
теперь добавим pv для файлов сайта.
создадим pv и pvc
[root@minikub ~]# cat persistent-volume-for-site-files.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
kind: PersistentVolume apiVersion: v1 metadata: name: pv-files-of-site-test.ru labels: type: local spec: capacity: storage: 2Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain hostPath: path: "/nfs-client/files-of-site-test.ru" --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-files-of-site-test.ru spec: accessModes: - ReadWriteMany storageClassName: "" volumeName: pv-files-of-site-test.ru resources: requests: storage: 1Gi |
[/codesyntax]
тут:
pv-files-of-site-test.ru - наш вольюм
pvc-files-of-site-test.ru - запрос на вольюм
/nfs-client/files-of-site-test.ru - директория на nfs сервере
создаём директорию
[root@minikub ~]# mkdir /nfs-client/files-of-site-test.ru
и создаём наши новые pv и pvc
[root@minikub ~]# kubectl apply -f persistent-volume-for-site-files.yaml
persistentvolume/pv-files-of-site-test.ru created
persistentvolumeclaim/pvc-files-of-site-test.ru created
проверяем:
1 2 3 4 5 6 7 8 9 |
[root@minikub ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-files-of-site-test.ru 2Gi RWX Retain Bound default/pvc-files-of-site-test.ru 106s research-vol 2Gi RWX Retain Bound default/research-pvc 2d22h [root@minikub ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-files-of-site-test.ru Bound pv-files-of-site-test.ru 2Gi RWX 110s research-pvc Bound research-vol 2Gi RWX 2d22h |
теперь поправим наши конфиг файлы для nginx и для apache
[root@minikub ~]# cat my-project/nginx-configmap.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: my-app.conf: | server { listen 80; server_name _; root /var/site; location / { proxy_pass http://my-service-apache:80; # А вот сюда пишем название сервиса отвечающего за апач } } --- apiVersion: v1 kind: ConfigMap metadata: name: apache-conf data: my-app-apache.conf: | Listen 80 <VirtualHost *:80> DocumentRoot "/var/site/" ServerName _ </VirtualHost> |
[root@minikub ~]# kubectl apply -f my-project/nginx-configmap.conf
configmap/nginx-conf created
configmap/apache-conf created
проверяем:
1 2 3 4 |
[root@minikub ~]# kubectl get configmap NAME DATA AGE apache-conf 1 2m59s nginx-conf 1 2m59s |
[root@minikub ~]# cat my-project/deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 2 selector: matchLabels: app: my-app # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: my-app # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: nginx-conf #имя нашего конфигмапа, созданного ранее. mountPath: /etc/nginx/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: research-vol # это имя взято из лейбла pv mountPath: /var/log/nginx/ # тут указываем какую директорию мы прокидываем в pv - name: pv-files-of-site-test-ru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: nginx-conf configMap: name: nginx-conf #тут указываем pvc - наш запрос на pv - name: research-vol # это имя взято из лейбла pv persistentVolumeClaim: claimName: research-pvc # это имя взято из лейбла pvс - name: pv-files-of-site-test-ru persistentVolumeClaim: claimName: pvc-files-of-site-test-ru |
[/codesyntax]
[root@minikub ~]# cat my-project/deployment-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment-apache spec: replicas: 4 selector: matchLabels: app: apache # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: apache # по вот этому лейблу репликасет цепляет под spec: containers: - image: httpd:2.4.43 name: apache ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 60m memory: 200Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 120m memory: 300Mi resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: apache-conf #имя нашего конфигмапа, созданного ранее. mountPath: /usr/local/apache2/conf/extra/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: research-vol # это имя взято из лейбла pv mountPath: /usr/local/apache2/logs/ # тут указываем какую директорию мы прокидываем в pv - name: pv-files-of-site-test-ru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: apache-conf configMap: name: apache-conf #тут указываем pvc - наш запрос на pv - name: research-vol # это имя взято из лейбла pv persistentVolumeClaim: claimName: research-pvc # это имя взято из лейбла pvс - name: pv-files-of-site-test-ru persistentVolumeClaim: claimName: pvc-files-of-site-test-ru |
[/codesyntax]
[root@minikub ~]# kubectl apply -f my-project/deployment-apache.yaml
[root@minikub ~]# kubectl apply -f my-project/deployment.yaml
всё, после того как поды обновятся можно загружать файлы сайта в директорию:
/nfs-client/files-of-site-test.ru/
========================================================
Dynamic NFS provision
добавим динамическую работу с pv
у нас уже установлен nfs сервер:
192.168.1.82 и у него общая директория /nfs
на клиентах директория /nfs
cat rbac.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
kind: ServiceAccount apiVersion: v1 metadata: name: nfs-client-provisioner --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io |
[/codesyntax]
cat class.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 |
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: example.com/nfs reclaimPolicy: Retain parameters: archiveOnDelete: "false" |
[/codesyntax]
cat deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner spec: replicas: 1 selector: matchLabels: app: nfs-client-provisioner strategy: type: Recreate template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: example.com/nfs - name: NFS_SERVER value: 192.168.1.82 - name: NFS_PATH value: /nfs volumes: - name: nfs-client-root nfs: server: 192.168.1.82 path: /nfs |
[/codesyntax]
запрос будет выглядеть следующим образом:
cat pvc.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc1 spec: storageClassName: managed-nfs-storage accessModes: - ReadWriteMany resources: requests: storage: 500Mi |
[/codesyntax]
теперь применяем:
kubectl apply -f rbac.yaml
kubectl apply -f class.yaml
kubectl apply -f deployment.yaml
kubectl apply -f pvc.yaml
============================================================
apache nginx + файлы сайта на nfs сервере c auto provision.
[root@minikub ~]# cat nfs-auto-provisioner/rbac.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
kind: ServiceAccount apiVersion: v1 metadata: name: nfs-client-provisioner --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io |
[/codesyntax]
[root@minikub ~]# cat nfs-auto-provisioner/class.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: test.ru/nfs reclaimPolicy: Retain parameters: archiveOnDelete: "false" |
[root@minikub ~]# cat nfs-auto-provisioner/deployment.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner spec: replicas: 1 selector: matchLabels: app: nfs-client-provisioner strategy: type: Recreate template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: test.ru/nfs - name: NFS_SERVER value: 192.168.1.82 - name: NFS_PATH value: /nfs volumes: - name: nfs-client-root nfs: server: 192.168.1.82 path: /nfs |
[root@minikub ~]# kubectl apply -f rbac.yaml
[root@minikub ~]# kubectl apply -f class.yaml
[root@minikub ~]# kubectl apply -f deployment.yaml
cat pvc.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: volume-for-site-testru spec: storageClassName: managed-nfs-storage accessModes: - ReadWriteMany resources: requests: storage: 3Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: volume-for-logs-site-testru spec: storageClassName: managed-nfs-storage accessModes: - ReadWriteMany resources: requests: storage: 4Gi |
[/codesyntax]
cat httpd/service-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: service-apache-for-site-testru # имя сервиса spec: ports: - port: 8080 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: apache-site-testru #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
cat httpd/deployment-apache.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
apiVersion: v1 kind: ConfigMap metadata: name: apache-conf-for-site-testru data: testru.conf: | <VirtualHost *:80> ServerName _ DocumentRoot /var/site/ ErrorLog /var/log/httpd/testru-httpd-error.log CustomLog /var/log/httpd/testru-httpd-access.log combined <IfModule php7_module> AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps <IfModule dir_module> DirectoryIndex index.html index.php </IfModule> <Directory /var/site> Options -Indexes Options +ExecCGI Require all granted Options FollowSymLinks AllowOverride All </Directory> </IfModule> </VirtualHost> --- apiVersion: apps/v1 kind: Deployment metadata: name: deployment-apache-site-testru spec: replicas: 1 selector: matchLabels: app: apache-site-testru # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: apache-site-testru # по вот этому лейблу репликасет цепляет под spec: containers: - image: polinux/httpd-php:php72 name: apache ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 1000m memory: 400Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 2000m memory: 1024Mi # тут подключаем ранее созданный конфиг apache volumeMounts: #должен располагаться под containers - name: apache-conf-for-site-testru #имя нашего конфигмапа, созданного ранее. mountPath: /etc/httpd/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: volume-for-logs-site-testru # это имя взято из лейбла pv mountPath: /var/log/httpd/ # тут указываем какую директорию мы прокидываем в pv - name: volume-for-site-testru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: apache-conf-for-site-testru configMap: name: apache-conf-for-site-testru #тут указываем pvc - наш запрос на pv - name: volume-for-site-testru # это имя взято из лейбла pv persistentVolumeClaim: claimName: volume-for-site-testru # это имя взято из лейбла pvс - name: volume-for-logs-site-testru persistentVolumeClaim: claimName: volume-for-logs-site-testru |
cat nginx/service-nginx.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: service-nginx-for-site-testru # имя сервиса spec: ports: - port: 80 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: nginx-site-testru #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
cat nginx/deployment-nginx.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf-for-site-testru data: testru.conf: | server { listen 80; server_name _; access_log /var/log/nginx/testru-nginx-access.log; error_log /var/log/nginx/testru-nginx-error.log error; location ~* \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|swf|js|html|htm|)$ { root /var/site; } location / { proxy_pass http://service-apache-for-site-testru:8080; # А вот сюда пишем название сервиса отвечающего за апач proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; } } --- apiVersion: apps/v1 kind: Deployment metadata: name: deployment-nginx-site-testru spec: replicas: 1 selector: matchLabels: app: nginx-site-testru # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: nginx-site-testru # по вот этому лейблу репликасет цепляет под spec: containers: - image: nginx:1.12 name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: 50m memory: 100Mi limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: 100m memory: 100Mi # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: nginx-conf-for-site-testru #имя нашего конфигмапа, созданного ранее. mountPath: /etc/nginx/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: volume-for-logs-site-testru # это имя взято из лейбла pv mountPath: /var/log/nginx/ # тут указываем какую директорию мы прокидываем в pv - name: volume-for-site-testru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: nginx-conf-for-site-testru configMap: name: nginx-conf-for-site-testru #тут указываем pvc - наш запрос на pv - name: volume-for-site-testru # это имя взято из лейбла pv persistentVolumeClaim: claimName: volume-for-site-testru # это имя взято из лейбла pvс - name: volume-for-logs-site-testru persistentVolumeClaim: claimName: volume-for-logs-site-testru |
[/codesyntax]
kubectl apply -f pvc.yaml
kubectl apply -f httpd/service-apache.yaml
kubectl apply -f httpd/deployment-apache.yaml
kubectl apply -f nginx/service-nginx.yaml
kubectl apply -f nginx/deployment-nginx.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[root@minikub my-project]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-636e51ad-cd68-4425-80f0-259669a3a4ec 4Gi RWX Retain Bound default/volume-for-logs-site-testru managed-nfs-storage 6m42s pvc-8e1b883e-1407-441f-9d24-162e7d83b015 3Gi RWX Retain Bound default/volume-for-site-testru managed-nfs-storage 6m42s [root@minikub my-project]# kubectl describe pv pvc-8e1b883e-1407-441f-9d24-162e7d83b015 Name: pvc-8e1b883e-1407-441f-9d24-162e7d83b015 Labels: <none> Annotations: pv.kubernetes.io/provisioned-by: test.ru/nfs Finalizers: [kubernetes.io/pv-protection] StorageClass: managed-nfs-storage Status: Bound Claim: default/volume-for-site-testru Reclaim Policy: Retain Access Modes: RWX VolumeMode: Filesystem Capacity: 3Gi Node Affinity: <none> Message: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 192.168.1.82 Path: /nfs/default-volume-for-site-testru-pvc-8e1b883e-1407-441f-9d24-162e7d83b015 ReadOnly: false Events: <none> |
cat /nfs-client/default-volume-for-site-testru-pvc-8e1b883e-1407-441f-9d24-162e7d83b015/index.html
ttt
Helm
Установим helm
yum install epel-release
yum install snapd
systemctl enable --now snapd.socket
systemctl enable snapd
systemctl restart snapd
ln -s /var/lib/snapd/snap /snap
snap install helm --classic
echo 'export PATH="$PATH:/snap/bin" ' >> ~/.profile
export PATH="$PATH:/snap/bin"
Получить справку по возможностям хельма:
[root@minikub ~]# helm help
Создание Helm Chart
Далее — создадим свой чарт, обновим в нём шаблоны, и задеплоим какое-то приложение в Kubernretes.
Создаём новый чарт:
[root@minikub ~]# mkdir helm
[root@minikub ~]# cd helm/
[root@minikub helm]# helm create example-chart
Creating example-chart
посмотрим содержимое:
[root@minikub helm]# tree example-chart
example-chart
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
3 directories, 10 files
Содержимое его деплоймента:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
[root@minikub helm]# cat example-chart/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "example-chart.fullname" . }} labels: {{- include "example-chart.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "example-chart.selectorLabels" . | nindent 6 }} template: metadata: {{- with .Values.podAnnotations }} annotations: {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "example-chart.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "example-chart.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }} |
[/codesyntax]
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
[root@minikub helm]# cat example-chart/values.yaml # Default values for example-chart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: nginx pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "" imagePullSecrets: [] nameOverride: "" fullnameOverride: "" serviceAccount: # Specifies whether a service account should be created create: true # Annotations to add to the service account annotations: {} # The name of the service account to use. # If not set and create is true, a name is generated using the fullname template name: "" podAnnotations: {} podSecurityContext: {} # fsGroup: 2000 securityContext: {} # capabilities: # drop: # - ALL # readOnlyRootFilesystem: true # runAsNonRoot: true # runAsUser: 1000 service: type: ClusterIP port: 80 ingress: enabled: false annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: - host: chart-example.local paths: [] tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 100 targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 nodeSelector: {} tolerations: [] affinity: {} |
[/codesyntax]
Тут всё достаточно очевидно — для replicas: {{ .Values.replicaCount }}
в templates/deployment.yaml
будет использовано значение replicaCount: 1
из values.yaml
.
Но мы эти шаблоны использовать не будем — а напишем свой велосипед чарт.
Удаляем их:
[root@minikub helm]# rm -rf example-chart/templates/*
Далее добавим свой ConfigMap.
Добавление template
Создадим файл example-chart/templates/configmap.yaml
, а в нём — содержимое для файла index.html
:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 |
[root@minikub helm]# cat example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap data: index.html: "Hello, World" |
[/codesyntax]
chart linter
Перед установкой чарта имеет смысл выполнить проверку синтаксиса чарта — используем helm lint
:
[root@minikub helm]# helm lint example-chart/
==> Linting example-chart/
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
chart install
Ещё раз проверим — на какой кластер настроен наш kubectl
:
[root@minikub helm]# kubectl config current-context
minikube
Для установки выполняем helm install
, которому первым аргументом передаём имя релиза, потом опции, и путь к файлам чарта.
Перед выполнением реальных действий имеет смысл выполнить «тестовый прогон» — используем --dry-run
, и добавим --debug
для деталей:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
[root@minikub helm]# helm install example-chart --dry-run --debug example-chart/ install.go:159: [debug] Original chart version: "" install.go:176: [debug] CHART PATH: /root/helm/example-chart NAME: example-chart LAST DEPLOYED: Sun Jul 5 20:18:00 2020 NAMESPACE: default STATUS: pending-install REVISION: 1 TEST SUITE: None USER-SUPPLIED VALUES: {} COMPUTED VALUES: affinity: {} autoscaling: enabled: false maxReplicas: 100 minReplicas: 1 targetCPUUtilizationPercentage: 80 fullnameOverride: "" image: pullPolicy: IfNotPresent repository: nginx tag: "" imagePullSecrets: [] ingress: annotations: {} enabled: false hosts: - host: chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} podAnnotations: {} podSecurityContext: {} replicaCount: 1 resources: {} securityContext: {} service: port: 80 type: ClusterIP serviceAccount: annotations: {} create: true name: "" tolerations: [] HOOKS: MANIFEST: --- # Source: example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap data: index.html: "Hello, World" |
[/codesyntax]
Ошибок нет — устанавливаем его:
[root@minikub helm]# helm install example-chart example-chart/
NAME: example-chart
LAST DEPLOYED: Sun Jul 5 20:18:35 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Проверяем его статус:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 |
[root@minikub helm]# helm get manifest example-chart --- # Source: example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nginx-configmap data: index.html: "Hello, World" |
[/codesyntax]
helm
вывел информацию о ресурсах и файлах, которые были применены к релизу.
Проверим с kubectl
:
[root@minikub helm]# kubectl describe cm nginx-configmap
Name: nginx-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, World
Events: <none>
chart uninstall
Аналогично, для удаления используем helm uninstall
и имя релиза:
[root@minikub helm]# helm uninstall example-chart
release "example-chart" uninstalled
Template переменные
Хорошо — всё работает, но сейчас все данные в нашем ConfigMap статичны.
Изменим это — включим в работу шаблонизатор.
Для helm
достпен набор предопределённых значений, например — Release.Name
, см. полный список в документации.
Редактируем шаблон нашего ConfigMap:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 |
[root@minikub helm]# cat example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: index.html: "Hello, World" |
[/codesyntax]
И добавим своих переменных — удаляем текущий файл values.yaml
:
[root@minikub helm]# rm -rf example-chart/values.yaml
И создаём его заново, но с одним полем — user: "Username"
:
[codesyntax lang="php"]
1 2 3 |
[root@minikub helm]# cat example-chart/values.yaml user: "Username" |
[/codesyntax]
А затем используем переменную user
в шаблоне:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 |
[root@minikub helm]# cat example-chart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap data: index.html: "Hello, {{ .Values.user }}" |
[/codesyntax]
Тут через .Values
мы указываем обращение к нашему values,yaml
, из которого helm
должен подтянуть значение переменной user.
Применяем:
[root@minikub helm]# helm install example-chart example-chart/
NAME: example-chart
LAST DEPLOYED: Sun Jul 5 20:26:11 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Проверяем:
1 2 3 |
[root@minikub helm]# kubectl get cm NAME DATA AGE example-chart-configmap 1 53s |
И содержимое:
[root@minikub helm]# kubectl describe cm example-chart-configmap
Name: example-chart-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, Username
Events: <none>
chart upgrade
Что, если мы хотим изменить значение Username?
Можно удалить релиз, и задеплоить заново, передав новое значение либо через редактирование values.yaml
, либо через --set
:
[root@minikub helm]# helm uninstall example-chart
release "example-chart" uninstalled
[root@minikub helm]# helm install example-chart example-chart/ --set user=NewUser
NAME: example-chart
LAST DEPLOYED: Sun Jul 5 20:28:53 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
Проверяем
[root@minikub helm]# kubectl describe cm example-chart-configmap
Name: example-chart-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, NewUser
Events: <none>
Другой вариант — вызвать helm upgrade
, передать имя релиза и новое значение:
[root@minikub helm]# helm upgrade example-chart example-chart/ --set user=AnotherOneUser
Release "example-chart" has been upgraded. Happy Helming!
NAME: example-chart
LAST DEPLOYED: Sun Jul 5 20:29:57 2020
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
проверяем:
[root@minikub helm]# kubectl describe cm example-chart-configmap
Name: example-chart-configmap
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: example-chart
meta.helm.sh/release-namespace: default
Data
====
index.html:
----
Hello, AnotherOneUser
Events: <none>
helm package
Что бы передать наш чарт другим пользователем — можно его упаковать в tgz-файл.
Используем helm package
, который создаст файл вида имя-чарта-версия-чарта.tgz.
Версию helm
получит из метаданных чарта:
[root@minikub helm]# cat example-chart/Chart.yaml | grep version:
version: 0.1.0
Упаковываем
[root@minikub helm]# helm package example-chart/
Successfully packaged chart and saved it to: /root/helm/example-chart-0.1.0.tgz
И содержимое архива:
[root@minikub helm]# tar tf example-chart-0.1.0.tgz
example-chart/Chart.yaml
example-chart/values.yaml
example-chart/templates/configmap.yaml
example-chart/.helmignore
Helm репозитории
Для передачи чартов используем helm-репозитории.
Раньше можно было запустить локальный репоизторий с помощью helm serve
, но в Helm v3 его выпилили.
Для работы с репозиториями в V3 используем helm repo
.
По-умолчанию в список репозиториев сразу добавляется репозиторий от Google:
[root@minikub helm]# helm repo add stable https://kubernetes-charts.storage.googleapis.com/
"stable" has been added to your repositories
[root@minikub helm]# helm repo list
NAME URL
stable https://kubernetes-charts.storage.googleapis.com/
Running local Helm repo
Для того, что бы создать свой репозиторий — достаточно выполнить helm package
чарта, после чего сгенерировать файл index.yaml
в каталоге, который хранит архив.
В качестве бекенда для репозиториев может быть что угодно — от Github Pages, до AWS S3, см. The Chart Repository Guide.
Тут пример локального репозитория.
Создаём каталог, переносим в него архив:
[root@minikub helm]# mkdir helm-local-repo
[root@minikub helm]# mv example-chart-0.1.0.tgz helm-local-repo/
Инициализируем репозиторий:
[root@minikub helm]# helm repo index helm-local-repo/
Содержимое
[root@minikub helm]# tree helm-local-repo/
helm-local-repo/
├── example-chart-0.1.0.tgz
└── index.yaml
0 directories, 2 files
Что бы получить к нему доступ — запустим простой NGINX:
[root@minikub helm]# docker run -ti -v $(pwd)/helm-local-repo/:/usr/share/nginx/html -p 80:80 nginx
Проверяем подключение:
[root@minikub helm]# curl localhost/index.yaml
NAME URL
stable https://kubernetes-charts.storage.googleapis.com/
Helm практика
рассмотрим наш деплоймент apache nginx
[root@minikub ~]# mkdir -p /root/helm/my-site/{charts,templates}
[root@minikub ~]# cat /root/helm/my-site/Chart.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 |
apiVersion: v2 name: test.ru description: A Helm chart for Kubernetes type: application version: 0.1.0 appVersion: 1.16.0 |
[/codesyntax]
[root@minikub ~]# cat /root/helm/my-site/values.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# имя сайта domain: test.ru #image для nginx image_nginx: nginx:latest #image для apache image_httpd: polinux/httpd-php:php72 #количество реплик для nginx number_of_replica_nginx: 2 #количество реплик для apache number_of_replica_httpd: 2 #имя сервиса для nginx name_of_service_nginx: service-nginx-for-site-testru #имя сервиса для apache name_of_service_apache: service-apache-for-site-testru #имя деплоймента для apache name_of_deployment_httpd: deployment-apache-site-testru #имя деплоймента для nginx name_of_deployment_nginx: deployment-nginx-site-testru #имя конфига для apache name_of_configmap_httpd: apache-conf-for-site-testru #имя конфига для nginx name_of_configmap_nginx: nginx-conf-for-site-testru requests_cpu_nginx: 50m requests_memory_nginx: 100Mi requests_cpu_httpd: 1000m requests_memory_httpd: 400Mi limits_cpu_nginx: 100m limits_memory_nginx: 100Mi limits_cpu_httpd: 2000m limits_memory_httpd: 1024Mi |
[/codesyntax]
[root@minikub ~]# vim /root/helm/my-site/templates/ingress.yml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
--- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-for-site-testru spec: rules: - host: {{ .Values.domain }} #тут указывается наш домен http: paths: #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service) - backend: serviceName: {{ .Values.name_of_service_nginx }} #тут указывается наш сервис на который ингресс будет перенаправлять весь поток servicePort: 80 #порт на котором сервис слушает |
[/codesyntax]
[root@minikub ~]# cat /root/helm/my-site/templates/service-nginx.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: {{ .Values.name_of_service_nginx }} # имя сервиса spec: ports: - port: 80 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: nginx-site-testru #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
[root@minikub ~]# cat /root/helm/my-site/templates/service-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
--- apiVersion: v1 kind: Service metadata: name: {{ .Values.name_of_service_apache }} # имя сервиса spec: ports: - port: 8080 # принимать на 80 targetPort: 80 # отправлять на 80 selector: app: apache-site-testru #отправлять на все поды с данным лейблом type: ClusterIP |
[/codesyntax]
[root@minikub ~]# cat /root/helm/my-site/templates/deployment-nginx.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Values.name_of_configmap_nginx }} data: #testru.conf: | {{.Values.domain}}.conf: | server { listen 80; server_name _; access_log /var/log/nginx/testru-nginx-access.log; error_log /var/log/nginx/testru-nginx-error.log error; location ~* \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|wav|bmp|rtf|swf|js|html|htm|)$ { root /var/site; } location / { proxy_pass http://{{.Values.name_of_service_apache}}:8080; # А вот сюда пишем название сервиса отвечающего за апач proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; } } --- apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.name_of_deployment_nginx }} spec: replicas: {{ .Values.number_of_replica_nginx }} selector: matchLabels: app: nginx-site-testru # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: nginx-site-testru # по вот этому лейблу репликасет цепляет под spec: containers: - image: {{ .Values.image_nginx }} name: nginx ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: {{ .Values.requests_cpu_nginx }} memory: {{ .Values.requests_memory_nginx }} limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: {{ .Values.limits_cpu_nginx }} memory: {{ .Values.limits_memory_nginx }} # тут подключаем ранее созданный конфиг nginx volumeMounts: #должен располагаться под containers - name: {{ .Values.name_of_configmap_nginx }} #имя нашего конфигмапа, созданного ранее. mountPath: /etc/nginx/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: volume-for-logs-site-testru # это имя взято из лейбла pv mountPath: /var/log/nginx/ # тут указываем какую директорию мы прокидываем в pv - name: volume-for-site-testru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: {{ .Values.name_of_configmap_nginx }} configMap: name: {{ .Values.name_of_configmap_nginx }} #тут указываем pvc - наш запрос на pv - name: volume-for-site-testru # это имя взято из лейбла pv persistentVolumeClaim: claimName: volume-for-site-testru # это имя взято из лейбла pvс - name: volume-for-logs-site-testru persistentVolumeClaim: claimName: volume-for-logs-site-testru |
[/codesyntax]
[root@minikub ~]# cat /root/helm/my-site/templates/deployment-apache.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Values.name_of_configmap_httpd }} data: #testru.conf: | {{.Values.domain}}.conf: | <VirtualHost *:80> ServerName _ DocumentRoot /var/site/ ErrorLog /var/log/httpd/testru-httpd-error.log CustomLog /var/log/httpd/testru-httpd-access.log combined <IfModule php7_module> AddType application/x-httpd-php .php AddType application/x-httpd-php-source .phps <IfModule dir_module> DirectoryIndex index.html index.php </IfModule> <Directory /var/site> Options -Indexes Options +ExecCGI Require all granted Options FollowSymLinks AllowOverride All </Directory> </IfModule> </VirtualHost> --- apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.name_of_deployment_httpd }} spec: replicas: {{ .Values.number_of_replica_httpd }} selector: matchLabels: app: apache-site-testru # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: apache-site-testru # по вот этому лейблу репликасет цепляет под spec: containers: - image: {{ .Values.image_httpd }} name: apache ports: - containerPort: 80 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: / port: 80 periodSeconds: 10 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: / port: 80 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 10 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: {{ .Values.requests_cpu_httpd }} memory: {{ .Values.requests_memory_httpd }} limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: {{ .Values.limits_cpu_httpd }} memory: {{ .Values.limits_memory_httpd }} # тут подключаем ранее созданный конфиг apache volumeMounts: #должен располагаться под containers - name: {{ .Values.name_of_configmap_httpd }} #имя нашего конфигмапа, созданного ранее. mountPath: /etc/httpd/conf.d/ # путь по которому мы будем монтировать наш конфиг #тут подключаем наш persistant volume - name: volume-for-logs-site-testru # это имя взято из лейбла pv mountPath: /var/log/httpd/ # тут указываем какую директорию мы прокидываем в pv - name: volume-for-site-testru mountPath: /var/site/ volumes: #(описывает тома) должен располагаться под spec - name: {{ .Values.name_of_configmap_httpd }} configMap: name: {{ .Values.name_of_configmap_httpd }} #тут указываем pvc - наш запрос на pv - name: volume-for-site-testru # это имя взято из лейбла pv persistentVolumeClaim: claimName: volume-for-site-testru # это имя взято из лейбла pvс - name: volume-for-logs-site-testru persistentVolumeClaim: claimName: volume-for-logs-site-testru |
[/codesyntax]
[root@minikub ~]# cd /root/helm/my-site/
[root@minikub my-site]# helm install site-testru ../my-site/
NAME: site-testru
LAST DEPLOYED: Wed Jul 22 17:46:19 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
1 2 3 |
[root@minikub my-site]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION site-testru default 1 2020-07-22 17:46:19.76686151 +0600 +06 deployed test.ru-0.1.0 1.16.0 |
Autoscaling
HorizontalPodAutoscaler не может быть применен к объектам, которые не предназначены для масштабирования, например DaemonSets. Horizontal Pod Autoscaler состоит из Kubernetes ресурса (объекта) и контроллера, поведение которого описывается ресурсом.
C периодичностью 15 секунд (можно изменить с помощью параметра --horizontal-pod-autoscaler-sync-period), контроллер собирает данные по использованию метрик, определенных в манифесте ресурса HorizontalPodAutoscaler. Метрики собираются или с resource metrics API (метрики использования ресурсов подами) или с custom metrics API (остальные метрики, например, метрики приложения).
Для каждого подконтрольного пода, контроллер собирает метрики (например, использования CPU) с resource metrics API (metrics.k8s.io, предоставляется metrics-server). Далее, происходит вычисление текущего значения использования CPU в процентах от запрошенных ресурсов (resource request) контейнерами каждого пода, после чего это значение сравнивается с “целевым” (target) значением - порогом, после которого количество подов должно быть увеличено.
Важно! Если не указаны resource request хотя бы для одного из контейнеров в Replication Controller, Replica Set или Deployment, то текущее значение использование CPU подами не может быть корректно определено, и, в результате, HorizontalPodAutoscaler не будет предпринимать никаких действий по масштабированию.
Формула, по которой HorizontalPodAutoscaler вычисляет требуемое количество реплик выглядит так:
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
Например, если текущее значение метрики (currentMetricValue) равно 200m,
а ожидаемое (desiredMetricValue) установлено в 100m,
то количество реплик будет удвоено (200.0 / 100.0 == 2.0).
Если же текущее значение метрики равно всего лишь 50m, то количество реплик должно быть уменьшено вдвое (50.0 / 100.0 == 0.5). Если соотношение текущего значения метрики к ожидаемому значению достаточно близко к 1, то никаких действий не будет предпринято.
если указали targetAverageUtilization при описании ресурса HorizontalPodAutoscaler, то текущее значение метрики (currentMetricValue) использования CPU рассчитывается как среднее значение этой метрики для всех подов, контролируемых данным автоскейлером.
После того, как текущее значение использования CPU снизилось и оставалось низким в течении 5 минут (устанавливается с помощью параметра --horizontal-pod-autoscaler-downscale-stabilization), количество реплик было автоматически уменьшается.
Итак для начала надо установить metrics-server
helm repo add stable https://charts.helm.sh/stable
helm upgrade -i metrics-server stable/metrics-server --set args='{--kubelet-preferred-address-types=InternalIP,--kubelet-insecure-tls,--metric-resolution=30s}' --namespace=kube-system
Посмотреть ресурсы на нодах:
kubectl top node
посмотреть ресурсы на деплойментах:
kubectl top deployment
посмотреть ресурсы на подах:
kubectl top pod
у нас есть следующий деплоймент и сервис
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: hello-world-deployment spec: replicas: 1 selector: matchLabels: app: hello-world-app template: metadata: labels: app: hello-world-app spec: containers: - image: nginx:latest name: hello-world-app ports: - containerPort: 80 resources: requests: cpu: 30m memory: 50Mi limits: cpu: 200m memory: 300Mi --- apiVersion: v1 kind: Service metadata: name: hello-world-app-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: hello-world-app type: ClusterIP |
[/codesyntax]
добавим к нему автоскейлер по CPU и MEMORY
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
--- apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-example-cpu spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hello-world-deployment minReplicas: 1 maxReplicas: 5 targetCPUUtilizationPercentage: 10 --- apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: hpa-example-memory spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hello-world-deployment minReplicas: 1 maxReplicas: 5 metrics: - type: Resource resource: name: memory targetAverageUtilization: 25 |
[/codesyntax]
ниже рассмотрим что куда зачем:
Для CPU:
1 2 3 4 5 6 7 8 9 10 11 12 |
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-example-cpu (1) spec: scaleTargetRef: apiVersion: apps/v1 (2) kind: Deployment (3) name: hello-world-deployment (4) minReplicas: 1 (5) maxReplicas: 5 (6) targetCPUUtilizationPercentage: 10 (7) |
1.Имя этого автоскейлера
2.Версия API масштабируемого объекта
3.Тип объекта для масштабирования
4.Название масштабируемого объекта
5.Минимальное количество реплик для уменьшения
6.Максимальное количество реплик для масштабирования
7.Средний процент запрошенной памяти, которую должен использовать каждый модуль. т.е. % от requests
использования CPU, при достижении которого НРА начнёт добавлять или удалять поды
Для MEMORY:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: hpa-example-memory (1) spec: scaleTargetRef: apiVersion: apps/v1 (2) kind: Deployment (3) name: hello-world-deployment (4) minReplicas: 1 (5) maxReplicas: 5 (6) metrics: - type: Resource resource: name: memory targetAverageUtilization: 25 (7) |
1.Имя этого автоскейлера
2.Версия API масштабируемого объекта
3.Тип объекта для масштабирования
4.Название масштабируемого объекта
5.Минимальное количество реплик для уменьшения
6.Максимальное количество реплик для масштабирования
7.Средний процент запрошенной памяти, которую должен использовать каждый модуль.
чтобы протестировать автосейлинг запустим нагрузку:
kubectl run load-generator --image=busybox -- /bin/sh -c "while true; do wget -q -O- http://hello-world-app-service; done"
ci/cd проекта - gitlab
Рассмотрим как деплоить проект в кубер через ci/cd от gitlab
Сначала добавим пользователя gitlab - kubernetes в котором у нас будут храниться конфиги и образа.
заходим под рутом и создаём нового пользователя:
далее надо задать ему пароль
выходим из под рута
авторизуемся под нашим пользователем:
указываем новый пароль
нас выкинуло, пароль успешно задан:
создаём новый проект:
и задаём SSH ключ
генерим ключ если нету:
[root@minikub ~]# ssh-keygen
и добавляем его в гитлаб
[root@minikub ~]# cat /root/.ssh/id_rsa.pub
переходим в наш проект:
копируем URL
и выкачиваем:
[root@minikub ~]# git clone git@192.168.1.190:kubernetes/street-terminal.git
[root@minikub ~]# cd street-terminal/
Создаём namespace :
[root@minikub ~]# kubectl create namespace terminal-soft
там у нас уже есть redis (как его добавить мы описывали вот в этой статье:
Redis in kubernetes
так же в кубере будет запущена база postgres, вооот по этой статье:
postgres - stolon
)
на них пока не обращаем внимания, рассмотрим поэтапный деплой 1 это будет сборка контейнера и загрузка его в gitlab registry.
у нас есть докерфайл:
[root@minikub ~]# cat street-terminal/service/Dockerfile
[codesyntax lang="php"]
1 2 3 4 |
FROM openjdk:8-jdk-alpine COPY app/ /app/ WORKDIR /app ENTRYPOINT ["java", "-jar", "/app/monolith-app-1.0-SNAPSHOT.jar"] |
[/codesyntax]
в папке app находится наше скомпилированное java приложение и файл с подключением к базе и к редису:
[codesyntax lang="php"]
1 2 3 4 5 |
[root@minikub ~]# ll street-terminal/service/app/ total 53636 -rw-r--r-- 1 root root 538 Oct 15 15:30 application.properties -rw-r--r-- 1 root root 54915739 Oct 15 15:30 monolith-app-1.0-SNAPSHOT.jar |
[/codesyntax]
создаём 2 раннера один docker другой shell, для этого смотрим токен, необходимый для регистрации ранера:
вот наш токен:
TyJT8b8vdcMRNDG7trE5
с ним мы будем регистрировать наши ранеры. я в качестве ранера выбрал свой же гитлаб но можно использовать любой сервер. Установить ранер можно как указано в этой статье:
Установка и настройка Gitlab и Gitlab Runner
у меня он уже установлен
Приступим к регистрации SHELL раннера:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[root@gitlab ~]# gitlab-runner register Running in system-mode. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): http://192.168.1.190/ Please enter the gitlab-ci token for this runner: TyJT8b8vdcMRNDG7trE5 Please enter the gitlab-ci description for this runner: [gitlab]: shell-runner Please enter the gitlab-ci tags for this runner (comma separated): Whether to lock Runner to current project [true/false]: [false]: Registering runner... succeeded runner=TyJT8b8v Please enter the executor: docker, docker-ssh, parallels, virtualbox, kubernetes, shell, ssh, docker+machine, docker-ssh+machine: shell Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! |
[/codesyntax]
Теперь установим DOCKER runner:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[root@gitlab ~]# gitlab-runner register Running in system-mode. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): http://192.168.1.190/ Please enter the gitlab-ci token for this runner: TyJT8b8vdcMRNDG7trE5 Please enter the gitlab-ci description for this runner: [gitlab]: docker-runner Please enter the gitlab-ci tags for this runner (comma separated): docker-runner Whether to run untagged builds [true/false]: [false]: Whether to lock Runner to current project [true/false]: [false]: Registering runner... succeeded runner=TyJT8b8v Please enter the executor: virtualbox, docker+machine, kubernetes, ssh, docker-ssh+machine, docker, docker-ssh, parallels, shell: docker Please enter the default Docker image (e.g. ruby:2.1): alpine:latest Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded! |
[/codesyntax]
при регистрации ранера я забыл добавить тег shell ранеру, - его всегда можно можно добавить/поправить в панели:
Проверим статус и включены ли Docker и Gitlab раннер при запуске системы:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 |
[root@gitlab ~]# gitlab-runner status gitlab-runner: Service is running! [root@gitlab ~]# [root@gitlab ~]# systemctl is-enabled gitlab-runner enabled [root@gitlab ~]# [root@gitlab ~]# systemctl is-enabled docker enabled [root@gitlab ~]# |
[/codesyntax]
теперь проверим в панели появились ли наши runner-ы
добавляем права на нашей целевой тачке:
[root@minikub street-terminal]# adduser gitlab-runner
[root@minikub street-terminal]# usermod -a -G docker gitlab-runner
[root@gitlab ~]# usermod -a -G docker gitlab-runner
[root@minikub street-terminal]# id gitlab-runner
uid=1004(gitlab-runner) gid=1004(gitlab-runner) groups=1004(gitlab-runner),993(docker)
[root@minikub street-terminal]# systemctl restart docker
[root@minikub street-terminal]# passwd gitlab-runner
Changing password for user gitlab-runner.
New password:
BAD PASSWORD: The password is a palindrome
Retype new password:
passwd: all authentication tokens updated successfully.
[root@minikub street-terminal]# cat /etc/sudoers | grep wheel | grep -v '#'
%wheel ALL=(ALL) NOPASSWD: ALL
С сервера с которого runer будет производить деплой, должны быть раскиданы ssh ключи (из под пользователя gitlab-runner )
[root@gitlab ~]# su - gitlab-runner
[gitlab-runner@gitlab ~]$ cat /etc/hosts | grep minikub
192.168.1.120 minikub
[gitlab-runner@gitlab ~]$ ssh-keygen
[gitlab-runner@gitlab ~]$ ssh-copy-id gitlab-runner@minikub
так же копируем конфиг чтобы раннер мог выполнять удалённые команды:
[root@minikub street-terminal]# cp /etc/kubernetes/admin.conf /home/gitlab-runner/.kube/config
[root@minikub street-terminal]# chown -R gitlab-runner:gitlab-runner /home/gitlab-runner/.kube/
на всех тачках добавляем:
cat /etc/docker/daemon.json
{ "insecure-registries" : ["192.168.1.190:4567"] }
systemctl daemon-reload
systemctl restart docker
Создаём в корне проекта файл .gitlab-ci.yml
[root@minikub street-terminal]# cat /root/street-terminal/.gitlab-ci.yml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
stages: #Тут описываются стадии - create_image variables: #Здесь описываем переменные project_name: 'service' #Имя проекта tag1: 'v1' .autorizate_to_gitlab: &autorizate_to_gitlab | # Данная запись является ЯКОРЕМ, т.е. её можно вызывать сколько угодно рас и она будет выполнять описанные в ней действия ssh gitlab-runner@minikub docker login -u kubernetes -p 123456789 http://192.168.1.190:4567 # тут мы авторизуемся в гитлаб на нашей целевой тачке docker login -u kubernetes -p 123456789 http://192.168.1.190:4567 # тут мы авторизуемся в гитлаб на нашем ранере create_image: # Первая стадия сборки образов variables: # Описание переменных HOST: 'IP1' # Определяем переменную HOST которая будет использоваться в якорях (пока ничего не указываем) stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: #с помощью директивы only. Она определяем ветки, для которых будет создаваться пайплайн, а с помощью ключевого слова tags можно разрешить создавать пайплайн для тегов. К сожалению, директива only есть только для задач — её нельзя указать при описании стадии - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе script: - docker build -f service/Dockerfile -t 192.168.1.190:4567/kubernetes/street-terminal/$project_name:$tag1 service/. # пути до файлов указываются относительно корня проекта - docker push 192.168.1.190:4567/kubernetes/street-terminal/$project_name:$tag1 - ssh gitlab-runner@minikub docker pull 192.168.1.190:4567/kubernetes/street-terminal/$project_name:$tag1 # тут выкачиваем наш собранный образ на целевоей сервер minikub after_script: - docker logout http://192.168.1.190:4567 # Разлогиниваемся на гитлаб ранере - sudo docker rmi 192.168.1.190:4567/kubernetes/street-terminal/$project_name:$tag1 # Удаляем собранный образ с гитлаб ранера(чистим за собой) when: manual # Данные действия производятся вручную |
[/codesyntax]
данный pipeline будет производить:
1.сборку образа
2.тегирование и загрузку образа в gitlab
3.выкачивание образа на целевой сервер.
пушим его в наш репозиторий:
[root@minikub street-terminal]# git add .
[root@minikub street-terminal]# git commit -m "add ci/cd8"
[master 4dd6343] add ci/cd8
1 file changed, 1 insertion(+)
[root@minikub street-terminal]# git push
далее в нашей панели заходим в пайплайны:
не обращаем внимания на остальные коммиты пайплайнов это я тестил пока писал инструкцию. Выбираем наш последний коммит:
тут запускаем коммит:
видим что изменился статус на running
попадаем в следующее меню которое показывает процесс выполнения(на скриншоте показано успешное выполнение)
проверяем наличие собранного образа в нашем registry:
поидее минимальная часть выполнена. НОООООО там пароли логины висят в открытом виде а это не есть хорошо, поэтому надо использовать переменные. Переменные эти будут работать в рамках одного проекта.
Добавим переменные в сам gitlab а в /root/street-terminal/.gitlab-ci.yml будем их вызывать
Добавим 2 переменные в сам гитлаб:
login_kubernetes
и
kubernetes_password
В файле .gitlab-ci.yml будем вызывать эти переменные следующим образом:
${login_kubernetes}
${kubernetes_password}
так же добавим переменные в сам gitlab-ci
gitlab_server: '192.168.1.190:4567'
gitlab_user_project: 'kubernetes/street-terminal'
их будем вызывать следующим образом:
$gitlab_server
$gitlab_user_project
[root@minikub street-terminal]# cat /root/street-terminal/.gitlab-ci.yml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
stages: #Тут описываются стадии - create_image variables: #Здесь описываем переменные project_name: 'service' #Имя проекта tag1: 'v1' gitlab_server: '192.168.1.190:4567' gitlab_user_project: 'kubernetes/street-terminal' .autorizate_to_gitlab: &autorizate_to_gitlab | # Данная запись является ЯКОРЕМ, т.е. её можно вызывать сколько угодно рас и она будет выполнять описанные в ней действия ssh gitlab-runner@minikub docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server # тут мы авторизуемся в гитлаб на нашей целевой тачке docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server # тут мы авторизуемся в гитлаб на нашем ранере create_image: # Первая стадия сборки образов variables: # Описание переменных HOST: 'IP1' # Определяем переменную HOST которая будет использоваться в якорях (пока ничего не указываем) stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: #с помощью директивы only. Она определяем ветки, для которых будет создаваться пайплайн, а с помощью ключевого слова tags можно разрешить создавать пайплайн для тегов. К сожалению, директива only есть только для задач — её нельзя указать при описании стадии - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе script: - docker build -f service/Dockerfile -t $gitlab_server/$gitlab_user_project/$project_name:$tag1 service/. # пути до файлов указываются относительно корня проекта - docker push $gitlab_server/$gitlab_user_project/$project_name:$tag1 - ssh gitlab-runner@minikub docker pull $gitlab_server/$gitlab_user_project/$project_name:$tag1 after_script: - docker logout $gitlab_server # Разлогиниваемся на гитлаб ранере - sudo docker rmi $gitlab_server/$gitlab_user_project/$project_name:$tag1 # Удаляем собранный образ с гитлаб ранера(чистим за собой) when: manual # Данные действия производятся вручную |
[/codesyntax]
добавляем эти данные в наш гитлаб:
[root@minikub street-terminal]# git add .
[root@minikub street-terminal]# git commit -m "add ci/cd14"
[root@minikub street-terminal]# git push
Ниже helm chart нашего деплоймента
[root@minikub street-terminal]# cat /root/street-terminal/service/deployment-helm/Chart.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 |
apiVersion: v2 name: terminal-soft description: A Helm chart for Kubernetes type: application version: 0.1.0 appVersion: 1.16.0 |
[/codesyntax]
[root@minikub street-terminal]# cat /root/street-terminal/service/deployment-helm/templates/deployment.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
--- apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.deployment_name }} namespace: {{ .Values.namespace }} spec: replicas: {{ .Values.replica_number }} selector: matchLabels: app: {{ .Values.app_name }} # по вот этому лейблу репликасет цепляет под # тут описывается каким мокаром следует обновлять поды strategy: rollingUpdate: maxSurge: 1 # указывает на какое количество реплик можно увеличить maxUnavailable: 1 # указывает на какое количество реплик можно уменьшить #т.е. в одно время при обновлении, будет увеличено на один (новый под) и уменьшено на один (старый под) type: RollingUpdate ## тут начинается описание контейнера template: metadata: labels: app: {{ .Values.app_name }} # по вот этому лейблу репликасет цепляет под spec: containers: - image: "{{ .Values.image_app.repository }}:{{ .Values.image_app.tag }}" name: {{ .Values.app_name }} ports: - containerPort: 8086 # тут начинаются проверки по доступности readinessProbe: # проверка готово ли приложение failureThreshold: 3 #указывает количество провалов при проверке httpGet: # по сути дёргает курлом на 80 порт path: /ui/test port: 8086 periodSeconds: 20 #как часто должна проходить проверка (в секундах) successThreshold: 1 #сбрасывает счётчик неудач, т.е. при 3х проверках если 1 раз успешно прошло, то счётчик сбрасывается и всё ок timeoutSeconds: 1 #таймаут на выполнение пробы 1 секунда initialDelaySeconds: 120 livenessProbe: #проверка на жизнь приложения, живо ли оно failureThreshold: 3 httpGet: path: /ui/test port: 8086 periodSeconds: 20 successThreshold: 1 timeoutSeconds: 1 initialDelaySeconds: 120 #означает что первую проверку надо сделать только после 10 секунд # тут начинается описание лимитов для пода resources: requests: #количество ресурсов которые резервируются для pod на ноде cpu: {{ .Values.requests_cpu_app }} memory: {{ .Values.requests_memory_app }} limits: #количество ресурсов которые pod может использовать(верхняя граница) cpu: {{ .Values.limits_cpu_app }} memory: {{ .Values.limits_memory_app }} |
[/codesyntax]
[root@minikub street-terminal]# cat /root/street-terminal/service/deployment-helm/templates/service.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
--- kind: Service apiVersion: v1 metadata: name: {{ .Values.service_name }} namespace: {{ .Values.namespace }} spec: selector: app: {{ .Values.app_name }} ports: - protocol: TCP port: 8086 targetPort: 8086 |
[/codesyntax]
[root@minikub street-terminal]# cat /root/street-terminal/service/deployment-helm/templates/ingress.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
--- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: {{ .Values.ingress_name }} namespace: {{ .Values.namespace }} spec: rules: - host: {{ .Values.domain }} #тут указывается наш домен http: paths: #список путей которые хотим обслуживать(он дефолтный и все запросы будут отпаврляться на бэкенд, т.е. на сервис my-service) - backend: serviceName: {{ .Values.service_name }} #тут указывается наш сервис servicePort: 8086 #порт на котором сервис слушает path: "/ui/test" pathType: Prefix |
[/codesyntax]
[root@minikub street-terminal]# cat /root/street-terminal/service/deployment-helm/values.yaml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#неймспейс в котором запускаемся namespace: terminal-soft #имя деплоймента deployment_name: deployment-terminal-soft #имя сервиса service_name: service-terminal-soft #имя ingress ingress_name: ingress-terminal-soft #указываем наш домен по которому будет слушать ingress domain: terminal-soft.test.ru #количество реплик деплоймента replica_number: 1 #имя лейбла сервиса app_name: terminal-soft #имя образа для сервиса image_app: repository: 192.168.1.190:4567/kubernetes/street-terminal/service tag: "v1" #количество ресурсов которые резервируются для pod на ноде проц и оперативка requests_cpu_app: 200m requests_memory_app: 600Mi #количество ресурсов которые pod может использовать(верхняя граница) limits_cpu_app: 320m limits_memory_app: 800Mi |
[/codesyntax]
[root@minikub street-terminal]# cat /root/street-terminal/.gitlab-ci.yml
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
stages: #Тут описываются стадии - create_image - check_postgres variables: #Здесь описываем переменные project_name: 'service' #Имя проекта tag1: 'v1' gitlab_server: '192.168.1.190:4567' gitlab_user_project: 'kubernetes/street-terminal' target_server: 'ssh gitlab-runner@minikub' .autorizate_to_gitlab: &autorizate_to_gitlab | # Данная запись является ЯКОРЕМ, т.е. её можно вызывать сколько угодно рас и она будет выполнять описанные в ней действия $target_server docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server # тут мы авторизуемся в гитлаб на нашей целевой тачке docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server # тут мы авторизуемся в гитлаб на нашем ранере create_image: # Первая стадия сборки образов variables: # Описание переменных HOST: 'IP1' # Определяем переменную HOST которая будет использоваться в якорях (пока ничего не указываем) stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: #с помощью директивы only. Она определяем ветки, для которых будет создаваться пайплайн, а с помощью ключевого слова tags можно разрешить создавать пайплайн для тегов. К сожалению, директива only есть только для задач — её нельзя указать при описании стадии - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе script: - docker build -f service/Dockerfile -t $gitlab_server/$gitlab_user_project/$project_name:$tag1 service/. # пути до файлов указываются относительно корня проекта - docker push $gitlab_server/$gitlab_user_project/$project_name:$tag1 - $target_server docker pull $gitlab_server/$gitlab_user_project/$project_name:$tag1 after_script: - docker logout $gitlab_server # Разлогиниваемся на гитлаб ранере - sudo docker rmi $gitlab_server/$gitlab_user_project/$project_name:$tag1 # Удаляем собранный образ с гитлаб ранера(чистим за собой) # when: manual # Данные действия производятся вручную check_postgres: stage: check_postgres tags: - shell-runner only: - master script: - $target_server kubectl -n terminal-soft exec -it stolon-pg-keeper-0 -- psql --host stolon-pg-proxy --port 5432 --username MY_USER postgres -V # when: delayed # если необходимо отсрочить выполнение на какое время # start_in: 1 minutes # отсрочка на 1 минуту |
[/codesyntax]
[root@minikub street-terminal]# git add .
[root@minikub street-terminal]# git commit -m "add ci/cd34"
[root@minikub street-terminal]# git push
будет происходить автосборка образа/загрузка его в гитлаб/и выкачивание с целевого сервера во втором этапе будет проходить проверка базы постгрес которая запущена в кубере.
как видим всё ок, оба этапа отработали автоматически
===========================================================
поправим нашу CI/CD для человеческого использования:
у нас есть база данных:
test
пользователь:
test
пароль
test
будем делать проверку именно по коннекту к базе данных
чтобы HELM нормально запускался с раннера поставим его туда
[root@gitlab~]# yum install epel-release
[root@gitlab~]# yum install snapd
[root@gitlab~]# systemctl enable --now snapd.socket
[root@gitlab~]# systemctl enable snapd
[root@gitlab~]# systemctl restart snapd
[root@gitlab~]# ln -s /var/lib/snapd/snap /snap
[root@gitlab~]# snap install helm --classic
[root@gitlab~]# echo 'export PATH="$PATH:/snap/bin" ' >> ~/.profile
echo 'export PATH="$PATH:/var/lib/snapd/snap/bin"' >> ~/.profile
[root@gitlab~]# export PATH="$PATH:/snap/bin"
Так же чтобы с ранера работал kubectrl надо его поставить:
[root@gitlab~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
[root@gitlab~]# yum install kubectl
Теперь надо добавить kubeconfig чтобы всё нормально запускалось, для этого создадим переменную в нашем gitlab
содержимое файла:
[root@minikub street-terminal]# cat /etc/kubernetes/admin.conf
пихаем в переменную: KUBECONFIG
ну и сразу добавим переменную для пароля базы данных:
kubernetes_database_password
ci/cd будет выглядеть следующим образом:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
stages: - create_image - check_postgres - deploy_service variables: gitlab_server: '192.168.1.190:4567' gitlab_user_project: 'kubernetes/street-terminal' project_name: 'service' #Имя проекта tag1: v1 replicas: 3 requests_cpu: 100m limits_cpu: 420m requests_memory: 300Mi limits_memory: 900Mi domen_ingres: terminal-soft.test.ru POSTGRES_HOST: 192.168.1.184 POSTGRES_DB: test POSTGRES_USER: test POSTGRES_PASSWORD: ${kubernetes_database_password} .autorizate_to_gitlab: &autorizate_to_gitlab | docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server create_image: # Первая стадия сборки образов stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе script: - docker build -f service/Dockerfile -t $gitlab_server/$gitlab_user_project/$project_name:$tag1 service/. - docker push $gitlab_server/$gitlab_user_project/$project_name:$tag1 after_script: - docker logout $gitlab_server # Разлогиниваемся на гитлаб ранере - docker rmi $gitlab_server/$gitlab_user_project/$project_name:$tag1 # Удаляем собранный образ с гитлаб ранера(чистим за собой) when: manual # Данные действия производятся вручную check_postgres: stage: check_postgres tags: - shell-runner only: - master script: - docker run --rm jbergknoff/postgresql-client postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:5432/$POSTGRES_DB when: manual deploy_service: stage: deploy_service tags: - shell-runner only: - master script: - helm upgrade --install --kubeconfig="$KUBECONFIG" -n terminal-soft terminal-soft service/deployment-helm/ --values service/deployment-helm/values.yaml --set-string replica_number=$replicas --set-string image_app.tag=$tag1 --set-string requests_cpu_app=$requests_cpu --set-string requests_memory_app=$requests_memory --set-string limits_cpu_app=$limits_cpu --set-string limits_memory_app=$limits_memory --set-string domain=$domen_ingres when: manual |
[/codesyntax]
но делать проверку базы в ci/cd не кошерно поэтому уберём этот этап.
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
stages: - create_image - deploy_service variables: gitlab_server: '192.168.1.190:4567' gitlab_user_project: 'kubernetes/street-terminal' project_name: 'service' #Имя проекта tag1: v3 replicas: 2 requests_cpu: 100m limits_cpu: 420m requests_memory: 300Mi limits_memory: 900Mi domen_ingres: terminal-soft.test.ru .autorizate_to_gitlab: &autorizate_to_gitlab | docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server create_image: # Первая стадия сборки образов stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе script: - docker build -f service/Dockerfile -t $gitlab_server/$gitlab_user_project/$project_name:$tag1 service/. - docker push $gitlab_server/$gitlab_user_project/$project_name:$tag1 after_script: - docker logout $gitlab_server # Разлогиниваемся на гитлаб ранере - docker rmi $gitlab_server/$gitlab_user_project/$project_name:$tag1 # Удаляем собранный образ с гитлаб ранера(чистим за собой) when: manual # Данные действия производятся вручную deploy_service: stage: deploy_service tags: - shell-runner only: - master script: - helm upgrade --install --kubeconfig="$KUBECONFIGa" -n terminal-soft terminal-soft service/deployment-helm/ --values service/deployment-helm/values.yaml --set-string replica_number=$replicas --set-string image_app.tag=$tag1 --set-string requests_cpu_app=$requests_cpu --set-string requests_memory_app=$requests_memory --set-string limits_cpu_app=$limits_cpu --set-string limits_memory_app=$limits_memory --set-string domain=$domen_ingres when: manual |
[/codesyntax]
меняя переменные в gitlab-ci и запуская деплой они будут меняться и для helm чарта.
===================================
сделаем так чтобы при коммите и указания TAG происходил деплой, т.е. начиналась сборка нового образа с новым тэгом, для этого поправим gitlab-ci, так же сразу добавим деплой redis чарта:
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
stages: - create_image - run_redis - deploy_service variables: gitlab_server: '192.168.1.190:4567' gitlab_user_project: 'kubernetes/street-terminal' project_name: 'service' #Имя проекта # tag1: v3 .autorizate_to_gitlab: &autorizate_to_gitlab | docker login -u ${login_kubernetes} -p ${kubernetes_password} $gitlab_server .git_tag_variable: &git_tag_variable | git fetch --tags export TAG=$(git describe --tags --abbrev=0) echo $TAG create_image: # Первая стадия сборки образов stage: create_image tags: - shell-runner # Указываем какой ранер будет производить все действия. only: - master # Указываем что действия производятся на ветке мастер before_script: - *autorizate_to_gitlab # Вызов якоря для авторизации в гитлабе - *git_tag_variable script: - docker build -f service/Dockerfile -t $gitlab_server/$gitlab_user_project/$project_name:$TAG service/. - docker push $gitlab_server/$gitlab_user_project/$project_name:$TAG after_script: - *git_tag_variable - docker logout $gitlab_server # Разлогиниваемся на гитлаб ранере - docker rmi $gitlab_server/$gitlab_user_project/$project_name:$TAG # Удаляем собранный образ с гитлаб ранера(чистим за собой) when: manual # Данные действия производятся вручную run_redis: stage: run_redis tags: - shell-runner only: - master script: - kubectl apply -f "$terminal_sof_redis_password_kubctl_secret" --kubeconfig="$KUBECONFIG" -n terminal-soft - helm upgrade --install redis-terminal-soft --kubeconfig="$KUBECONFIG" -n terminal-soft redis/ --values redis/values-gitlab-production.yaml when: manual deploy_service: stage: deploy_service tags: - shell-runner only: - master script: - helm upgrade --install --kubeconfig="$KUBECONFIG" -n terminal-soft terminal-soft service/deployment-helm/ --values service/deployment-helm/values.yaml --set-string image_app.tag=$TAG when: manual |
[/codesyntax]
Переменная terminal_sof_redis_password_kubctl_secret это переменная FILE в самом гитлабе, с полным содержимым файла:
redis/secret-password.yaml
чтобы тэг передался надо сделать следующее:
git add .
git tag -a v2 -m "commit new tag v2"
git commit -m "new image with tag"
git push
git push origin --tags
после этого переданный нами тэг будет взят и образ соберётся с тэгом v2
удалить tag локальный можно командой:
git tag -d v1
удалить tag в гитлабе можно командой
git push origin :refs/tags/v2
чтобы gitlab-runner запускал несколько задач параллельно надо в файле:
/etc/gitlab-runner/config.toml
добавить или изменить параметр:
concurrent = 2
после чего надо сделать:
gitlab-ctl restart