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   |