Установка Kubernetes 1.8 Bare Metal

в 7:43, , рубрики: devops, docker, k8s, kubernetes, orchestration, Серверное администрирование, системное администрирование

Установка Kubernetes 1.8 Bare Metal - 1
В интернете написано довольно много статей по установке Kubernetes, но большинство из них базируются на kubeadm и minikube. Это, конечно, здорово, что можно легко и за пару кликов развернуть кластер, но хотелось бы иметь больше понимания из чего состоит Kubernetes. Попробую исправить эту ситуацию данным руководством.

Цель: кластер Kubernetes с авторизацией по ключам SSL и токенам.
Дано: 2 виртуалки на Centos 7 (при желании, руководство легко адаптируется под другие дистрибутивы)

c00test01 — master/minion — 10.10.12.101
c00test02 — minion — 10.10.12.102
Примечание: установка производилась с отключенными firewalld и selinux.

1. Установка Etcd

$ yum install etcd-3.1.9

Правим конфиг

/etc/etcd/etcd.conf

ETCD_NAME=c00test01
ETCD_DATA_DIR=/var/lib/etcd

#[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://10.10.12.101:2380
ETCD_INITIAL_CLUSTER=c00test01=https://10.10.12.101:2380
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN=etcd-k8-cluster

ETCD_LISTEN_PEER_URLS=https://0.0.0.0:2380

ETCD_ADVERTISE_CLIENT_URLS=https://10.10.12.101:2379
ETCD_LISTEN_CLIENT_URLS=https://0.0.0.0:2379

#[proxy]
ETCD_PROXY="off"

#[security]
ETCD_CA_FILE=/etc/etcd/certs/ca.crt
ETCD_TRUSTED_CA_FILE=/etc/etcd/certs/ca.crt
ETCD_CERT_FILE=/etc/etcd/certs/server.crt
ETCD_KEY_FILE=/etc/etcd/certs/server.key
ETCD_CLIENT_CERT_AUTH=true
ETCD_PEER_CA_FILE=/etc/etcd/certs/ca.crt
ETCD_PEER_TRUSTED_CA_FILE=/etc/etcd/certs/ca.crt
ETCD_PEER_CERT_FILE=/etc/etcd/certs/peer.crt
ETCD_PEER_KEY_FILE=/etc/etcd/certs/peer.key
ETCD_PEER_CLIENT_CERT_AUTH=true

Правим init-скрипт

/usr/lib/systemd/system/etcd.service

