Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revisionBoth sides next revision | ||
linux_faq:kubernetes_using_single_node_as_master_and_worker [2019/10/15 13:56] – [Ingress, Cert-Manager и сертификаты Let's Encrypt] mike | linux_faq:kubernetes_using_single_node_as_master_and_worker [2022/03/11 07:59] – [Мониторинг nginx ingess] admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Single node Kubernetes setup - Ubuntu 18.04 ====== | ||
+ | sudo apt-get -y purge cloud-init && sudo rm -rf /etc/cloud | ||
+ | sudo apt-get install -y apt-transport-https \ | ||
+ | ca-certificates curl \ | ||
+ | gnupg-agent \ | ||
+ | software-properties-common | ||
+ | sudo apt-add-repository universe | ||
+ | | ||
+ | echo 'deb http:// | ||
+ | curl -s https:// | ||
+ | | ||
+ | sudo apt-get update | ||
+ | sudo apt-get install -y docker.io kubeadm kubelet | ||
+ | | ||
+ | # Setup Docker daemon. | ||
+ | cat > / | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | }, | ||
+ | " | ||
+ | } | ||
+ | EOF | ||
+ | | ||
+ | sudo mkdir -p / | ||
+ | | ||
+ | # Enable services and restart docker. | ||
+ | sudo systemctl daemon-reload | ||
+ | sudo systemctl enable docker | ||
+ | sudo systemctl restart docker | ||
+ | sudo systemctl enable kubelet.service | ||
+ | | ||
+ | sudo usermod -a -G docker $USER | ||
+ | | ||
+ | # To ensure that kubelet starts only after docker: | ||
+ | cat << EOF | sudo tee / | ||
+ | [Unit] | ||
+ | After=docker.service | ||
+ | EOF | ||
+ | |||
+ | # Kubernetes Cluster Init | ||
+ | sudo kubeadm init --pod-network-cidr=10.244.0.0/ | ||
+ | | ||
+ | mkdir -p $HOME/.kube | ||
+ | sudo cp -i / | ||
+ | sudo chown $(id -u):$(id -g) $HOME/ | ||
+ | # | ||
+ | #kubectl apply -f https:// | ||
+ | kubectl apply -f https:// | ||
+ | | ||
+ | #kubectl -n kube-system patch deployment coredns --type=json -p=' | ||
+ | | ||
+ | kubectl taint nodes --all node-role.kubernetes.io/ | ||
+ | |||
+ | ====== Настройка манифестов компонентво кубера на слабых маишинках ====== | ||
+ | Я запускаю свой кластер в контейнере на сервере Proxmox, | ||
+ | Чтобы немного облегчить им жизнь и сделать поведение компонентов k8s более предсказуемым нужно увеличить таймауты **livenessProbe**, | ||
+ | Для этого - редактируем манифесты в директории **/ | ||
+ | < | ||
+ | livenessProbe: | ||
+ | failureThreshold: | ||
+ | initialDelaySeconds: | ||
+ | periodSeconds: | ||
+ | timeoutSeconds: | ||
+ | readinessProbe: | ||
+ | failureThreshold: | ||
+ | periodSeconds: | ||
+ | timeoutSeconds: | ||
+ | startupProbe: | ||
+ | failureThreshold: | ||
+ | initialDelaySeconds: | ||
+ | periodSeconds: | ||
+ | timeoutSeconds: | ||
+ | </ | ||
+ | И перезапускаем **kubelet**: | ||
+ | sudo service kubelet restart | ||
+ | ====== Изменение редактора kubectl edit ====== | ||
+ | sudo awk -v line=' | ||
+ | ====== Автодополнение kubectl ====== | ||
+ | sudo awk -v line=' | ||
+ | ===== / | ||
+ | ==== Failed to initialize CSINodeInfo ==== | ||
+ | Если нода не переходит в состояние **Ready**, а при выполнении | ||
+ | kubectl describe nodes | ||
+ | Видна ошибка: | ||
+ | Failed to initialize CSINodeInfo: | ||
+ | то в файлике **/ | ||
+ | < | ||
+ | CSIMigration: | ||
+ | ==== cgroupDriver ==== | ||
+ | https:// | ||
+ | Также в файлике **/ | ||
+ | И вообще - если в системе есть **systemd**, | ||
+ | То есть просто в конце файлика с нулевым отступом можно дописать: | ||
+ | cgroupDriver: | ||
+ | |||
+ | |||
+ | |||
+ | ===== Kubelet Log level ===== | ||
+ | / | ||
+ | |||
+ | ExecStart=/ | ||
+ | |||
+ | sudo systemctl daemon-reload | ||
+ | sudo systemctl restart kubelet | ||
+ | ====== CoreDNS ====== | ||
+ | https:// | ||
+ | ===== Изменяем дефолтный DNS-сервер для forwarding' | ||
+ | Конфигурация **CoreDNS** хранится в **ConfigMap coredns** | ||
+ | kubectl edit cm coredns -n kube-system | ||
+ | Редактируем параметр **forward**. Вместо **/ | ||
+ | forward . 192.168.1.100 | ||
+ | |||
+ | ====== Kubernetes monitoring ====== | ||
+ | Чтобы работали команды | ||
+ | < | ||
+ | Нужно установить сервер метрик. | ||
+ | ===== Установка сервера метрик kubernetes ===== | ||
+ | https:// | ||
+ | kubectl apply -f https:// | ||
+ | В результате в неймспейсе **kube-system** появится **deployment** **metrics-server** и развернется **pod** **metrics-server-...**.\\ | ||
+ | В нашем кластере отключен **ssl**, но он включен по-дефолту в **metrics-server**. Поэтому выполняем: | ||
+ | kubectl edit deploy -n kube-system metrics-server | ||
+ | и в **spec.template.spec.containers.args** добавляем: | ||
+ | < | ||
+ | Без этого параметра metrics-server не запустится, | ||
+ | < | ||
+ | Все. Через некоторое время команды **kubectl top** начнут выдавать осмысленную информацию. \\ | ||
+ | Если этого не происходит, | ||
+ | kubectl logs -n kube-system metrics-server... | ||
+ | Видно такое: | ||
+ | reststorage.go: | ||
+ | То можно попробывать добавить в в **spec.template.spec.containers.args** такое:< | ||
+ | ====== Helm ====== | ||
+ | С третьей версией **Helm** ничего в кластер ставить не нужно. Для использования достаточно бинарника и сконфигурированного **context** для доступа к кластеру. | ||
+ | |||
+ | ====== Обновление kubernetes ====== | ||
+ | смотрим какие версии **kubeadm** нам доступны | ||
+ | sudo apt-get update | ||
+ | apt-cache madison kubeadm | ||
+ | Разрешаем обновление **kubernetes-cni** и **kubeadm**: | ||
+ | sudo apt-mark unhold kubernetes-cni kubeadm | ||
+ | Ставим нужную версию **kubeadm**: | ||
+ | sudo apt-get install kubeadm=1.20.9-00 | ||
+ | Проверяем возможность апгрейда: | ||
+ | sudo kubeadm upgrade plan | ||
+ | Если у нас хост с **containerd** (без **docker**), | ||
+ | sudo apt-get install docker.io | ||
+ | Обновляем: | ||
+ | sudo kubeadm upgrade apply v1.20.9 | ||
+ | Разрешаем обновление **kubelet** и **kubectl** | ||
+ | sudo apt-mark unhold kubelet kubectl | ||
+ | И обновляем их до нужной версии: | ||
+ | sudo apt-get install -y kubelet=1.20.9-00 kubectl=1.20.9-00 | ||
+ | Морозим обратно версии пакетов: | ||
+ | sudo apt-mark hold kube* | ||
+ | Апгрейдим всю систему: | ||
+ | sudo apt-get update && sudo apt-get upgrade | ||
+ | ====== Доступ к подам снаружи ====== | ||
+ | Для доступа к сервисам, | ||
+ | * [[https:// | ||
+ | * **Ingress Controller** для маршрутизации **HTTP/ | ||
+ | * **Cert Manager** для управления сертификатами (в том числе и **Let' | ||
+ | ===== LoadBalancer - MetalLB ===== | ||
+ | https:// | ||
+ | https:// | ||
+ | helm repo add metallb https:// | ||
+ | helm repo update | ||
+ | kubectl create ns metallb-system | ||
+ | helm upgrade --install -n metallb-system metallb metallb/ | ||
+ | --set configInline.address-pools[0].name=" | ||
+ | --set configInline.address-pools[0].protocol=" | ||
+ | --set configInline.address-pools[0].addresses[0]=" | ||
+ | ==== Апгрейдим metallb ==== | ||
+ | helm repo update | ||
+ | helm upgrade -n metallb-system metallb metallb/ | ||
+ | ===== Ingress-controller ===== | ||
+ | https:// | ||
+ | Либо тоже самое можно сделать с помощью helm-чарта: | ||
+ | kubectl create ns ingress | ||
+ | helm repo add ingress-nginx https:// | ||
+ | helm repo update | ||
+ | |||
+ | #helm install stable/ | ||
+ | helm upgrade --install nginx -n ingress ingress-nginx/ | ||
+ | --set controller.service.type=LoadBalancer, | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | script-src ' | ||
+ | img-src ' | ||
+ | style-src ' | ||
+ | font-src ' | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | Ну или без драконовских запретов (заголовки **Content-Security-Policy** влияют на все ресурсы за этим **ingress-controller** и что-то может просто не заработать): | ||
+ | helm upgrade --install nginx -n ingress ingress-nginx/ | ||
+ | --set controller.service.type=LoadBalancer \ | ||
+ | --set controller.service.externalTrafficPolicy=Cluster \ | ||
+ | --set controller.service.loadBalancerIP=192.168.77.160 \ | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | --set controller.addHeaders." | ||
+ | |||
+ | В результате - в неймспейсе **ingress** появится сервис **nginx-ingress-nginx-controller**, | ||
+ | Теперь можно создавать **ingress**' | ||
+ | ==== Мониторинг nginx ingess ==== | ||
+ | В кластере нужно развернуть **CRD** и оператор **prometheus**: | ||
+ | \\ | ||
+ | **nginx-ingress-monitoring-values.yaml** | ||
+ | < | ||
+ | controller: | ||
+ | metrics: | ||
+ | port: 10254 | ||
+ | enabled: true | ||
+ | service: | ||
+ | annotations: | ||
+ | prometheus.io/ | ||
+ | prometheus.io/ | ||
+ | servicePort: | ||
+ | type: ClusterIP | ||
+ | |||
+ | serviceMonitor: | ||
+ | enabled: true | ||
+ | additionalLabels: | ||
+ | jobLabel: nginx-ingress | ||
+ | namespace: " | ||
+ | namespaceSelector: | ||
+ | matchNames: | ||
+ | - ingress | ||
+ | scrapeInterval: | ||
+ | |||
+ | prometheusRule: | ||
+ | enabled: true | ||
+ | namespace: ingress | ||
+ | rules: | ||
+ | - alert: NGINXConfigFailed | ||
+ | expr: count(nginx_ingress_controller_config_last_reload_successful == 0) > 0 | ||
+ | for: 1s | ||
+ | labels: | ||
+ | severity: critical | ||
+ | annotations: | ||
+ | description: | ||
+ | summary: uninstall the latest ingress changes to allow config reloads to resume | ||
+ | - alert: NGINXCertificateExpiry | ||
+ | expr: (avg(nginx_ingress_controller_ssl_expire_time_seconds) by (host) - time()) < 604800 | ||
+ | for: 1s | ||
+ | labels: | ||
+ | severity: critical | ||
+ | annotations: | ||
+ | description: | ||
+ | summary: renew expiring certificates to avoid downtime | ||
+ | - alert: NGINXTooMany500s | ||
+ | expr: 100 * ( sum( nginx_ingress_controller_requests{status=~" | ||
+ | for: 1m | ||
+ | labels: | ||
+ | severity: warning | ||
+ | annotations: | ||
+ | description: | ||
+ | summary: More than 5% of all requests returned 5XX, this requires your attention | ||
+ | - alert: NGINXTooMany400s | ||
+ | expr: 100 * ( sum( nginx_ingress_controller_requests{status=~" | ||
+ | for: 1m | ||
+ | labels: | ||
+ | severity: warning | ||
+ | annotations: | ||
+ | description: | ||
+ | summary: More than 5% of all requests returned 4XX, this requires your attention | ||
+ | </ | ||
+ | |||
+ | helm upgrade --reuse-values -n ingress nginx ingress-nginx/ | ||
+ | ===== Cert manager ===== | ||
+ | https:// | ||
+ | https:// | ||
+ | Устанавливаем: | ||
+ | < | ||
+ | helm repo add jetstack https:// | ||
+ | helm repo update | ||
+ | |||
+ | helm upgrade --install \ | ||
+ | cert-manager jetstack/ | ||
+ | --namespace cert-manager \ | ||
+ | --create-namespace \ | ||
+ | --version v1.5.4 \ | ||
+ | --set installCRDs=true | ||
+ | </ | ||
+ | https:// | ||
+ | Создаем издателя **Let' | ||
+ | < | ||
+ | apiVersion: cert-manager.io/ | ||
+ | kind: ClusterIssuer | ||
+ | metadata: | ||
+ | name: letsencrypt | ||
+ | spec: | ||
+ | acme: | ||
+ | # You must replace this email address with your own. | ||
+ | # Let's Encrypt will use this to contact you about expiring | ||
+ | # certificates, | ||
+ | email: mike@autosys.tk | ||
+ | server: https:// | ||
+ | privateKeySecretRef: | ||
+ | # Secret resource used to store the account' | ||
+ | name: cert-issuer-account-key | ||
+ | # Add a single challenge solver, HTTP01 using nginx | ||
+ | solvers: | ||
+ | - http01: | ||
+ | ingress: | ||
+ | class: nginx | ||
+ | EOF | ||
+ | </ | ||
+ | Смотрим на его состояние: | ||
+ | kubectl describe clusterissuer letsencrypt | ||
+ | Должно быть так: | ||
+ | < | ||
+ | ... | ||
+ | Conditions: | ||
+ | ... | ||
+ | Status: | ||
+ | Type: Ready | ||
+ | </ | ||
+ | |||
+ | ==== Апгрейдим cert-manager ==== | ||
+ | helm repo update | ||
+ | helm upgrade --namespace cert-manager cert-manager jetstack/ | ||
+ | ===== Ingress, Cert-Manager и сертификаты Let's Encrypt ===== | ||
+ | < | ||
+ | < | ||
+ | https:// | ||
+ | https:// | ||
+ | Итак, у нас установлен **MetalLB**, | ||
+ | В результате, | ||
+ | < | ||
+ | NAME | ||
+ | http-https-nginx-ingress-controller | ||
+ | http-https-nginx-ingress-default-backend | ||
+ | </ | ||
+ | Для примера буду делат доступ к **AWX**, который установлен в моем кластере **Kubernetes**. \\ | ||
+ | В неймспейсе, | ||
+ | < | ||
+ | kind: Ingress | ||
+ | metadata: | ||
+ | annotations: | ||
+ | kubernetes.io/ | ||
+ | name: awx-web | ||
+ | namespace: awx | ||
+ | spec: | ||
+ | rules: | ||
+ | - host: awx.autosys.tk | ||
+ | http: | ||
+ | paths: | ||
+ | - backend: | ||
+ | serviceName: | ||
+ | servicePort: | ||
+ | path: / | ||
+ | tls: | ||
+ | - hosts: | ||
+ | - awx.autosys.tk | ||
+ | secretName: awx-autosys-tk-tls | ||
+ | </ | ||
+ | В результате, | ||
+ | \\ | ||
+ | Теперь нужно сконфигурировать **ACME Issuer** - это сущность, | ||
+ | https:// | ||
+ | < | ||
+ | kubectl apply -f - << EOF | ||
+ | apiVersion: cert-manager.io/ | ||
+ | kind: ClusterIssuer | ||
+ | metadata: | ||
+ | name: letsencrypt | ||
+ | spec: | ||
+ | acme: | ||
+ | # You must replace this email address with your own. | ||
+ | # Let's Encrypt will use this to contact you about expiring | ||
+ | # certificates, | ||
+ | email: m.usik@sdventures.com | ||
+ | server: https:// | ||
+ | privateKeySecretRef: | ||
+ | # Secret resource that will be used to store the account' | ||
+ | name: letsencrypt-issuer-account-key | ||
+ | # Add a single challenge solver, HTTP01 using nginx | ||
+ | solvers: | ||
+ | - http01: | ||
+ | ingress: | ||
+ | class: nginx | ||
+ | EOF | ||
+ | </ | ||
+ | После того, как создан **Issuer** (в данном случае - **ClusterIssuer** с именем **letsencrypt**) можно добавить в манифест ингресса информацию о нем. Редактируем ресурс **Ingress** и приводим секцию **annotations** к виду: | ||
+ | < | ||
+ | metadata: | ||
+ | annotations: | ||
+ | cert-manager.io/ | ||
+ | kubernetes.io/ | ||
+ | name: awx-web | ||
+ | namespace: awx | ||
+ | </ | ||
+ | Все. Теперь можно увидеть, | ||
+ | kubectl get certificate -A | ||
+ | Если сертификат долго не готов, то нужно смотреть логи пода **cert-manager**: | ||
+ | kubectl get po -n cert-manager | ||
+ | kubectl logs cert-manager-55c44f98f-g9vrb -n cert-manager -f | ||
+ | У меня, например, | ||
+ | ====== Rancher ====== | ||
+ | **Rancher** - это web-консоль для управления кластеами **kubernetes**. Устанавливать осторожно, | ||
+ | https:// | ||
+ | Если у нас уже установлены **MetalLB**, | ||
+ | helm install rancher-latest/ | ||
+ | В моем случае, | ||
+ | Error: validation failed: unable to recognize "": | ||
+ | После этого я скачал чарт: | ||
+ | helm fetch rancher-latest/ | ||
+ | Распаковал его: | ||
+ | tar -xvf ./ | ||
+ | И просто удалил файл, который создает **Issuer**, так как у меня в кластере уже есть **ClusterIssuer**. | ||
+ | rm ./ | ||
+ | Затем запаковал чарт обратно и установил его: | ||
+ | mv ./ | ||
+ | helm package rancher | ||
+ | helm install ./ | ||
+ | В итоге **rancher** установился нормально! \\ | ||
+ | Затем я отредактировал **ingress**, | ||
+ | certmanager.k8s.io/ | ||
+ | на уже существующий в кластере: | ||
+ | cert-manager.io/ | ||
+ | kubernetes.io/ | ||
+ | Залогиниться в первый раз можно с помощью логина/ | ||
+ | ====== awx on single nodes kubernetes ====== | ||
+ | Для базы данных я использую внешний сервер **postgres**, | ||
+ | После запуска playbook' | ||
+ | kubectl edit sts awx -n awx | ||
+ | Также, нода будет иметь **taint**: | ||
+ | taints: | ||
+ | - effect: NoSchedule | ||
+ | key: node.kubernetes.io/ | ||
+ | timeAdded: " | ||
+ | Чтобы под запустился нужно добавить в конфигурацию **StatefullSet**: | ||
+ | kubectl edit sts awx -n awx | ||
+ | соответствующий **toleration** (в **spec: | ||
+ | < | ||
+ | - effect: NoSchedule | ||
+ | operator: Exists | ||
+ | </ |