User Tools

Site Tools


Sidebar

Me
Здравствуйте!

Меня зовут Михаил Усик!
Я системный администратор
и наполняю эту wiki,
решая разнообразные IT-задачки.

Я всегда готов помочь Вам
наладить IT-инфраструктуру
за скромное вознаграждение!

mike@autosys.tk
+7 (977) 887-96-23

linux_faq:kubernetes_using_single_node_as_master_and_worker

Single node Kubernetes setup - Ubuntu 18.04

sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common
sudo apt-add-repository universe
sudo apt-get -y purge cloud-init && sudo rm -rf /etc/cloud

sudo apt-get install -y docker.io

# 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

# Restart docker.
sudo systemctl daemon-reload
sudo systemctl enable docker
sudo systemctl restart docker

sudo usermod -a -G docker $USER

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 -y install kubeadm kubelet=1.15.4-00
sudo systemctl enable kubelet.service
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version stable-1.15

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

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

#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-

CoreDNS

Изменяем дефолтный DNS-сервер для forwarding'a запросов

Конфигурация CoreDNS хранится в ConfigMap coredns

kubectl edit cm coredns -n kube-system

Редактируем параметр forward. Вместо /etc/resolv.conf пописываем адрес нужного DNS-сервера

forward . 192.168.1.100

Helm - Tiller

#sudo snap install helm --classic

curl -s --list-only https://github.com/helm/helm/releases  | grep http | grep helm- | grep amd64 | grep Linux
wget https://get.helm.sh/helm-v2.14.2-linux-amd64.tar.gz
tar -xvf ./helm-v2.14.2-linux-amd64.tar.gz 
cp ./linux-amd64/helm /usr/bin/
cp .linux-amd64/tiller /usr/bin/

kubectl create serviceaccount tiller --namespace kube-system

cat <<EOF | kubectl apply -f -
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: ""
EOF
#https://github.com/helm/helm/issues/6374
helm init --service-account tiller --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | sed 's@  replicas: 1@  replicas: 1\n  selector: {"matchLabels": {"app": "helm", "name": "tiller"}}@' | kubectl apply -f -

Доступ к подам снаружи

Для доступа к сервисам, которые предоставляют поды, нужно установить и настроить:

  • 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).

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

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

В результате - в неймспейсе 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
Устанавливаем:

# 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

https://docs.cert-manager.io/en/latest/tasks/issuers/index.html
Создаем издателя Let's Encrypt (ACME Issuer):

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

Смотрим на его состояние:

kubectl describe clusterissuer letsencrypt

Должно быть так:

Status:
  ...
  Conditions:
    ...
    Status:                True
    Type:                  Ready

Ingress, Cert-Manager и сертификаты Let's Encrypt

https://docs.cert-manager.io/en/latest/getting-started/install/kubernetes.html
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
https://docs.cert-manager.io/en/latest/tutorials/acme/quick-start/#
Итак, у нас установлен MetalLB, Ingress Controller и CertManager.
В результате, сервис Ingress Controller должен получить адрес в локальной (или нелокальной сети) из диапазона, прописанного в конфигурации MetalLB:

# 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

Для примера буду делат доступ к AWX, который установлен в моем кластере Kubernetes.
В неймспейсе, куда развернут AWX (в моем случае это awx) делаем ingress, который будет направлять запросы в соотвествующий сервис, где работает web-морда AWX:

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

В результате, HTTP-запросы на IP-адрес Ingress-контроллера будут перенаправлены на сервис web-морды AWX.

Теперь нужно сконфигурировать ACME Issuer - это сущность, которая будет запрашивать сертификаты по протоколу ACME у серверов Let's Encrypt:

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

После того, как создан Issuer (в данном случае - ClusterIssuer с именем letsencrypt) можно добавить в манифест ингресса информацию о нем. Редактируем ресурс Ingress и приводим секцию annotations к виду:

kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
    kubernetes.io/ingress.class: nginx
  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

У меня, например, возникали проблемы с резолвингом доменнного имени, для которого получаем сертификат в поде 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

соответствующий tolerationspec:template:spec:. Например - перед volumes):

      tolerations:
      - effect: NoSchedule
        operator: Exists

Discussion

Enter your comment. Wiki syntax is allowed:
X M E B T
 
linux_faq/kubernetes_using_single_node_as_master_and_worker.txt · Last modified: 2019/11/21 11:08 by admin