[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
EnvironmentFile=-/etc/etcd/etcd.conf
User=etcd
ExecStart=/usr/bin/etcd
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Скачиваем easy-rsa:

$ mkdir /tmp/easyrsa
$ cd /tmp/easyrsa
$ curl -sSL -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
$ tar xzf easy-rsa.tar.gz
$ cd easy-rsa-master/easyrsa3

Генерируем самоподписанные сертификаты:

$ ./easyrsa --batch init-pki
# корневой
$ ./easyrsa --batch --req-cn="10.10.12.101" build-ca nopass
# серверный etcd
$ ./easyrsa --batch --subject-alt-name="IP:10.10.12.101 DNS:c00test01" build-server-full server nopass
# сертификат для peer-ов etcd
$ ./easyrsa --batch --subject-alt-name "IP:10.10.12.101 DNS:c00test01" build-server-full peer nopass
# клиентский для kube-apiserver и flannel
$ ./easyrsa --batch build-client-full client nopass

Копируем в директорию сертификатов etcd:

$ mkdir /etc/etcd/certs
$ cp -p pki/ca.crt /etc/etcd/certs/ca.crt
$ cp -p pki/issued/* /etc/etcd/certs/
$ cp -p pki/private/* /etc/etcd/certs/
$ chmod –R 440 /etc/etcd/certs/
# Приберемся
$ rm -rf /tmp/easyrsa/pki/

Стартуем etcd:

$ systemctl enable etcd && systemctl start etcd

Загружаем конфиг сети в etcd:

/tmp/flannel-conf.json

{ 
  "Network": "172.96.0.0/12",
  "SubnetLen": 24,
  "Backend":
    {
      "Type": "vxlan"
    }
}

# 'cluster.lan' можно изменить на свое имя кластера
$ /usr/bin/etcdctl --cert-file=/etc/flanneld/certs/client.crt --key-file=/etc/flanneld/certs/client.key --ca-file=/etc/flanneld/certs/ca.crt --no-sync --peers=https://10.10.12.101:2379 set /cluster.lan/network/config < /tmp/flannel-conf.json

2. Установка flannel

$ yum install flannel-0.7.1

Правим конфиг:

/etc/sysconfig/flanneld

# 'cluster.lan' можно изменить на свое имя кластера
FLANNEL_ETCD="https://c00test01:2379"
FLANNEL_ETCD_ENDPOINTS="https://c00test01:2379"

FLANNEL_ETCD_KEY="/cluster.lan/network"
FLANNEL_ETCD_PREFIX="/cluster.lan/network"

FLANNEL_ETCD_CAFILE="/etc/flanneld/certs/ca.crt"
FLANNEL_ETCD_CERTFILE="/etc/flanneld/certs/client.crt"
FLANNEL_ETCD_KEYFILE="/etc/flanneld/certs/client.key"

FLANNEL_OPTIONS="-etcd-cafile /etc/flanneld/certs/ca.crt -etcd-certfile /etc/flanneld/certs/client.crt -etcd-keyfile /etc/flanneld/certs/client.key"

Скопируем сертификаты:

$ mkdir –R /etc/flanneld/certs
$ cp /etc/etcd/certs/ca.pem /etc/flanneld/certs/ca.crt
$ cp /etc/etcd/certs/client.crt /etc/flanneld/certs/client.crt
$ cp /etc/etcd/certs/client.key /etc/flanneld/certs/client.key
$ chmod –R 440 /etc/flanneld/certs/

Стартуем flannel:

$ systemctl enable flanneld && systemctl start flannel

3. Устанавливаем и запускаем Docker

$ yum install docker-1.12.6
$ systemctl enable docker && systemctl start docker

Переходим к установке/настройке самого Kubernetes

4. Установка apiserver

Устанавливаем готовые к употреблению RPM отсюда:

$ mkdir /tmp/k8s
$ cd /tmp/k8s
$ rpms=(kubernetes-master kubernetes-client kubernetes-node)
$ for i in ${rpms[*]}; do wget https://kojipkgs.fedoraproject.org/packages/kubernetes/1.8.1/1.fc28/x86_64/${i}-1.8.1-1.fc28.x86_64.rpm; done
$ yum install kubernetes-master-1.8.1-1.fc28.x86_64.rpm kubernetes-client-1.8.1-1.fc28.x86_64.rpm kubernetes-node-1.8.1-1.fc28.x86_64.rpm

Генерируем сертификаты:

$ cd /tmp/easyrsa
$ ./easyrsa --batch init-pki
# корневой
$ ./easyrsa --batch --req-cn="10.10.12.101" build-ca nopass
# серверный apiserver-а. в alt-names должны быть перечислены все ip и dns имена мастер-сервера
$ ./easyrsa --batch --subject-alt-name="IP:172.30.0.1 DNS:kubernetes DNS:kubernetes.default DNS:kubernetes.default.svc DNS:kubernetes.default.svc.cluster.lan IP:10.10.12.101 DNS:c00test01" build-server-full server nopass
# серверный kubelet. поскольку генерируем один сертификат на всех миньенов, в alt-names указываем все hostname серверов, которые будут миньенами
# этот сертификат нужен чтобы при командах 'kubectl log', 'kubectl exec' не было ошибок 'certificate signed by unknown authority'
$ ./easyrsa --batch --subject-alt-name "DNS:c00test01 DNS:c00test02" build-server-full apiserver-kubelet-client nopass
# клиентский kubelet и kubectl
$ ./easyrsa --batch build-client-full kubelet nopass
$ ./easyrsa --batch build-client-full kubectl nopass

Скопируем их в директорию kubernetes:

$ cp -p pki/ca.crt /etc/kubernetes/certs/ca.crt
$ cp -p pki/issued/* /etc/kubernetes/certs/
$ cp -p pki/private/* /etc/kubernetes/certs/
$ chown –R kube:kube /etc/kubernetes/certs/
$ chmod –R 440 /etc/kubernetes/certs/
# Приберемся
$ rm -rf /tmp/easyrsa/pki/

Скопируем сертификаты etcd в директорию kubernetes:

$ mkdir /etc/kubernetes/certs/etcd
$ cd /etc/etcd/certs 
$ cp ca.crt /etc/kubecnetes/certs/etcd/ca.crt
$ cp client.crt /etc/kubecnetes/certs/etcd/client.crt
$ cp client.key /etc/kubecnetes/certs/etcd/client.key

Удаляем /etc/kubernetes/config так как все настройки по подключению будут указываться в *.kubeconfig файлах

rm /etc/kubernetes/config

Правим конфиг:

/etc/kubernetes/apiserver

KUBE_API_ADDRESS="--bind-address=0.0.0.0"

KUBE_API_PORT="--secure-port=6443"

# KUBELET_PORT="--kubelet-port=10250"

KUBE_ETCD_SERVERS="--etcd-servers=https://c00test01:2379 --etcd-cafile=/etc/kubernetes/certs/etcd/ca.crt --etcd-certfile=/etc/kubernetes/certs/etcd/client.crt --etcd-keyfile=/etc/kubernetes/certs/etcd/client.key"

KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=172.30.0.0/16"

KUBE_ADMISSION_CONTROL="--admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota"

KUBE_API_ARGS="--tls-cert-file=/etc/kubernetes/certs/server.crt 
--tls-private-key-file=/etc/kubernetes/certs/server.key 
--tls-ca-file=/etc/kubernetes/certs/ca.crt 
--client-ca-file=/etc/kubernetes/certs/ca.crt 
--kubelet-certificate-authority=/etc/kubernetes/certs/ca.crt 
--kubelet-client-certificate=/etc/kubernetes/certs/apiserver-kubelet-client.crt 
--kubelet-client-key=/etc/kubernetes/certs/apiserver-kubelet-client.key 
--token-auth-file=/etc/kubernetes/tokens/known_tokens.csv 
--service-account-key-file=/etc/kubernetes/certs/server.crt 
--bind-address=0.0.0.0 
--insecure-port=0 
--apiserver-count=1 
--basic-auth-file=/etc/kubernetes/certs/basic.cnf 
--anonymous-auth=false 
--allow-privileged=true"

Создаем директорию для токенов и пустой файл в ней:

$ mkdir /etc/kubernetes/tokens
$ touch /etc/kubernetes/tokens/known_tokens.csv

Разрешаем apiserver-у «биндить» привилегированные порты:

$ setcap cap_net_bind_service=ep /usr/bin/kube-apiserver

Создаем файл для basic auth:

$ touch /etc/kubernetes/certs/basic.cnf

Заполняется по правилу: имя_пользователя, пароль,id
id – произвольное уникальное число

Например:

/etc/kubernetes/certs/basic.cnf

admin,password,001
deploy,deploy,002

Можно обойтись и без basic auth, но иногда приходится использовать, как в случае с деплоем в кластер средствами ansible.

Генерируем токены.
Обратите внимание что токены будут одинаковы для всех kubelet и kube-proxy. Чтобы сгенерировать разные, достаточно добавить -<имя_хоста> к имени аккаунта. (примвер: system:kubelet-c00test02)

generate_tokes.sh

#!/bin/bash
accounts=(system:controller_manager system:scheduler system:kubectl system:dns system:kubelet system:proxy)
for account in ${accounts[*]}; do
  token=$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64 | tr -d "=+/" | dd bs=32 count=1 2>/dev/null)
  echo "${token},${account},${account}" >> "/etc/kubernetes/tokens/known_tokens.csv"
  echo "${token}" > "/etc/kubernetes/tokens/${account}.token"
done

Стартуем api-server:

$ systemctl enable kube-apiserver && systemctl start kube-apiserver

Настраиваем controller-manager.

Правим конфиги:

/etc/kubernetes/controller-manager

KUBE_CONTROLLER_MANAGER_ARGS="--kubeconfig=/etc/kubernetes/controller-manager.kubeconfig 
--service-account-private-key-file=/etc/kubernetes/certs/server.key 
--root-ca-file=/etc/kubernetes/certs/ca.crt "

/etc/kubernetes/controller-manager.kubeconfig

# 'cluster.lan' можно изменить на свое имя кластера
apiVersion: v1
kind: Config
current-context: controller-manager-to-cluster.lan
preferences: {}
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/certs/ca.crt
    server: https://c00test01:6443
  name: cluster.lan
contexts:
- context:
    cluster: cluster.lan
    user: controller-manager
  name: controller-manager-to-cluster.lan
users:
- name: controller-manager
  user:
# в token вписать содержимое /etc/kubernetes/tokens/system:controller-manager.token
    token: cW6ha9WHzTK9Y4psT9pMKcUqfr673ydF

Стартуем controller-manager:

$ systemctl enable kube-controller-manager && systemctl start kube-controller-manager

Настраиваем kube-scheduler.

Правим конфиги:

/etc/kubernetes/scheduler

KUBE_SCHEDULER_ARGS="--kubeconfig=/etc/kubernetes/scheduler.kubeconfig"

/etc/kubernetes/scheduler.kubeconfig

# 'cluster.lan' можно изменить на свое имя кластера
apiVersion: v1
kind: Config
current-context: scheduler-to-cluster.lan
preferences: {}
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/certs/ca.crt
    server: https://c00test01:6443
  name: cluster.lan
contexts:
- context:
    cluster: cluster.lan
    user: scheduler
  name: scheduler-to-cluster.lan
users:
- name: scheduler
  user:
# в token вписать содержимое /etc/kubernetes/tokens/system:scheduler.token
    token: A2cU20Q9MkzdK8ON6UnVaP1nusWNKrWT

Стартуем kube-scheduler:

$ systemctl enable kube-scheduler && systemctl start kube-scheduler

Настраиваем kubectl.

Правим конфиг:

/etc/kubernetes/kubectl.kubeconfig

# 'cluster.lan' можно изменить на свое имя кластера
apiVersion: v1
kind: Config
current-context: kubectl-to-cluster.lan
preferences: {}
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/certs/ca.crt
    server: https://c00test01:6443
  name: cluster.lan
contexts:
- context:
    cluster: cluster.lan
    user: kubectl
  name: kubectl-to-cluster.lan
users:
- name: kubectl
  user:
    client-certificate: /etc/kubernetes/certs/kubectl.crt
    client-key: /etc/kubernetes/certs/kubectl.key

Для удобства, чтобы при вызове kubectl не указывать расположение до конфига параметром –kubeconfig, можно создать в хомяке своего пользователя директорию .kube и скопировать туда конфиг kubectl переименовав в config

Например:
/home/user1/.kube/config

Установка kube-dns.

Деплоим kube-dns replication controller

$ cat <<EOF | kubectl create –f –
apiVersion: v1
kind: ReplicationController
metadata:
  name: kube-dns-v20
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    version: v20
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  selector:
    k8s-app: kube-dns
    version: v20
  template:
    metadata:
      labels:
        k8s-app: kube-dns
        version: v20
    spec:
# блок привязки
# я обычно привязываю системные компоненты к мастер-ноде
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - c00test01
# блок привязки
      containers:
      - name: kubedns
        image: gcr.io/google_containers/kubedns-amd64:1.8
        resources:
          limits:
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi
        livenessProbe:
          httpGet:
            path: /healthz-kubedns
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /readiness
            port: 8081
            scheme: HTTP
          initialDelaySeconds: 3
          timeoutSeconds: 5
        args:
        # command = "/kube-dns"
# 'cluster.lan' можно изменить на свое имя кластера
        - --domain=cluster.lan.
        - --dns-port=10053
        ports:
        - containerPort: 10053
          name: dns-local
          protocol: UDP
        - containerPort: 10053
          name: dns-tcp-local
          protocol: TCP
      - name: dnsmasq
        image: gcr.io/google_containers/kube-dnsmasq-amd64:1.4
        livenessProbe:
          httpGet:
            path: /healthz-dnsmasq
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        args:
        - --cache-size=1000
        - --no-resolv
        - --server=127.0.0.1#10053
        - --log-facility=-
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
      - name: healthz
        image: gcr.io/google_containers/exechealthz-amd64:1.2
        resources:
          limits:
            memory: 50Mi
          requests:
            cpu: 10m
            memory: 50Mi
        args:
# 'cluster.lan' можно изменить на свое имя кластера
        - --cmd=nslookup kubernetes.default.svc.cluster.lan 127.0.0.1 >/dev/null
        - --url=/healthz-dnsmasq
        - --cmd=nslookup kubernetes.default.svc.cluster.lan 127.0.0.1:10053 >/dev/null
        - --url=/healthz-kubedns
        - --port=8080
        - --quiet
        ports:
        - containerPort: 8080
          protocol: TCP
      dnsPolicy: Default
      tolerations:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
      - key: CriticalAddonsOnly
        operator: Exists
EOF

Деплоим kube-dns service

$ cat <<EOF | kubectl create –f –
apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "KubeDNS"
spec:
  selector:
    k8s-app: kube-dns
# берется 10й по порядку из пула,
# который указан в параметре apiserver-а '-–service-cluster-ip-range'
  clusterIP: 172.30.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP
EOF

Установка мастера закончена. Однако посмотрев на статус pod-ов, мы увидим что kube-dns в статусе pending. Это потому что пока мы не настроили миньенов, в которые Kubernetes будет селить pod-ы.

Для миньенов необходимо выполнить действия пунктов 2 и 3 (установить flannel и docker).

5. Установка и настройка kubelet

На ноде c00test01 у нас уже все установлено, а вот на ноде c00test02 нужно установить пакеты:

$ mkdir /tmp/k8s
$ cd /tmp/k8s
$ rpms=(kubernetes-client kubernetes-node);for i in ${rpms[*]}; do wget https://kojipkgs.fedoraproject.org/packages/kubernetes/1.8.1/1.fc28/x86_64/${i}-1.8.1-1.fc28.x86_64.rpm; done
$ yum install kubernetes-client-1.8.1-1.fc28.x86_64.rpm kubernetes-node-1.8.1-1.fc28.x86_64.rpm

Так же нужно скопировать сертификаты и ключи с мастер-ноды в директорию /etc/kubernetes/certs:
kubelet.crt
kubelet.key
apiserver-kubelet-client.crt
apiserver-kubelet-client.key

Правим конфиги:

/etc/kubernetes/kubelet

KUBELET_ADDRESS="--address=0.0.0.0"

# KUBELET_PORT="--port=10250"

KUBELET_HOSTNAME="--hostname-override=c00test02"

KUBELET_ARGS="--register-node=true 
--tls-cert-file=/etc/kubernetes/certs/apiserver-kubelet-client.crt 
--tls-private-key-file=/etc/kubernetes/certs/apiserver-kubelet-client.key 
--require-kubeconfig=true 
--kubeconfig=/etc/kubernetes/kubelet.kubeconfig 
--pod-manifest-path=/etc/kubernetes/manifests 
--cgroup-driver=systemd 
--allow-privileged=true 
--cluster-domain=cluster.lan 
--authorization-mode=Webhook 
--fail-swap-on=false 
--cluster-dns=172.30.0.10"

Возьмем с мастера содержимое ca.crt:

$ base64 /etc/kubernetes/certs/ca.crt

/etc/kubernetes/kubelet.kubeconfig

apiVersion: v1
kind: Config
current-context: kubelet-to-cluster.lan # change 'cluster.lan to your cluster name'
preferences: {}
clusters:
- cluster:
    certificate-authority-data: <содержимое_ca.crt_в_base64>
    server: https://c00test01:6443
  name: cluster.lan # change 'cluster.lan to your cluster name'
contexts:
- context:
    cluster: cluster.lan # change 'cluster.lan to your cluster name'
    user: kubelet
  name: kubelet-to-cluster.lan # change 'cluster.lan to your cluster name'
users:
- name: kubelet
  user:
    client-certificate: /etc/kubernetes/certs/kubelet.crt
    client-key: /etc/kubernetes/certs/kubelet.key

/etc/kubernetes/proxy

<source lang=«basic>
KUBE_PROXY_ARGS=»--kubeconfig=/etc/kubernetes/proxy.kubeconfig --cluster-cidr=172.30.0.0/16"

/etc/kubernetes/proxy.kubeconfig

apiVersion: v1
kind: Config
current-context: proxy-to-cluster.lan # change 'cluster.lan to your cluster name'
preferences: {}
contexts:
- context:
    cluster: cluster.lan # change 'cluster.lan to your cluster name'
    user: proxy
  name: proxy-to-cluster.lan # change 'cluster.lan to your cluster name'
clusters:
- cluster:
    certificate-authority-data: <содержимое_ca.crt_в_base64>
    server: https://c00test01:6443
  name: cluster.lan # change 'cluster.lan to your cluster name'
users:
- name: proxy
  user:
    client-certificate: /etc/kubernetes/certs/kubelet.crt
    client-key: /etc/kubernetes/certs/kubelet.key

Стартуем kubelet и kube-proxy:

$ systemctl enable kubelet && systemctl enable kube-proxy
$ systemctl start kubelet && systemctl start kube-proxy

Установка закончена, можно проверить состояние нод и pod-а kube-dns.

$ kubectl get nodes
NAME          STATUS    ROLES     AGE       VERSION
c00test01     Ready     master    5m        v1.8.1
c00test02     Ready     <none>    4m        v1.8.1

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                   READY     STATUS    RESTARTS   AGE
kube-system   kube-dns-v20-2jqsj                     3/3       Running   0          3m

При написании данного руководства были использованы следующие материалы:
Официальная документация
Kubernetes Ansible

Автор: Aleksey

Источник

Поделиться

* - обязательные к заполнению поля