четверг, 31 декабря 2015 г.

Установка системы управления docker-контейнерами kubernetes


С развитием инфраструктуры docker-контейнеров появляется необходимость управления большим числом docker-контейнеров. Для этой цели служат системы: 
  • Kubernetes развиваемый компанией Google
  • Mesos развиваемый в сообществе Apache 
  • Docker Swarm от создателей Docker.
Компания Google утверждает, что уже более 9-ти лет использует в своей работе контейнеры. Поэтому разрабатываемая ими система Kubernetes является на сегодня стабильной и продвинутой.
С помощью этой статьи вы сможете легко развернуть кластер kubernetes из мастера и двух нод. И легко добавлять node-машины в дальнейшем. Мастер нода имеет API для управления кластером и дирежирует контейнерами. Ноды получают команды от мастера и запускают контейнеры.
Для начала нужно иметь 2 сервера и установить на них Docker.
Мы будем использовать 2 Docker-демона на каждом сервере:
  1. Docker начальной загрузки для запуска flanneld и etcd;
  2. Основной Docker для запуска инфраструктуры Kubernetes и запуска наших контейнеров.
Потребность в двух docker-демонах необходима по той причине, что для объединения всех контейнеров в единую сеть, будет использоваться демон flannel. Он должен запускаться не в основном Docker.

Настройка мастера
Мастер настраивается в 2 этапа:
  1. установка flanneld и etcd
  2. запуск компонент мастера
Для простоты, инициализируем переменную с IP адресом мастера:
export MASTER_IP=<IP адрес мастера, например 1.2.3.4>

Запускаем вспомогательный docker
sudo sh -c 'docker -d -H unix:///var/run/docker-bootstrap.sock \
  -p /var/run/docker-bootstrap.pid \
  --iptables=false \
  --ip-masq=false \
  --bridge=none \
  --graph=/var/lib/docker-bootstrap \
  2> /var/log/docker-bootstrap.log 1> /dev/null &'
Этот docker запускается с опцией --iptables=false, чтобы запускаемые им контейнеры работали только с опцией --net=host.

Запускаем etcd для flannel и API
sudo docker -H unix:///var/run/docker-bootstrap.sock run  \
  --restart=always \
  --net=host 
  -d gcr.io/google_containers/etcd:2.0.12 \
  /usr/local/bin/etcd --addr=127.0.0.1:4001 \
  --bind-addr=0.0.0.0:4001 \
  --data-dir=/var/etcd/data
Прописываем в etcd сеть для flannel 
Сеть не должна пересекаться с уже имеющимися сетями:
sudo docker -H unix:///var/run/docker-bootstrap.sock run \
  --net=host \
  gcr.io/google_containers/etcd:2.0.12 \
  etcdctl set /coreos.com/network/config '{ "Network": "10.1.0.0/16" }'
Устанавливаем flannel на мастер-ноде
Flannel перенастраивает bridge, который настроил Docker. Поэтому надо остановить основной Docker, запустить Flannel и снова запустить Docker.
Останавливаем Docker
sudo service docker stop

Запускаем flannel
sudo docker -H unix:///var/run/docker-bootstrap.sock run \
  -d \
  --restart=always \
  --net=host \
  --privileged \
  -v /dev/net:/dev/net \
  quay.io/coreos/flannel:0.5.0
Эта команда выведет длинный хеш, который будет использоваться в следующей команде. Скопируйте его.

Получаем настройки flannel-сети
sudo docker -H unix:///var/run/docker-bootstrap.sock \
  exec <длинный-хеш> cat /run/flannel/subnet.env
Пример вывода этой команды:
FLANNEL_SUBNET=10.1.10.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=false

Добавляем вспомогательный Docker в автозагрузку
Создаём файл /lib/systemd/system/docker-bootstrap.socket с таким содержимым:
[Unit]
Description=Docker Socket for the API
PartOf=docker-bootstrap.service

[Socket]
ListenStream=/var/run/docker-bootstrap.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
И файл /lib/systemd/system/docker-bootstrap.service с таким содержимым:
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker-bootstrap.socket
Requires=docker-bootstrap.socket

[Service]
ExecStart=/usr/bin/docker -d -H unix:///var/run/docker-bootstrap.sock -p /var/run/docker-bootstrap.pid --iptables=false --ip-masq=false --bridge=none --graph=/var/lib/docker-bootstrap
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
В файл /lib/systemd/system/docker.service после After=network.target docker.socket
добавляем docker-bootstrap.service
После этого перечитываем конфиги systemctl
systemctl daemon-reload
systemctl enable docker-bootstrap

Настраиваем основной Docker
В конфиругационном файле или в скрипте запуска (для Ubuntu это /etc/default/docker или /etc/systemd/service/docker.service) нужно добавить:
--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
Вместо FLANNEL_SUBNET и FLANNEL_MTU нужно прописать параметры из вывода предыдущей команды.
Команда запуска основного докера должа получится примерно такой:
/usr/bin/docker -d -H fd:// --bip="10.1.10.1/24" --mtu=1472

Удаляем существующий Docker bridge
По-умолчанию Docker создаёт bridge и именем docker0. Удалим его
sudo /sbin/ifconfig docker0 down
sudo brctl delbr docker0
Запускаем запускаем основной Docker
sudo service docker start

