이재홍의 언제나 최신 Kubernetes - Unit 6.3 Vagrantfile 살펴보기

저작권 안내
  • 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
  • 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.

로컬에서 Kubernetes 클러스터 구축하기

이재홍 http://www.pyrasis.com

Vagrantfile 살펴보기

이번에는 앞에서 실행했던 Vagrantfile의 내용을 살펴보겠습니다. 양이 많은 것 같지만 그렇게 복잡하지는 않습니다.

Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.boot_timeout = 3000

  config.vm.define "master" do |master|
    master.vm.box = "ubuntu/jammy64"
    master.vm.network "private_network", ip: "192.168.56.10"
    master.vm.hostname = "master"

    master.vm.provider "virtualbox" do |v|
      v.memory = 4096
      v.cpus = 4
    end

    master.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.10
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

OUTPUT_FILE=/vagrant/join.sh
rm -rf $OUTPUT_FILE
rm -rf /vagrant/.kube
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.56.10 --apiserver-advertise-address=192.168.56.10
sudo kubeadm token create --print-join-command > $OUTPUT_FILE
chmod +x $OUTPUT_FILE

mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
cp -R $HOME/.kube /vagrant/.kube
cp -R $HOME/.kube /home/vagrant/.kube
sudo chown -R vagrant:vagrant /home/vagrant/.kube
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl completion bash >/etc/bash_completion.d/kubectl
echo 'alias k=kubectl' >>/home/vagrant/.bashrc
    EOC
  end

  (1..3).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "ubuntu/jammy64"
      worker.vm.network "private_network", ip: "192.168.56.1#{i}"
      worker.vm.hostname = "worker#{i}"

      worker.vm.provider "virtualbox" do |v|
        v.memory = 2048
        v.cpus = 2
      end

      worker.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.1#{i}
EOF

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
      EOC
    end
  end
end

먼저 Vagrantfile의 첫 부분입니다(참고로 Vagrantfile은 Ruby 언어로 작성이 되어 있습니다). VagrantfileVagrant.configure("2") do |config|로 시작하며 그 아래에 각종 설정을 넣게 됩니다. 여기서 "2"Vagrant.configure 버전 2라는 뜻이며 가상머신을 2개 만들겠다는 뜻이 아닙니다.

Vagrant.configure("2") do |config|
  config.vm.boot_timeout = 3000
  • config.vm.boot_timeout: 가상머신 부팅 대기 시간입니다. 이 값을 짧게 설정하면 부팅이 끝나기 전에 vagrant up 명령이 실패할 수 있습니다.

이제 master 노드 설정 부분입니다. config.vm.define "master" do |master|으로 마스터 노드 정의하고 그 아래에 설정을 넣게 됩니다.

  config.vm.define "master" do |master|
    master.vm.box = "ubuntu/jammy64"
    master.vm.network "private_network", ip: "192.168.56.10"
    master.vm.hostname = "master"

    master.vm.provider "virtualbox" do |v|
      v.memory = 4096
      v.cpus = 4
    end
  • master.vm.box: Vagrant는 가상머신 이미지를 box라고 부릅니다. 여기서는 Ubuntu 22.04 버전인 "ubuntu/jammy64"를 사용하도록 설정했습니다.
  • master.vm.network: 네트워크 설정입니다. "private_network"로 내부 네트워크를 사용하도록 했고 master 노드의 IP 주소는 "192.168.56.10"으로 설정했습니다.
  • master.vm.hostname: 가상머신의 호스트 이름입니다. master 노드이므로 "master"로 설정했습니다.
  • master.vm.provider "virtualbox" do |v|: 우리는 가상머신 프로그램으로 VirtualBox를 사용하기로 했으므로 VirtualBox 관련 설정을 해줍니다.
    • v.memory: 가상머신의 메모리 크기입니다. 여기서는 4096(4Gi)을 설정했습니다.
    • v.cpus: 가상머신의 CPU 개수입니다. 여기서는 4개로 설정했습니다.

여기서부터는 provision이라고 해서 Vagrant가 가상머신을 생성한 뒤 실행할 스크립트를 정의하는 부분입니다. 이 부분의 내용이 많은데, 부분 부분 나눠서 설명하겠습니다.

master 노드의 provision 설정은 이렇게 시작합니다. master.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC에서 "0"은 provision의 이름, "shell"은 셸 스크립트, preserve_order: true는 실행 순서를 유지하겠다는 뜻입니다. privileged: true는 현재 스크립트를 root 권한으로 실행하겠다는 뜻입니다. 마지막으로 inline: <<-EOC 다음 줄부터 스크립트가 시작됩니다.

다음은 kubeadm 실행에 필요한 커널 모듈을 로딩하고, 커널 설정값을 변경하는 부분입니다.

