1 - kubeadm 설치하기
이 페이지에서는 kubeadm
툴박스 설치 방법을 보여준다.
이 설치 프로세스를 수행한 후 kubeadm으로 클러스터를 만드는 방법에 대한 자세한 내용은 kubeadm을 사용하여 클러스터 생성하기 페이지를 참고한다.
시작하기 전에
- 호환되는 리눅스 머신. 쿠버네티스 프로젝트는 데비안 기반 배포판, 레드햇 기반 배포판, 그리고 패키지 매니저를 사용하지 않는 경우에 대한 일반적인 가이드를 제공한다.
- 2 GB 이상의 램을 장착한 머신. (이 보다 작으면 사용자의 앱을 위한 공간이 거의 남지 않음)
- 2 이상의 CPU.
- 클러스터의 모든 머신에 걸친 전체 네트워크 연결. (공용 또는 사설 네트워크면 괜찮음)
- 모든 노드에 대해 고유한 호스트 이름, MAC 주소 및 product_uuid. 자세한 내용은 여기를 참고한다.
- 컴퓨터의 특정 포트들 개방. 자세한 내용은 여기를 참고한다.
- 스왑의 비활성화. kubelet이 제대로 작동하게 하려면 반드시 스왑을 사용하지 않도록 설정한다.
MAC 주소 및 product_uuid가 모든 노드에 대해 고유한지 확인
- 사용자는
ip link
또는ifconfig -a
명령을 사용하여 네트워크 인터페이스의 MAC 주소를 확인할 수 있다. - product_uuid는
sudo cat /sys/class/dmi/id/product_uuid
명령을 사용하여 확인할 수 있다.
일부 가상 머신은 동일한 값을 가질 수 있지만 하드웨어 장치는 고유한 주소를 가질 가능성이 높다. 쿠버네티스는 이러한 값을 사용하여 클러스터의 노드를 고유하게 식별한다. 이러한 값이 각 노드에 고유하지 않으면 설치 프로세스가 실패할 수 있다.
네트워크 어댑터 확인
네트워크 어댑터가 두 개 이상이고, 쿠버네티스 컴포넌트가 디폴트 라우트(default route)에서 도달할 수 없는 경우, 쿠버네티스 클러스터 주소가 적절한 어댑터를 통해 이동하도록 IP 경로를 추가하는 것이 좋다.
iptables가 브리지된 트래픽을 보게 하기
br_netfilter
모듈이 로드되었는지 확인한다. lsmod | grep br_netfilter
를 실행하면 된다. 명시적으로 로드하려면 sudo modprobe br_netfilter
를 실행한다.
리눅스 노드의 iptables가 브리지된 트래픽을 올바르게 보기 위한 요구 사항으로, sysctl
구성에서 net.bridge.bridge-nf-call-iptables
가 1로 설정되어 있는지 확인해야 한다. 다음은 예시이다.
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system
자세한 내용은 네트워크 플러그인 요구 사항 페이지를 참고한다.
필수 포트 확인
필수 포트들은 쿠버네티스 컴포넌트들이 서로 통신하기 위해서 열려 있어야 한다. 다음과 같이 telnet 명령을 이용하여 포트가 열려 있는지 확인해 볼 수 있다.
telnet 127.0.0.1 6443
사용자가 사용하는 파드 네트워크 플러그인(아래 참조)은 특정 포트를 열어야 할 수도 있다. 이것은 각 파드 네트워크 플러그인마다 다르므로, 필요한 포트에 대한 플러그인 문서를 참고한다.
런타임 설치
파드에서 컨테이너를 실행하기 위해, 쿠버네티스는 컨테이너 런타임을 사용한다.
기본적으로, 쿠버네티스는 컨테이너 런타임 인터페이스(CRI)를 사용하여 사용자가 선택한 컨테이너 런타임과 인터페이스한다.
런타임을 지정하지 않으면, kubeadm은 잘 알려진 유닉스 도메인 소켓 목록을 검색하여 설치된 컨테이너 런타임을 자동으로 감지하려고 한다. 다음 표에는 컨테이너 런타임 및 관련 소켓 경로가 나열되어 있다.
런타임 | 유닉스 도메인 소켓 경로 |
---|---|
도커 | /var/run/dockershim.sock |
containerd | /run/containerd/containerd.sock |
CRI-O | /var/run/crio/crio.sock |
도커와 containerd가 모두 감지되면 도커가 우선시된다. 이것이 필요한 이유는 도커 18.09에서 도커만 설치한 경우에도 containerd와 함께 제공되므로 둘 다 감지될 수 있기 때문이다. 다른 두 개 이상의 런타임이 감지되면, kubeadm은 오류와 함께 종료된다.
kubelet은 빌트인 dockershim
CRI 구현을 통해 도커와 통합된다.
자세한 내용은 컨테이너 런타임을 참고한다.
기본적으로, kubeadm은 컨테이너 런타임으로 도커(Docker)를 사용한다.
kubelet은 빌트인 dockershim
CRI 구현을 통해 도커와 통합된다.
자세한 내용은 컨테이너 런타임을 참고한다.
kubeadm, kubelet 및 kubectl 설치
모든 머신에 다음 패키지들을 설치한다.
-
kubeadm
: 클러스터를 부트스트랩하는 명령이다. -
kubelet
: 클러스터의 모든 머신에서 실행되는 파드와 컨테이너 시작과 같은 작업을 수행하는 컴포넌트이다. -
kubectl
: 클러스터와 통신하기 위한 커맨드 라인 유틸리티이다.
kubeadm은 kubelet
또는 kubectl
을 설치하거나 관리하지 않으므로, kubeadm이
설치하려는 쿠버네티스 컨트롤 플레인의 버전과 일치하는지
확인해야 한다. 그렇지 않으면, 예상치 못한 버그 동작으로 이어질 수 있는
버전 차이(skew)가 발생할 위험이 있다. 그러나, kubelet과 컨트롤 플레인 사이에 하나의
마이너 버전 차이가 지원되지만, kubelet 버전은 API 서버 버전 보다
높을 수 없다. 예를 들어, 1.7.0 버전의 kubelet은 1.8.0 API 서버와 완전히 호환되어야 하지만,
그 반대의 경우는 아니다.
kubectl
설치에 대한 정보는 kubectl 설치 및 설정을 참고한다.
버전 차이에 대한 자세한 내용은 다음을 참고한다.
- 쿠버네티스 버전 및 버전-차이 정책
- Kubeadm 관련 버전 차이 정책
-
apt
패키지 색인을 업데이트하고, 쿠버네티스apt
리포지터리를 사용하는 데 필요한 패키지를 설치한다.sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl
-
구글 클라우드의 공개 사이닝 키를 다운로드 한다.
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
-
쿠버네티스
apt
리포지터리를 추가한다.echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
-
apt
패키지 색인을 업데이트하고, kubelet, kubeadm, kubectl을 설치하고 해당 버전을 고정한다.sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
# permissive 모드로 SELinux 설정(효과적으로 비활성화)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
참고:
-
setenforce 0
및sed ...
를 실행하여 permissive 모드로 SELinux를 설정하면 효과적으로 비활성화된다. 컨테이너가 호스트 파일시스템(예를 들어, 파드 네트워크에 필요한)에 접근하도록 허용하는 데 필요하다. kubelet에서 SELinux 지원이 개선될 때까지 이 작업을 수행해야 한다. -
구성 방법을 알고 있는 경우 SELinux를 활성화된 상태로 둘 수 있지만 kubeadm에서 지원하지 않는 설정이 필요할 수 있다.
CNI 플러그인 설치(대부분의 파드 네트워크에 필요)
CNI_VERSION="v0.8.2"
ARCH="amd64"
sudo mkdir -p /opt/cni/bin
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-${ARCH}-${CNI_VERSION}.tgz" | sudo tar -C /opt/cni/bin -xz
명령어 파일을 다운로드할 디렉터리 정의
DOWNLOAD_DIR
변수는 쓰기 가능한 디렉터리로 설정되어야 한다.
Flatcar Container Linux를 실행 중인 경우, DOWNLOAD_DIR=/opt/bin
을 설정한다.
DOWNLOAD_DIR=/usr/local/bin
sudo mkdir -p $DOWNLOAD_DIR
crictl 설치(kubeadm / Kubelet 컨테이너 런타임 인터페이스(CRI)에 필요)
CRICTL_VERSION="v1.17.0"
ARCH="amd64"
curl -L "https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-${ARCH}.tar.gz" | sudo tar -C $DOWNLOAD_DIR -xz
kubeadm
, kubelet
, kubectl
설치 및 kubelet
systemd 서비스 추가
RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
ARCH="amd64"
cd $DOWNLOAD_DIR
sudo curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${RELEASE}/bin/linux/${ARCH}/{kubeadm,kubelet,kubectl}
sudo chmod +x {kubeadm,kubelet,kubectl}
RELEASE_VERSION="v0.4.0"
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubelet/lib/systemd/system/kubelet.service" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /etc/systemd/system/kubelet.service
sudo mkdir -p /etc/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
kubelet
활성화 및 시작
systemctl enable --now kubelet
/usr
디렉터리를 읽기 전용 파일시스템으로 마운트한다.
클러스터를 부트스트랩하기 전에, 쓰기 가능한 디렉터리를 구성하기 위한 추가 단계를 수행해야 한다.
쓰기 가능한 디렉터리를 설정하는 방법을 알아 보려면 Kubeadm 문제 해결 가이드를 참고한다.
kubelet은 이제 kubeadm이 수행할 작업을 알려 줄 때까지 크래시루프(crashloop) 상태로 기다려야 하므로 몇 초마다 다시 시작된다.
cgroup 드라이버 구성
컨테이너 런타임과 kubelet은 "cgroup 드라이버"라는 속성을 갖고 있으며, cgroup 드라이버는 리눅스 머신의 cgroup 관리 측면에 있어서 중요하다.
컨테이너 런타임과 kubelet의 cgroup 드라이버를 일치시켜야 하며, 그렇지 않으면 kubelet 프로세스에 오류가 발생한다.
더 자세한 사항은 cgroup 드라이버 설정하기를 참고한다.
문제 해결
kubeadm에 문제가 있는 경우, 문제 해결 문서를 참고한다.
다음 내용
2 - kubeadm API로 컴포넌트 사용자 정의하기
이 페이지는 kubeadm이 배포하는 컴포넌트(component)들을 사용자 정의하는 방법을 다룬다. 컨트롤 플레인 컴포넌트에
대해서는 Cluster Configuration
구조에서 플래그를 사용하거나 노드당 패치를 사용할 수 있다. kubelet과
kube-proxy의 경우, KubeletConfiguration
과 KubeProxyConfiguration
을 각각 사용할 수 있다.
이 모든 옵션이 kubeadm 구성 API를 통해 가용하다. 구성의 각 필드 상세 사항은 API 참조 페이지에서 찾아볼 수 있다.
kube-system/coredns
컨피그맵을 수동으로
패치하고, 그 이후에 CoreDNS 파드를 다시 생성해야 한다. 또는,
기본 CoreDNS 디플로이먼트를 생략하고 자체 변형(variant)을 배포할 수 있다.
더 자세한 사항은 kubeadm에서 초기화 단계 사용하기을 참고한다.
Kubernetes v1.12 [stable]
ClusterConfiguration
의 플래그로 컨트롤 플레인 사용자 정의하기
kubeadm의 ClusterConfiguration
오브젝트는 API 서버, 컨트롤러매니저, 스케줄러, Etcd와 같은 컨트롤 플레인 컴포넌트에 전달되는
기본 플래그를 사용자가 덮어쓸 수 있도록 노출한다.
이 컴포넌트는 다음 구조체를 사용하여 정의된다.
apiServer
controllerManager
scheduler
etcd
이 구조체들은 공통 필드인 extraArgs
를 포함하며, 이 필드는 키: 값
쌍으로 구성된다.
컨트롤 플레인 컴포넌트를 위한 플래그를 덮어쓰려면 다음을 수행한다.
- 사용자 구성에 적절한
extraArgs
필드를 추가한다. extraArgs
필드에 플래그를 추가한다.kubeadm init
에--config <CONFIG YAML 파일>
파라미터를 추가해서 실행한다.
kubeadm config print init-defaults
를 실행하고 원하는 파일에 출력을
저장하여 기본값들로 구성된 ClusterConfiguration
오브젝트를 생성할 수 있다.
ClusterConfiguration
오브젝트는 현재 kubeadm 클러스터에서 전역(global)으로 사용된다. 즉, 사용자가 추가하는 모든 플래그는
다른 노드에 있는 동일한 컴포넌트에도 모두 적용될 것이다. 다른 노드에서
컴포넌트별로 개별 구성을 적용하려면 패치를 사용하면 된다.
--foo
를 여러 번 전달하는 것은 현재 지원하지 않는다.
이 문제를 해결하려면 패치를 사용해야 한다.
APIServer 플래그
자세한 내용은 kube-apiserver 레퍼런스 문서를 확인한다.
사용 예시:
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
apiServer:
extraArgs:
anonymous-auth: "false"
enable-admission-plugins: AlwaysPullImages,DefaultStorageClass
audit-log-path: /home/johndoe/audit.log
컨트롤러매니저 플래그
자세한 내용은 kube-controller-manager 레퍼런스 문서를 확인한다.
사용 예시:
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
controllerManager:
extraArgs:
cluster-signing-key-file: /home/johndoe/keys/ca.key
deployment-controller-sync-period: "50"
스케줄러 플래그
자세한 내용은 kube-scheduler 레퍼런스 문서를 확인한다.
사용 예시:
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.16.0
scheduler:
extraArgs:
config: /etc/kubernetes/scheduler-config.yaml
extraVolumes:
- name: schedulerconfig
hostPath: /home/johndoe/schedconfig.yaml
mountPath: /etc/kubernetes/scheduler-config.yaml
readOnly: true
pathType: "File"
Etcd 플래그
자세한 사항은 etcd 서버 문서를 확인한다.
사용 예시:
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
etcd:
local:
extraArgs:
election-timeout: 1000
패치를 통해 컨트롤 플레인 사용자 정의하기
Kubernetes v1.22 [beta]
Kubeadm을 사용하면 패치 파일이 있는 디렉토리를 개별 노드에 대한 InitConfiguration
과 JoinConfiguration
에
전달할 수 있다. 이 패치는 컨트롤 플레인 컴포넌트 메니패스트가 디스크에 기록되기 전에
최종 사용자 정의 단계로 사용될 수 있다.
--config <YOUR CONFIG YAML>
을 사용하여 이 파일을 kubeadm init
에 전달할 수 있다.
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
patches:
directory: /home/user/somedir
kubeadm init
의 경우, ---
로 구분된 ClusterConfiguration
과 InitConfiguration
을 모두
포함하는 파일을 전달할 수 있다.
--config <YOUR CONFIG YAML>
을 사용하여 이 파일을 kubeadm join
에 전달할 수 있다.
apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration
nodeRegistration:
patches:
directory: /home/user/somedir
디렉토리는 target[suffix][+patchtype].extension
형태의 파일을 포함해야 한다.
예를 들면, kube-apiserver0+merge.yaml
또는 단순히 etcd.json
의 형태이다.
target
은kube-apiserver
,kube-controller-manager
,kube-scheduler
그리고etcd
중 하나가 될 수 있다.patchtype
은strategic
,merge
그리고json
중 하나가 될 수 있으며 kubectl에서 지원하는 패치 형식을 준수해야 한다.patchtype
의 기본값은strategic
이다.extension
은json
또는yaml
중 하나여야 한다.suffix
는 어떤 패치가 먼저 적용되는지를 결정하는 데 사용할 수 있는 영숫자 형태의 선택적 문자열이다.
kubeadm upgrade
를 사용하여 kubeadm 노드를 업그레이드하는 경우, 업그레이드 이후에도
사용자 정의를 유지하려면 동일한 패치를 다시 제공해야 한다. 이는 동일한 디렉토리로 지정된 --patches
플래그를 사용하여 처리할 수 있다. kubeadm upgrade
는 동일 목적으로 재사용할 수 있는 구성
API 구조를 현재는 지원하지 않는다.
kubelet 사용자 정의하기
kubelet을 사용자 정의하려면, KubeletConfiguration
을 동일한 구성 파일 내에서 ---
로 구분된 ClusterConfiguration
이나 InitConfiguration
다음에 추가하면
된다. 그런 다음 kubeadm init
에 해당 파일을 전달한다.
KubeletConfiguration
을 적용한다. 노드별 설정을
적용하려면 kubelet 플래그를 덮어쓰기(overrides)로 사용하여, InitConfiguration
및
JoinConfiguration
모두에서 지원되는 nodeRegistration.kubeletExtraArgs
에 전달할 수 있다.
일부 kubelet 플래그는 더 이상 사용되지 않는다(deprecated). 따라서 사용하기 전에 kubelet 참조 문서를 통해
상태를 확인해야 한다.
자세한 사항은 kubeadm을 통해 클러스터의 각 kubelet 구성하기에서 살펴본다.
kube-proxy 사용자 정의하기
kube-proxy를 사용자 정의하려면, KubeProxyConfiguration
을 ---
로 구분된 ClusterConfiguration
이나 InitConfiguration
다음에 두고 kubeadm init
에 전달하면 된다.
자세한 사항은 API 참조 페이지에서 살펴볼 수 있다.
KubeProxyConfiguration
이 클러스터의 모든 kube-proxy 인스턴스에 적용된다는 것을 의미한다.
3 - 고가용성 토폴로지 선택
이 페이지는 고가용성(HA) 쿠버네티스 클러스터의 토플로지를 구성하는 두 가지 선택 사항을 설명한다.
다음과 같이 HA 클러스터를 구성할 수 있다.
- etcd 노드와 컨트롤 플레인 노드를 함께 위치시키는 중첩된(stacked) 컨트롤 플레인 노드 방식
- etcd와 컨트롤 플레인이 분리된 노드에서 운영되는 외부 etcd 노드 방식
HA 클러스터를 구성하기 전에 각 토플로지의 장단점을 주의 깊게 고려해야 한다.
중첩된 etcd 토플로지
중첩된 HA 클러스터는 etcd에서 제공하는 분산 데이터 저장소 클러스터를, 컨트롤 플레인 구성 요소를 실행하는 kubeadm으로 관리되는 노드에 의해서 형성된 클러스터 상단에 중첩하는 토플로지이다.
각 컨트롤 플레인 노드는 kube-apiserver
, kube-scheduler
, kube-controller-manager
인스턴스를 운영한다.
kube-apiserver
는 로드 밸런서를 이용하여 워커 노드에 노출되어 있다.
각 컨트롤 플레인 노드는 지역 etcd 맴버를 생성하고
이 etcd 맴버는 오직 해당 노드의 kube-apiserver
와 통신한다.
비슷한 방식이 지역의 kube-controller-manager
와 kube-scheduler
에도 적용된다.
이 토플로지는 컨트롤 플레인과 etcd 맴버가 같은 노드에 묶여 있다. 이는 외부 etcd 노드의 클러스터를 구성하는 것보다는 단순하며 복제 관리도 간단하다.
그러나 중첩된 클러스터는 커플링에 실패할 위험이 있다. 한 노드가 다운되면 etcd 맴버와 컨트롤 플레인을 모두 잃어버리고, 중복성도 손상된다. 더 많은 컨트롤 플레인 노드를 추가하여 이 위험을 완화할 수 있다.
그러므로 HA 클러스터를 위해 최소 3개인 중첩된 컨트롤 플레인 노드를 운영해야 한다.
이는 kubeadm의 기본 토플로지이다. 지역 etcd 맴버는
kubeadm init
와 kubeadm join --control-plane
을 이용할 때에 컨트롤 플레인 노드에 자동으로 생성된다.
외부 etcd 토플로지
외부 etcd를 이용하는 HA 클러스터는 etcd로 제공한 분산된 데이터 스토리지 클러스터가 컨트롤 플레인 구성 요소를 운영하는 노드로 형성하는 클러스터의 외부에 있는 토플로지이다.
중첩된 etcd 토플로지와 유사하게, 외부 etcd 토플로지에 각 컨트롤 플레인 노드는 kube-apiserver
, kube-scheduler
, kube-controller-manager
의 인스턴스를 운영한다. 그리고 kube-apiserver
는 로드 밸런서를 이용하여 워커노드에 노출한다. 그러나 etcd 맴버는 분리된 호스트에서 운영되고, 각 etcd 호스트는 각 컨트롤 플레인 노드의 kube-apiserver
와 통신한다.
이 토플로지는 컨트롤 플레인과 etcd 맴버를 분리한다. 이는 그러므로 컨트롤 플레인 인스턴스나 etcd 맴버를 잃는 충격이 덜하고, 클러스터 중복성에 있어 중첩된 HA 토플로지만큼 영향을 미치지 않는다.
그러나, 이 토플로지는 중첩된 토플로지에 비해 호스트 개수가 두배나 필요하다. 이 토플로지로 HA 클러스터를 구성하기 위해서는 최소한 3개의 컨트롤 플레인과 3개의 etcd 노드가 필요하다.