Differences

This shows you the differences between two versions of the page.

Link to this comparison view

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 [2020/07/07 13:47] – [Helm - Tiller] adminlinux_faq:kubernetes_using_single_node_as_master_and_worker [2021/03/28 08:31] – [Установка сервера метрик kubernetes] 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://apt.kubernetes.io/ kubernetes-xenial main' | sudo tee /etc/apt/sources.list.d/kubernetes.list
 +  curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add
 +  
 +  sudo apt-get update
 +  sudo apt-get install -y docker.io kubeadm kubelet
 +  
 +  # Setup Docker daemon.
 +  cat > /etc/docker/daemon.json <<EOF
 +  {
 +    "exec-opts": ["native.cgroupdriver=systemd"],
 +    "log-driver": "json-file",
 +    "log-opts": {
 +      "max-size": "100m"
 +    },
 +    "storage-driver": "overlay2"
 +  }
 +  EOF
 +  
 +  sudo mkdir -p /etc/systemd/system/docker.service.d
 +  
 +  # 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 /etc/systemd/system/kubelet.service.d/12-after-docker.conf
 +  [Unit]
 +  After=docker.service
 +  EOF
 +   
 +  # Kubernetes Cluster Init 
 +  sudo kubeadm init --pod-network-cidr=10.244.0.0/16
 +  
 +  mkdir -p $HOME/.kube
 +  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 +  sudo chown $(id -u):$(id -g) $HOME/.kube/config
  
 +  #https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md
 +  #kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml
 +  kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
 +  
 +  #kubectl -n kube-system patch deployment coredns --type=json -p='[{"op": "replace", "path": "/spec/replicas", "value":1}]'
 +  
 +  kubectl taint nodes --all node-role.kubernetes.io/master-
 +
 +====== Изменение редактора kubectl edit ======
 +  sudo awk -v line='export KUBE_EDITOR="/bin/nano"' 'FNR==NR && line==$0{f=1; exit} END{if (!f) print line >> FILENAME}' /etc/bash.bashrc
 +====== Автодополнение kubectl ======
 +  sudo awk -v line='source <(kubectl completion bash)' 'FNR==NR && line==$0{f=1; exit} END{if (!f) print line >> FILENAME}' /etc/bash.bashrc
 +===== /var/lib/kubelet/config.yaml =====
 +==== Failed to initialize CSINodeInfo ====
 +Если нода не переходит в состояние **Ready**, а при выполнении
 +  kubectl describe nodes
 +Видна ошибка:
 +  Failed to initialize CSINodeInfo: error updating CSINode annotation: timed out waiting for the condition; caused by: the server could not find the requested resource
 +то в файлике **/var/lib/kubelet/config.yaml** нужно добавить:
 +<code>featureGates:
 +  CSIMigration: false</code>
 +==== cgroupDriver ====
 +https://kubernetes.io/docs/setup/production-environment/container-runtimes/ \\
 +Также в файлике **/var/lib/kubelet/config.yaml** нужно включить такой же **cgroupDriver**, что и для **docker** (в файлике **/etc/docker/daemon.json**). По дефолту стоит **cgroupfs**. \\
 +И вообще - если в системе есть **systemd**, то нужно использовать **cgroupDriver**. Если будет включен **cgroupfs**, то ресурсами будут управлять два менеджера одновременно, что негативно сказыватся на стабильности. \\
 +То есть просто в конце файлика с нулевым отступом можно дописать: 
 +  cgroupDriver: systemd
 +
 +
 +
 +===== Kubelet Log level =====
 +  /etc/systemd/system/multi-user.target.wants/kubelet.service 
 +
 +  ExecStart=/usr/bin/kubelet --v=2
 +
 +  sudo systemctl daemon-reload
 +  sudo systemctl restart kubelet
 +====== CoreDNS ======
 +https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns \\
 +===== Изменяем дефолтный DNS-сервер для forwarding'a запросов =====
 +Конфигурация **CoreDNS** хранится в **ConfigMap coredns**
 +  kubectl edit cm coredns -n kube-system
 +Редактируем параметр **forward**. Вместо **/etc/resolv.conf** пописываем адрес нужного DNS-сервера
 +  forward . 192.168.1.100
 +
 +====== Kubernetes monitoring ======
 +Чтобы работали команды
 +<code>kubectl top nodes</code>и<code>kubectl top pods</code>
 +Нужно установить сервер метрик. 
 +===== Установка сервера метрик kubernetes =====
 +https://github.com/kubernetes-sigs/metrics-server
 +  kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml
 +В результате в неймспейсе **kube-system** появится **deployment** **metrics-server** и развернется **pod** **metrics-server-...**.\\
 +В нашем кластере отключен **ssl**, но он включен по-дефолту в **metrics-server**. Поэтому выполняем:
 +  kubectl edit deploy -n kube-system metrics-server
 +и в **spec.template.spec.containers.args** добавляем:
 +<code>  - --kubelet-insecure-tls</code>
 +Без этого параметра metrics-server не запустится, а в логах будет примерно такое:
 +<<code>[unable to fully scrape metrics from node kub-worker01: unable to fetch metrics from node kub-sbl-apps-dev-worker01: Get "https://192.168.44.11:10250/stats/summary?only_cpu_and_memory=true": x509: cannot validate certificate for 192.168.44.11 because it doesn't contain any IP SANs </code>
 +Все. Через некоторое время команды **kubectl top** начнут выдавать осмысленную информацию. \\
 +Если этого не происходит, а в логах 
 +  kubectl logs -n kube-system metrics-server...
 +Видно такое:
 +  reststorage.go:160] unable to fetch pod metrics for ...
 +То можно попробывать добавить в в **spec.template.spec.containers.args** такое:<code>- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP</code>
 +====== Helm ======
 +С третьей версией **Helm** ничего в кластер ставить не нужно. Для использования достаточно бинарника и сконфигурированного **context** для доступа к кластеру.
 +
 +====== Доступ к подам снаружи ======
 +Для доступа к сервисам, которые предоставляют поды, нужно установить и настроить:
 +  * [[https://metallb.universe.tf/|LoadBalancer MetalLB]] для получения сервисами IP-адресов локальной (или нелокальной) сети.
 +  * **Ingress Controller** для маршрутизации **HTTP/HTTPS** запросов.
 +  * **Cert Manager** для управления сертификатами (в том числе и **Let's Encrypt**).
 +===== LoadBalancer - MetalLB =====
 +https://habr.com/ru/company/southbridge/blog/443110/ \\
 +https://metallb.universe.tf/installation/ \\
 +  kubectl create ns metallb-system
 +  helm install --name metallb stable/metallb --namespace metallb-system
 +При установке с помощью **helm** конфигурация хранится в **ConfigMap** с именем **metallb-config**, который лежит в том же неймспейсе куда установлен **metallb** (в данном случае - **metallb-system**).
 +<code>apiVersion: v1
 +kind: ConfigMap
 +metadata:
 +  namespace: metallb-system
 +  name: metallb-config
 +data:
 +  config: |
 +    address-pools:
 +    - name: default
 +      protocol: layer2
 +      addresses:
 +      - 192.168.77.160-192.168.77.189
 +</code>
 +==== Апгрейдим metallb ====
 +  helm repo update
 +  helm upgrade metallb stable/metallb --namespace metallb-system
 +
 +===== Ingress-controller =====
 +https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/# \\
 +Либо тоже самое можно сделать с помощью helm-чарта:
 +  kubectl create ns ingress
 +  #helm install stable/nginx-ingress --name http-https --namespace ingress
 +  helm install stable/nginx-ingress --name http-https --namespace ingress --set controller.service.type=LoadBalancer,controller.service.externalTrafficPolicy=Local,controller.service.loadBalancerIP=192.168.77.160 \
 +  --set controller.addHeaders."X-XSS-Protection"="1\;mode=block" \
 +  --set controller.addHeaders."Content-Security-Policy"="default-src 'self'; \
 +  script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com 'nonce-HM305BL1jG4mB1xm' https://mc.yandex.ru; \
 +  img-src 'self' https://www.google-analytics.com https://*.yandex.ru; \
 +  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \
 +  font-src 'self' https://themes.googleusercontent.com;" \
 +  --set controller.addHeaders."Strict-Transport-Security"="max-age=31536000;includeSubdomains;preload" \
 +  --set controller.addHeaders."X-Frame-Options"="SAMEORIGIN" \
 +  --set controller.addHeaders."X-Content-Type-Options"="nosniff"
 +Ну или без драконовских запретов (заголовки **Content-Security-Policy** влияют на все ресурсы за этим **ingress-controller** и что-то может просто не заработать):
 +  helm upgrade http-https stable/nginx-ingress --set controller.service.type=LoadBalancer \
 +  --set controller.service.externalTrafficPolicy=Local \
 +  --set controller.service.loadBalancerIP=192.168.77.160 \
 +  --set controller.addHeaders."X-XSS-Protection"="1\;mode=block" \
 +  --set controller.addHeaders."Strict-Transport-Security"="max-age=31536000;includeSubdomains;preload" \
 +  --set controller.addHeaders."X-Frame-Options"="SAMEORIGIN" \
 +  --set controller.addHeaders."X-Content-Type-Options"="nosniff"
 +
 +В результате - в неймспейсе **ingress** появится сервис **http-https-nginx-ingress-controller**, у которого будет тип **LoadBalancer** и который получит указанный IP-адрес в локальной сети из диапазона, сконфигурированного для **metallb**. \\
 +Теперь можно создавать **ingress**'ы, которые будут смотреть на сервисы внутри кластера и предоставлять к ним доступ. Пользователи будут посылать запросы на **ingress-controller**, а он, в свою очередь, - пересылать их на **ingress**'ы.
 +
 +===== Cert manager =====
 +https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/
 +https://docs.cert-manager.io/en/latest/getting-started/install/kubernetes.html#installing-with-helm \\
 +Устанавливаем:
 +<code># Install the CustomResourceDefinition resources separately
 +kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml
 +
 +# Create the namespace for cert-manager
 +kubectl create namespace cert-manager
 +
 +# Add the Jetstack Helm repository
 +helm repo add jetstack https://charts.jetstack.io
 +
 +# Update your local Helm chart repository cache
 +helm repo update
 +
 +# Install the cert-manager Helm chart
 +helm install \
 +  --name cert-manager \
 +  --namespace cert-manager \
 +  --version v0.11.0 \
 +  jetstack/cert-manager
 +</code>
 +https://docs.cert-manager.io/en/latest/tasks/issuers/index.html \\
 +Создаем издателя **Let's Encrypt** (ACME Issuer):
 +<code>apiVersion: cert-manager.io/v1alpha2
 +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, and issues related to your account.
 +    email: mike@autosys.tk
 +    server: https://acme-staging-v02.api.letsencrypt.org/directory
 +    privateKeySecretRef:
 +      # Secret resource used to store the account's private key.
 +      name: cert-issuer-account-key
 +    # Add a single challenge solver, HTTP01 using nginx
 +    solvers:
 +    - http01:
 +        ingress:
 +          class: nginx
 +</code>
 +Смотрим на его состояние:
 +  kubectl describe clusterissuer letsencrypt
 +Должно быть так:
 +<code>Status:
 +  ...
 +  Conditions:
 +    ...
 +    Status:                True
 +    Type:                  Ready
 +</code>
 +
 +==== Апгрейдим cert-manager ====
 +  helm repo update
 +  helm upgrade --namespace cert-manager cert-manager jetstack/cert-manager
 +===== Ingress, Cert-Manager и сертификаты Let's Encrypt =====
 +<del>https://docs.cert-manager.io/en/latest/getting-started/install/kubernetes.html</del>\\
 +<del>https://docs.bitnami.com/kubernetes/how-to/secure-kubernetes-services-with-ingress-tls-letsencrypt/#step-3-configure-tls-with-let-s-encrypt-certificates-and-cert-manager</del>\\
 +https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/#\\
 +Итак, у нас установлен **MetalLB**, **Ingress Controller** и **CertManager**. \\
 +В результате, сервис **Ingress Controller** должен получить адрес в локальной (или нелокальной сети) из диапазона, прописанного в конфигурации **MetalLB**:
 +<code># kubectl get svc -n ingress
 +NAME                                       TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                      AGE
 +http-https-nginx-ingress-controller        LoadBalancer   10.100.109.113   192.168.77.160   80:31833/TCP,443:32690/TCP   5h1m
 +http-https-nginx-ingress-default-backend   ClusterIP      10.107.152.17    <none>           80/TCP                       5h1m
 +</code>
 +Для примера буду делат доступ к **AWX**, который установлен в моем кластере **Kubernetes**. \\
 +В неймспейсе, куда развернут **AWX** (в моем случае это **awx**) делаем **ingress**, который будет направлять запросы в соотвествующий сервис, где работает web-морда **AWX**:
 +<code>apiVersion: extensions/v1beta1
 +kind: Ingress
 +metadata:
 +  annotations:
 +    kubernetes.io/ingress.class: nginx
 +  name: awx-web
 +  namespace: awx
 +spec:
 +  rules:
 +  - host: awx.autosys.tk
 +    http:
 +      paths:
 +      - backend:
 +          serviceName: awx-web-svc
 +          servicePort: 80
 +        path: /
 +  tls:
 +  - hosts:
 +    - awx.autosys.tk
 +    secretName: awx-autosys-tk-tls
 +</code>
 +В результате, HTTP-запросы на **IP**-адрес **Ingress**-контроллера будут перенаправлены на сервис web-морды AWX. \\
 +\\
 +Теперь нужно сконфигурировать **ACME Issuer** - это сущность, которая будет запрашивать сертификаты по протоколу **ACME** у серверов **Let's Encrypt**:
 +<code>apiVersion: cert-manager.io/v1alpha2
 +kind: ClusterIssuer
 +metadata:
 +  name: letsencrypt
 +  namespace: cert-manager
 +spec:
 +  acme:
 +    # You must replace this email address with your own.
 +    # Let's Encrypt will use this to contact you about expiring
 +    # certificates, and issues related to your account.
 +    email: mike@autosys.tk
 +    server: https://acme-v02.api.letsencrypt.org/directory
 +    privateKeySecretRef:
 +      # Secret resource used to store the account's private key.
 +      name: letsencrypt-cert-issuer-account-key
 +    # Add a single challenge solver, HTTP01 using nginx
 +    solvers:
 +    - http01:
 +        ingress:
 +          class: nginx
 +</code>
 +После того, как создан **Issuer** (в данном случае - **ClusterIssuer** с именем **letsencrypt**) можно добавить в манифест ингресса информацию о нем. Редактируем ресурс **Ingress** и приводим секцию **annotations** к виду:
 +<code>kind: Ingress
 +metadata:
 +  annotations:
 +    cert-manager.io/cluster-issuer: letsencrypt
 +    kubernetes.io/ingress.class: nginx
 +  name: awx-web
 +  namespace: awx
 +</code>
 +Все. Теперь можно увидеть, что появился сертификат: 
 +  kubectl get certificate -A
 +Если сертификат долго не готов, то нужно смотреть логи пода **cert-manager**:
 +  kubectl get po -n cert-manager
 +  kubectl logs cert-manager-55c44f98f-g9vrb -n cert-manager -f
 +У меня, например, возникали проблемы с резолвингом доменнного имени, для которого получаем сертификат в поде **cert-manager**, хотя из интернета имя резолвилось корректно и маршрутизация трафика работала нормально, но **cert-manager**, перед тем как запросить проверку у ACME-сервера, пытается сам убедиться, что проверка проходит, но так как имя в локалке не резолвилось корректно, то проверка не прошла.
 +====== Rancher ======
 +**Rancher** - это web-консоль для управления кластеами **kubernetes**. Устанавливать осторожно, поскольку она ставит с кластер много всякого и полностью удалить ее может быть проблематично. \\
 +https://rancher.com/docs/rancher/v2.x/en/installation/ha/helm-rancher/ \\
 +Если у нас уже установлены **MetalLB**, **Ingress Controller** и **Cert-Manager**, то можно ставить так:
 +  helm install rancher-latest/rancher --name rancher --namespace cattle-system --set hostname=rancher.autosys.tk --set ingress.tls.source=letsEncrypt --set letsEncrypt.email=mike@autosys.tk
 +В моем случае, **helm** ругнулся:
 +  Error: validation failed: unable to recognize "": no matches for kind "Issuer" in version "certmanager.k8s.io/v1alpha1"
 +После этого я скачал чарт:
 +  helm fetch rancher-latest/rancher
 +Распаковал его:
 +  tar -xvf ./rancher-2.3.0.tgz
 +И просто удалил файл, который создает **Issuer**, так как у меня в кластере уже есть **ClusterIssuer**.
 +  rm ./rancher/templates/issuer-letsEncrypt.yaml
 +Затем запаковал чарт обратно и установил его:
 +  mv ./rancher-2.3.0.tgz ./rancher-2.3.0.tgz.orig
 +  helm package rancher
 +  helm install ./rancher-2.3.0.tgz --name rancher --namespace cattle-system --set hostname=rancher.autosys.tk --set ingress.tls.source=letsEncrypt --set letsEncrypt.email=mike@autosys.tk
 +В итоге **rancher** установился нормально! \\
 +Затем я отредактировал **ingress**, заменив issuer:
 +  certmanager.k8s.io/issuer: rancher
 +на уже существующий в кластере:
 +    cert-manager.io/cluster-issuer: letsencrypt
 +    kubernetes.io/ingress.class: nginx
 +Залогиниться в первый раз можно с помощью логина/пароля admin/admin.
 +====== awx on single nodes kubernetes ======
 +Для базы данных я использую внешний сервер **postgres**, то есть **StorageClass** и **PersistentVolume** для базы мне не нужны. \\
 +После запуска playbook'a будет создан **StatefullSet**. Однако, если нода достаточно слабая, то под не запустится, потому что не хватит ресурсов. Нужно удалить все объекты **resources** с резервированием и лимитами ресурсов:
 +  kubectl edit sts awx -n awx
 +Также, нода будет иметь **taint**:
 +  taints:
 +  - effect: NoSchedule
 +    key: node.kubernetes.io/disk-pressure
 +    timeAdded: "2019-10-01T12:28:30Z"
 +Чтобы под запустился нужно добавить в конфигурацию **StatefullSet**:
 +  kubectl edit sts awx -n awx
 +соответствующий **toleration** (в **spec:template:spec:**. Например - перед **volumes**):
 +<code>      tolerations:
 +      - effect: NoSchedule
 +        operator: Exists
 +</code>
  • linux_faq/kubernetes_using_single_node_as_master_and_worker.txt
  • Last modified: 2024/04/22 12:38
  • by admin