cat <<-'EOF' >/etc/modules-load.d/kubernetes.conf
br_netfilter
EOF

sudo modprobe br_netfilter

cat <<-'EOF' >/etc/sysctl.d/kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system
  • br_netfilter: iptables를 사용하기 위해 필요한 커널 모듈입니다. 부팅할 때 로딩할 수 있도록 /etc/modules-load.d/kubernetes.conf 파일 안에도 넣어줍니다. 그리고 sudo modprobe br_netfilter 명령으로 br_netfilter 커널 모듈을 지금 즉시 로딩해줍니다.
  • net.ipv4.ip_forward = 1은 IPv4 포워딩 기능을 활성화합니다. net.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1은 컨테이너의 네트워크 패킷을 호스트의 iptables 설정에 따라 제어되도록 합니다. 부팅할 때 설정값을 반영할 수 있도록 /etc/sysctl.d/kubernetes.conf 파일 안에도 넣어줍니다. 그리고 sudo sysctl --system 명령을 실행하여 설정값을 지금 즉시 반영해줍니다.

kubelet 설정입니다. 이 Vagrantfile에서 생성한 VirtualBox 가상머신은 네트워크 인터페이스가 2개 생성됩니다. 여기서 master.vm.network "private_network", ip: "192.168.56.10"으로 생성한 두 번째 네트워크 인터페이스의 IP 주소인 192.168.56.10--node-ip에 설정해줍니다.

cat <<-'EOF' >/etc/default/kubelet
KUBELET_EXTRA_ARGS=--node-ip=192.168.56.10
EOF

containerd 설치 및 설정 부분입니다. 우리는 쿠버네티스의 컨테이너 런타임 인터페이스(CRI)로 containerd를 사용할 것이므로 다음과 같이 작성했습니다.

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd
sudo systemctl enable containerd
  • sudo apt update로 apt 패키지 목록을 업데이트해주고 sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates로 필요한 패키지들을 설치합니다.
  • sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg로 Docker 인증서를 설치하고, sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"로 apt 저장소 목록에 Docker 저장소를 추가해줍니다.
  • 다시 sudo apt update로 apt 패키지 목록을 업데이트해주고, sudo apt install -y containerd.iocontainerd를 설치합니다. 이 과정없이 sudo apt install -y containerd로 우분투에 내장된 containerd를 설치하면 kubeadm이 제대로 실행되지 않으므로 주의해야 합니다.
  • containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1로 containerd 기본 설정값을 만들어내고, sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.tomlSystemdCgrouptrue로 변경해줍니다. 우리는 쿠버네티스의 Cgroupssystemd를 사용할 것이기 때문입니다.
  • sudo systemctl restart containerd로 containerd 서비스를 재시작하여 바뀐 설정을 반영해주고, sudo systemctl enable containerd로 부팅했을 때 containerd 서비스가 실행되도록 설정해줍니다.

이 부분이 핵심입니다. kubeadm init으로 쿠버네티스 클러스터의 master 노드를 생성합니다.

OUTPUT_FILE=/vagrant/join.sh
rm -rf $OUTPUT_FILE
rm -rf /vagrant/.kube
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.56.10 --apiserver-advertise-address=192.168.56.10
sudo kubeadm token create --print-join-command > $OUTPUT_FILE
chmod +x $OUTPUT_FILE
  • OUTPUT_FILE=/vagrant/join.shkubeadm init 명령 실행 후 출력되는 kubeadm join 명령을 일일이 복사해서 붙여넣기 번거로우므로 스크립트 파일로 저장하기 위한 부분입니다. 특히 /vagrant 디렉터리는 Vagrant로 생성한 모든 가상머신에서 공유하는 디렉터리이며 Vagrantfile이 있는 로컬 폴더(디렉터리)와도 공유되는 곳입니다. rm -rf $OUTPUT_FILE로 이전 스크립트 파일을 삭제하고, rm -rf /vagrant/.kube로 이전 .kube 디렉터리도 삭제합니다.
  • sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --control-plane-endpoint=192.168.56.10 --apiserver-advertise-address=192.168.56.10으로 쿠버네티스 클러스터의 master 노드를 생성합니다.
    • --pod-network-cidr=10.244.0.0/16: 우리는 쿠버네티스 컨테이너 네트워크 인터페이스(CNI)로 flannel을 사용할 것이므로 --pod-network-cidr10.244.0.0/16로 설정해줍니다.
    • --control-plane-endpoint=192.168.56.10: 로컬 환경이라 도메인이 필요없으므로 제어 플레인 엔드포인트를 master 노드의 IP 주소 192.168.56.10으로 설정합니다.
    • --apiserver-advertise-address=192.168.56.10: apiserver 주소도 master 노드의 IP 주소 192.168.56.10으로 설정합니다.
  • kubeadm init 실행 후에도 kubeadm join 명령이 나오지만 스크립트 파일에 저장하기 위해 sudo kubeadm token create --print-join-command > $OUTPUT_FILE를 실행해줍니다. 그리고 chmod +x $OUTPUT_FILE로 스크립트 파일에 실행 권한을 부여합니다.