Запускаем kubernetes мастер
sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/sys:/sys:ro \
  --volume=/dev:/dev \
  --volume=/var/lib/docker/:/var/lib/docker:rw \
  --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
  --volume=/var/run:/var/run:rw \
  --net=host \
  --privileged=true \
  --pid=host \
  --restart=always \
  -d \
  gcr.io/google_containers/hyperkube:v1.1.3 /hyperkube kubelet --api-servers=http://localhost:8080 --v=2 --address=0.0.0.0 --enable-server --hostname-override=127.0.0.1 --config=/etc/kubernetes/manifests-multi --cluster-dns=10.0.0.10 --cluster-domain=cluster.local
Примечание: --cluster-dns и --cluster-domain нужны для запуска внутреннего DNS сервера. Можно исключить их из команды запуска мастера.

Примечание 2: если при запуске этого контейнера появляется ошибка "System error: The minimum allowed cpu-shares is 1024", то лечится она добавлением параметра --exec-opt native.cgroupdriver=cgroupfs в команду запуска основого Docker.


Запускаем service proxy для kubernetes
Service proxy обеспечивает балансировку нагрузку между группами контейнеров объединёных в Kubernetes services
sudo docker run -d --restart=always \
  --net=host \
  --privileged \
  gcr.io/google_containers/hyperkube:v1.1.3 /hyperkube proxy --master=http://127.0.0.1:8080 --v=2

Теперь у нас есть настроенный кластер из одной  ноды и мастера. Можем протестировать это.
Скачаем утилиту kubectl
wget -O /usr/bin/kubectl http://storage.googleapis.com/kubernetes-release/release/v1.1.3/bin/linux/amd64/kubectl
chmod +x /usr/bin/kubectl 
Запустим команду
kubectl get nodes
Пример вывода этой команды:
NAME        LABELS                             STATUS
127.0.0.1   kubernetes.io/hostname=127.0.0.1   Ready

Добавление ноды в кластер
Добавление ноды во многом повторяет настройку мастера. Процесс состоит из 3 шагов
  1. запуск flanneld
  2. запуск kubernetes
  3. добавление ноды в кластер
Инициализируем 2 переменные:
export MASTER_IP=<IP адрес мастера, например 1.2.3.4>
export NODE_IP=<IP адрес ноды, например 4.3.2.1>

Запуск flanneld
Запускаем Docker  для начальной загрузки
sudo sh -c 'docker -d -H unix:///var/run/docker-bootstrap.sock \
  -p /var/run/docker-bootstrap.pid \
  --iptables=false \
  --ip-masq=false \
  --bridge=none \
  --graph=/var/lib/docker-bootstrap \
  2> /var/log/docker-bootstrap.log 1> /dev/null &'

Останавливаем основной Docker
sudo service docker stop
Запускаем flannel
sudo docker -H unix:///var/run/docker-bootstrap.sock run \
  -d \
  --net=host \
  --privileged \
  -v /dev/net:/dev/net \
  quay.io/coreos/flannel:0.5.0 /opt/bin/flanneld --etcd-endpoints=http://${MASTER_IP}:4001
Эта команда выведет длинный хеш, который будет использоваться в следующей команде. Скопируйте его.

Получаем настройки flannel-сети
sudo docker -H unix:///var/run/docker-bootstrap.sock \
  exec <длинный-хеш> cat /run/flannel/subnet.env
Пример вывода этой команды:
FLANNEL_SUBNET=10.1.90.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=false

Настраиваем основной Docker
В конфиругационном файле или в скрипте запуска (для Ubuntu это /etc/default/docker или /etc/systemd/service/docker.service) нужно добавить:
--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
Вместо FLANNEL_SUBNET и FLANNEL_MTU нужно прописать параметры из вывода предыдущей команды.
Команда запуска основного докера должа получится примерно такой:
/usr/bin/docker -d -H fd:// --bip="10.1.90.1/24" --mtu=1472

Удаляем существующий Docker bridge
sudo /sbin/ifconfig docker0 down
sudo brctl delbr docker0
Запускаем запускаем основной Docker
sudo service docker start
Запуск kubernetes для ноды
Запускаем kubelet
sudo docker run \
    --volume=/:/rootfs:ro \
    --volume=/sys:/sys:ro \
    --volume=/dev:/dev \
    --volume=/var/lib/docker/:/var/lib/docker:rw \
    --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
    --volume=/var/run:/var/run:rw \
    --net=host \
    --privileged=true \
    --pid=host \
    -d \
    gcr.io/google_containers/hyperkube:v1.1.3 /hyperkube kubelet --api-servers=http://localhost:8080 --v=2 --address=0.0.0.0 --enable-server --hostname-override=127.0.0.1 --config=/etc/kubernetes/manifests-multi --cluster-dns=10.0.0.10 --cluster-domain=cluster.local
Примечание: --cluster-dns и --cluster-domain можно исключить из этой команды

Запуск service proxy

sudo docker run -d \
  --net=host \
  --privileged \
  gcr.io/google_containers/hyperkube:v1.1.3 /hyperkube proxy --master=http://${MASTER_IP}:8080 --v=2

Теперь, выполнив на мастере команду kubectl get nodes, мы увидим, что новая нода включена в кластер.
NAME              LABELS                                   STATUS
127.0.0.1         kubernetes.io/hostname=127.0.0.1         Ready
NODE_IP           kubernetes.io/hostname=NODE_IP           Ready

Сделано на основе документации:
https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/getting-started-guides/docker-multinode/master.md
https://github.com/kubernetes/kubernetes/blob/release-1.1/docs/getting-started-guides/docker-multinode/worker.md

Комментариев нет: