Bare Metal 서버에 kubespray를 이용하여 Production 환경의 Kubernetes 클러스터 구축
Kubespray는 일반적인 OS 설정과 Kubernetes 구성/관리 작업에 관련된 Ansible playbook들과 inventory 그리고 배포 도구들을 조합한 소프트웨어입니다.
구성환경
하드웨어
- 5 Nodes: VM 또는 물리 서버
Memory: 8GB
CPU: 4Core
디스크: 120GB 이상
소프트웨어
Kubernetes nodes
- Ubuntu 18.04
- Python
- SSH Server
- sudo 권한을 가진 유저
Kubespray machine
- Ansible 2.7.8+(not 2.8.x)
- Jinja 2.9+
Node 네트워킹 요구사항
- Docker 이미지들을 download하고 소프트웨어들을 설치할 수 있도록 인터넷 접속을 허용해줍니다.
- IPv4 Forwarding 활성화합니다.
- 배포 중에 문제가 발생하는 것을 방지하기 위해 방화벽을 비활성화합니다.
Node 준비
다음 내용들을 모든 node들에서 수행합니다.
Python 설치
Ansible이 작업을 수행하는 모든 서버는 python이 설치되어져 있어야 합니다. Ubuntu 18.04에서는 기본적으로 Python3이 설치되어져 있으므로 symbolic link를 만들어 줍니다.
sudo ln -s /usr/bin/python3 /usr/bin/python
Swap 비활성화
sudo swapoff -a
sudo sed -i '/ swap /d' /etc/fstab
key 기반 인증을 사용할 수 있도록 SSH 구성
Ansible을 실행하려는 서버에서 다음 명령어를 실행하여 RSA key pair를 생성합니다.
ssh-keygen -t rsa
public key를 모든 노드에 복사합니다.
ssh-copy-id ubuntu@<node-ip-address>
Ansible 제어 서버 구성
kubespray 구성
공식 레포지토리를 복제합니다.
git clone https://github.com/kubernetes-incubator/kubespray.git
cd kubespray
requirements.txt
으로 의존성 패키지들을 설치합니다.
sudo pip install -r requirements.txt
Ansible을 실행할 유저 설정
ansible.cfg
파일에서 다음 코드를 추가합니다.
vim ansible.cfg
...
[defaults]
...
remote_user=ubuntu
Inventory 생성
cp -rfp inventory/sample inventory/prod
sample inventory를 prod로 복사합니다. 이는 임의의 이름으로 설치하려는 클러스터에 맞게 정하시면 됩니다.
inventory generator를 사용하여 Inventory를 생성합니다.
declare -a IPS=(10.211.55.42 10.211.55.43 10.211.55.44 10.211.55.45 10.211.55.46)
CONFIG_FILE=inventory/prod/hosts.yml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
실행한 후에는 다음과 같이 인벤토리가 생성된 것을 확인하실 수 있습니다.
all:
hosts:
node1:
ansible_host: 10.211.55.42
ip: 10.211.55.42
access_ip: 10.211.55.42
node2:
ansible_host: 10.211.55.43
ip: 10.211.55.43
access_ip: 10.211.55.43
node3:
ansible_host: 10.211.55.44
ip: 10.211.55.44
access_ip: 10.211.55.44
node4:
ansible_host: 10.211.55.45
ip: 10.211.55.45
access_ip: 10.211.55.45
node5:
ansible_host: 10.211.55.46
ip: 10.211.55.46
access_ip: 10.211.55.46
children:
kube-master:
hosts:
node1:
node2:
kube-node:
hosts:
node1:
node2:
node3:
node4:
node5:
etcd:
hosts:
node1:
node2:
node3:
k8s-cluster:
children:
kube-master:
kube-node:
calico-rr:
hosts: {}
Kubernetes node tuning과 Kubernetes master들의 HA를 위한 haproxy 설치
Kubernetes node tuning을 위한 Ansible role을 다운로드 합니다.
cd roles/
git clone https://github.com/lapee79/ansible-role-ubuntu-tuning-for-k8s.git
mv ansible-role-ubuntu-tuning-for-k8s ubuntu-tuning-for-k8s
cd ..
tuning을 위한 playbook을 생성합니다.
cat << EOF | tee nodes-tuning.yml
---
- hosts: all
become: true
roles:
- name: ubuntu-tuning-for-k8s
tags:
- ubuntu
- kubernetes
EOF
nodes-tuning playbook을 수행합니다.
ansible-playbook -i inventory/prod/hosts.yml nodes-tuning.yml
Kubernetes mastser들을 HA 구성하기 위한 haproxy Ansible role을 다운로드합니다.
cd roles/
git clone https://github.com/lapee79/ansible-role-haproxy-for-k8s-masters.git
mv ansible-role-haproxy-for-k8s-masters haproxy-for-k8s-masters
inventory 디렉토리 내의 group_vars/all/all.yml
파일에서 haproxy에서 사용할 IP 주소와 port를 설정합니다.
cd ..
vim inventory/prod/group_vars/all/all.yml
...
## External LB example config
## apiserver_loadbalancer_domain_name: "elb.some.domain"
apiserver_loadbalancer_domain_name: "10.211.55.101"
loadbalancer_apiserver:
address: 10.211.55.101
port: 443
haproxy 설정값들을 포함하도록 inventory 파일을 수정합니다.
all:
hosts:
k8s-master-01:
ansible_host: 10.211.55.42
ip: 10.211.55.42
access_ip: 10.211.55.42
k8s-master-02:
ansible_host: 10.211.55.43
ip: 10.211.55.43
access_ip: 10.211.55.43
k8s-master-03:
ansible_host: 10.211.55.44
ip: 10.211.55.44
access_ip: 10.211.55.44
k8s-worker-01:
ansible_host: 10.211.55.45
ip: 10.211.55.45
access_ip: 10.211.55.45
k8s-worker-02:
ansible_host: 10.211.55.46
ip: 10.211.55.46
access_ip: 10.211.55.46
children:
kube-master:
hosts:
k8s-master-01:
vrrp_instance_state: MASTER
vrrp_instance_priority: 101
k8s-master-02:
vrrp_instance_state: BACKUP
vrrp_instance_priority: 100
k8s-master-03:
vrrp_instance_state: BACKUP
vrrp_instance_priority: 99
vars:
vrrp_interface: enp0s5
vrrp_instance_virtual_router_id: 51
kube-node:
hosts:
k8s-worker-01:
k8s-worker-02:
etcd:
hosts:
k8s-master-01:
k8s-master-02:
k8s-master-03:
k8s-cluster:
children:
kube-master:
kube-node:
calico-rr:
hosts: {}
Kubernetes master들에 haproxy를 설치하도록 playbook을 작성합니다..
cat << EOF | tee setup-haproxy-for-k8s-masters.yml
---
- hosts: kube-master
become: true
roles:
- name: haproxy-for-k8s-masters
tags:
- haproxy
- keepalived
- kubernetes
EOF
setup-haproxy-for-k8s-masters
playbook을 수행합니다.
cd ../../..
ansible-playbook -i inventory/prod/hosts.yml setup-haproxy-for-k8s-masters.yml
Kubernetes cluster 설정 변경
inventory 디렉토리 아래의 group_vars 내에는 config 파일들이 있습니다. 이 파일들을 수정하여 설정들을 변경할 수 있습니다.
vim inventory/prod/group_vars/k8s-cluster/k8s-cluster.yml
...
# Choose network plugin (cilium, calico, contiv, weave or flannel. Use cni for generic cni plugin)
# Can also be set to 'cloud', which lets the cloud provider setup appropriate routing
kube_network_plugin: calico
...
# configure arp_ignore and arp_announce to avoid answering ARP queries from kube-ipvs0 interface
# must be set to true for MetalLB to work
kube_proxy_strict_arp: true
...
# Make a copy of kubeconfig on the host that runs Ansible in {{ inventory_dir }}/artifacts
kubeconfig_localhost: true
# Download kubectl onto the host that runs Ansible in {{ bin_dir }}
# kubectl_localhost: false
vim inventory/prod/group_vars/k8s-cluster/addons.yml
...
# Kubernetes dashboard
# RBAC required. see docs/getting-started.md for access details.
dashboard_enabled: false
kubespray를 이용하여 Kubernetes 클러스터 구성
ansible playbook를 수행하여 Kubernetes 클러스터를 구성합니다.
ansible-playbook -i inventory/prod/hosts.yml cluster.yml -b -v \
--private-key=~/.ssh/private_key
Kubernetes 클러스터 검증
Kubernetes 클러스터 구성이 완료된 후에 다음 명령어를 사용하여 구성된 클러스터를 검증할 수 있습니다.
kubectl --kubeconfig=inventory/prod/artifacts/admin.conf cluster-info
kubectl --kubeconfig=inventory/prod/artifacts/admin.conf get nodes
Kubernetes 클러스터 확장/축소
node 추가
- inventory에 node host를 추가한 후에 kube-node 그룹에도 추가해줍니다.
cluster.yml
대신에scale.yml
playbook을 이용하여 ansible-playbook을 수행합니다.
ansible-playbook -i inventory/prod/hosts.yml scale.yml -b -v \
--private-key=~/.ssh/private_key
node 제거
remove-node.yml
playbook을 재수행하여 클러스터에서 master, worker, etcd node를 제거할 수 있습니다. 먼저 지정된 node들이 drain된 다음 Kubernetes 서비스들을 정지하고 certificate들을 삭제한 후에 마지막으로 이 node들을 삭제하는 kubectl 명령을 수행합니다. 이는 node 추가와 결합될 수 있습니다.
제거하려는 node들은 --extra-vars "node=,"
으로 값을 전달합니다.
ansible-playbook -i inventory/prod/hosts.yml remove-node.yml -b -v \
--private-key=~/.ssh/private_key \
--extra-vars "node=nodename,nodename2"
Kubernetes 업그레이드
주의
만약 기존에 deprecated API object들로 배포환경이 구축되어져 있고 Kubernetes 1.16 버젼 이상으로 업그레이드를 한다고 했을 때, 다음 설정을 통해 기존 object들을 유지할 수 있습니다.
https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16/
vim roles/kubernetes/node/defaults/main.yaml
...
# deprecated runtime을 활성화하려면 다음 section의 주석을 해제합니다.
kube_api_runtime_config:
- apps/v1beta1=true
- apps/v1beta2=true
- extensions/v1beta1/daemonsets=true
- extensions/v1beta1/deployments=true
- extensions/v1beta1/replicasets=true
- extensions/v1beta1/networkpolicies=true
- extensions/v1beta1/podsecuritypolicies=true
Rolling 업그레이드
클러스터 업그레이드를 수행할 때, Kubespray는 node들에 cordon, drain, uncordon을 지원합니다. 업그레이드만을 지원하기 위한 별도의 upgrade-cluster.yml
playbook이 존재합니다. 이는 기존에 최소 1대 이상의 kube-master가 반드시 존재해야 한다는 것을 의미합니다.
ansible-playbook upgrade-cluster.yml -b -i inventory/prod/hosts.yml -e kube_version=v1.16.3
업그레이드가 성공했다면 Server Version이 업그레이드 된 것을 확인하실 수 있습니다.
kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T23:42:50Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.3", GitCommit:"b3cbbae08ec52a7fc73d334838e18d17e8512749", GitTreeState:"clean", BuildDate:"2019-11-13T11:13:49Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}