이제 클러스터 바깥에서 클러스터를 제어할 수 있도록 .kube 디렉터리와 설정파일을 만들어주고, CNI인 flannel을 설치합니다. 그리고 bash 자동 완성 설정과 kubectlk로 약칭(alias)을 만들어줍니다.

mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
cp -R $HOME/.kube /vagrant/.kube
cp -R $HOME/.kube /home/vagrant/.kube
sudo chown -R vagrant:vagrant /home/vagrant/.kube
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
kubectl completion bash >/etc/bash_completion.d/kubectl
echo 'alias k=kubectl' >>/home/vagrant/.bashrc
  • mkdir -p $HOME/.kube로 홈 디렉터리에 .kube 디렉터리를 생성합니다. 그리고 sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config/etc/kubernetes/ 안에 있는 admin.conf.kube 아래에 config 파일로 복사해줍니다. 마지막으로 sudo chown $(id -u):$(id -g) $HOME/.kube/configconfig 파일의 소유자와 그룹을 현재 사용자와 그룹으로 변경해줍니다. 이때 $HOME/root이고 사용자와 그룹은 root입니다. 이렇게 해야 kubectl을 실행하여 flannel을 설치할 수 있습니다.
  • 가상머신 바깥에서 .kube 디렉터리를 가져갈 수 있도록 cp -R $HOME/.kube /vagrant/.kube를 실행합니다.
  • root가 아닌 vagrant 일반 계정에서도 kubectl을 실행할 수 있도록 cp -R $HOME/.kube /home/vagrant/.kube을 실행하여 .kube 디렉터리를 복사하고 sudo chown -R vagrant:vagrant /home/vagrant/.kube로 소유자와 그룹을 vagrant로 변경합니다.
  • kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml를 실행하여 CNI flannel을 설치합니다. CNI는 여러 종류가 있지만 여기서는 flannel을 설치하겠습니다.
  • kubectl completion bash >/etc/bash_completion.d/kubectl를 실행하여 bash 자동 완성 설정을 해주고, echo 'alias k=kubectl' >>/home/vagrant/.bashrc를 실행하여 kubectlk로 약칭(alias)을 만들어줍니다.

다음은 worker 노드 부분입니다. worker 노드는 (1..3)으로 1부터 3까지 루프를 돌면서 노드 3개를 생성합니다.

  (1..3).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "ubuntu/jammy64"
      worker.vm.network "private_network", ip: "192.168.56.1#{i}"
      worker.vm.hostname = "worker#{i}"

      worker.vm.provider "virtualbox" do |v|
        v.memory = 2048
        v.cpus = 2
      end

      worker.vm.provision "0", type: "shell", preserve_order: true, privileged: true, inline: <<-EOC
  • worker.vm.box: master 노드와 마찬가지로 Ubuntu 22.04 버전인 "ubuntu/jammy64"를 사용하도록 설정했습니다.
  • worker.vm.network: 네트워크 설정입니다. "private_network"로 내부 네트워크를 사용하도록 했고 worker 노드의 IP 주소는 "192.168.56.1#{i}"로 설정해서 11부터 13까지 사용하도록 합니다.
  • worker.vm.hostname: 가상머신의 호스트 이름입니다. "worker#{i}"로 설정하여 worker1부터 3까지 사용하도록 합니다.
  • worker.vm.provider "virtualbox" do |v|: worker 가상머신의 VirtualBox 설정입니다.
    • v.memory: 가상머신의 메모리 크기입니다. 여기서는 2048(2Gi)을 설정했습니다.
    • v.cpus: 가상머신의 CPU 개수입니다. 여기서는 2개로 설정했습니다.
  • worker.vm.provision: join.sh 스크립트 생성 부분, kubeadm init으로 master 노드를 생성하는 부분, flannel을 설치하는 부분, .kube 디렉터리 복사 부분 등을 제외하면 스크립트는 master와 동일하게 containerdkubeadm을 설치합니다.

지금까지 Vagrantfile로 가상머신을 생성하는 부분과 쿠버네티스 클러스터를 생성하기 위한 스크립트들을 알아보았습니다. Vagrant 없이 수동으로 가상머신을 생성하고, 스크립트를 입력해도 동일하게 쿠버네티스 클러스터를 만들 수 있습니다.

다음 장에서는 이 쿠버네티스 클러스터에서 Nginx 디플로이먼트와 서비스를 생성한 뒤 인그레스도 설정해보겠습니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

2022-10-22