베어메탈 Kubernetes 구성 과정
Terraform + Ansible + PXE + IPMI + MetalLB를 이용한 베어메탈 Kubernetes 구성 과정
이 구성은 다음과 같은 단계를 거칩니다:
Terraform: IPMI를 통해 베어메탈 서버를 프로비저닝하고 네트워크 설정을 구성합니다.
PXE (Preboot Execution Environment): 베어메탈 서버를 부팅하고 운영체제를 설치합니다.
Ansible: 운영체제 설치 후 Kubernetes 클러스터를 구성하고 MetalLB를 설정합니다.
MetalLB: Kubernetes 클러스터에 LoadBalancer 타입의 서비스를 제공합니다.
전제 조건:
Terraform, Ansible, IPMItool, PXE 서버가 이미 구성되어 있어야 합니다.
베어메탈 서버는 IPMI 인터페이스를 통해 접근 가능해야 합니다.
Kubernetes 설치에 필요한 모든 패키지 및 이미지는 PXE 서버에서 접근 가능해야 합니다.
MetalLB가 사용할 IP 주소 범위가 정의되어 있어야 합니다.
1. Terraform을 이용한 베어메탈 서버 프로비저닝 및 네트워크 설정
terraform.tf 파일 작성 (예시):
terraform {
required_providers {
ipmi = {
source = "bmc-toolbox/ipmi"
version = "~> 0.3.0"
}
}
}
provider "ipmi" {
endpoint = "bmc.example.com" # IPMI 엔드포인트
username = "admin" # IPMI 사용자 이름
password = "password" # IPMI 비밀번호
}
resource "ipmi_boot" "master1" {
host = "node1.example.com" # 베어메탈 서버 호스트 이름
boot_device = "network" # 네트워크 부팅 (PXE)
}
resource "null_resource" "network_config_master1" {
provisioner "local-exec" {
command = "sshpass -p 'password' ssh root@${self.triggers.ip} 'echo \"auto eth0\niface eth0 inet static\naddress 192.168.1.101\nnetmask 255.255.255.0\ngateway 192.168.1.1\ndns-nameservers 8.8.8.8 8.8.4.4\" > /etc/network/interfaces'"
interpreter = ["/bin/bash", "-c"]
triggers = {
ip = "192.168.1.101"
}
}
}
# 다른 노드에 대해서도 위와 같은 설정을 반복합니다.
terraform init: Terraform 초기화
terraform plan: 변경 사항 확인
terraform apply: 리소스 생성 및 적용 (IPMI 설정을 통해 PXE 부팅을 설정하고 네트워크 설정을 구성합니다.)
2. PXE를 이용한 운영체제 설치
PXE 서버 설정 파일 (/tftpboot/pxelinux.cfg/default) 수정 (예시):
DEFAULT menu.c32
TIMEOUT 300
ONTIMEOUT local
MENU TITLE PXE Boot Menu
LABEL ubuntu
MENU LABEL Install Ubuntu 20.04
KERNEL ubuntu/vmlinuz
APPEND initrd=ubuntu/initrd quiet splash -- ip=dhcp url=http://pxe_server_ip/preseed.cfg
LABEL local
MENU LABEL Boot from local disk
LOCALBOOT 0
베어메탈 서버 전원 켜기: IPMI를 통해 서버 전원을 켜고 PXE 부팅을 시작합니다.
ipmitool -I lanplus -H bmc.example.com -U admin -P password power on
운영체제 설치: PXE 서버에서 제공하는 Ubuntu 이미지를 통해 운영체제를 설치합니다. preseed.cfg 파일을 이용하여 자동 설치를 구성할 수 있습니다.
3. Ansible을 이용한 Kubernetes 클러스터 구성 및 MetalLB 설정
ansible.cfg 파일 설정 (예시):
[defaults]
inventory = hosts
remote_user = root
ask_pass = false
host_key_checking = false
hosts 파일 작성 (예시):
[masters]
node1.example.com ansible_host=192.168.1.101 ansible_ssh_pass=password
node2.example.com ansible_host=192.168.1.102 ansible_ssh_pass=password
node3.example.com ansible_host=192.168.1.103 ansible_ssh_pass=password
[workers]
node4.example.com ansible_host=192.168.1.104 ansible_ssh_pass=password
node5.example.com ansible_host=192.168.1.105 ansible_ssh_pass=password
[all:vars]
ansible_python_interpreter=/usr/bin/python3
playbook.yml 파일 작성 (예시 - kubeadm 사용):
---
- hosts: masters
become: true
tasks:
- name: Install required packages
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- software-properties-common
state: present
update_cache: yes
- name: Add Kubernetes apt key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add Kubernetes apt repository
apt_repository:
repo: deb https://apt.kubernetes.io/ kubernetes-xenial main
state: present
- name: Install kubeadm, kubelet, kubectl
apt:
name:
- kubeadm=1.23.0-00
- kubelet=1.23.0-00
- kubectl=1.23.0-00
state: present
update_cache: yes
notify:
- Restart kubelet
handlers:
- name: Restart kubelet
systemd:
name: kubelet
state: restarted
daemon_reload: yes
- hosts: masters[0] # master 노드 중 첫 번째 노드에서 실행
become: true
tasks:
- name: Initialize Kubernetes cluster
kubeadm:
state: present
config: /tmp/kubeadm-config.yaml # kubeadm 설정 파일 경로
- name: Create .kube directory
file:
path: /home/ubuntu/.kube
state: directory
mode: 0755
owner: ubuntu
group: ubuntu
- name: Copy kubeconfig to user's home directory
copy:
src: /etc/kubernetes/admin.conf
dest: /home/ubuntu/.kube/config
owner: ubuntu
group: ubuntu
mode: 0644
- name: Apply Calico network plugin
command: kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
become: true
become_user: ubuntu
- hosts: workers
become: true
tasks:
- name: Join Kubernetes cluster
command: kubeadm join 192.168.1.101:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> # kubeadm join 명령어
- hosts: masters
become: true
tasks:
- name: Apply MetalLB manifest
command: kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
- name: Apply MetalLB configuration
copy:
dest: /tmp/metallb-config.yaml
content: |
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.200-192.168.1.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
- name: Apply MetalLB configuration (kubectl apply)
command: kubectl apply -f /tmp/metallb-config.yaml
kubeadm-config.yaml 파일 작성 (예시):
apiVersion: kubeadhttp://m.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.23.0
controlPlaneEndpoint: "192.168.1.101:6443" # Master 노드의 IP 주소
networking:
podSubnet: "192.168.0.0/16"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ansible-playbook playbook.yml: Ansible playbook 실행 (Kubernetes 클러스터 구성 및 MetalLB 설정)
4. MetalLB를 이용한 LoadBalancer 서비스 확인
Kubernetes 클러스터에 LoadBalancer 타입의 서비스 배포:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
kubectl get svc my-service: 서비스 정보 확인 (EXTERNAL-IP 주소 확인)
EXTERNAL-IP 주소를 통해 서비스 접근 가능 여부 확인
주의 사항:
위 명령어는 예시이며, 실제 환경에 맞춰 설정을 변경해야 합니다.
보안을 위해 비밀번호를 안전하게 관리하고, SSH 키를 사용하는 것을 권장합니다.
Kubernetes 버전 및 패키지 버전은 사용하는 버전에 맞게 수정해야 합니다.
PXE 서버 및 네트워크 환경 설정을 꼼꼼히 확인해야 합니다.
Ansible playbook은 idempotent하게 작성하여 여러 번 실행해도 동일한 결과를 보장해야 합니다.
에러 발생 시 로그를 확인하고 문제 해결을 진행해야 합니다.
이 가이드라인은 베어메탈 Kubernetes 클러스터를 구성하는 데 필요한 기본적인 단계를 제공합니다. 실제 환경에서는 더 많은 설정 및 커스터마이징이 필요할 수 있습니다. 각 단계별로 자세한 정보를 검색하고 학습하여 성공적인 구축을 이루시길 바랍니다.
실제 환경 맞춤형 베어메탈 Kubernetes 구축 시나리오 (명령어 중심)
시나리오:
베어메탈 서버: 5대 (마스터 3대, 워커 2대)
IPMI 정보:
마스터 노드: bmc-master1.example.com, bmc-master2.example.com, bmc-master3.example.com
워커 노드: bmc-worker1.example.com, bmc-worker2.example.com
IPMI 사용자 이름: admin, 비밀번호: SecurePassword123
네트워크 정보:
IP 주소 범위: 192.168.10.101 - 192.168.10.105 (마스터: 101-103, 워커: 104-105)
게이트웨이: 192.168.10.1
DNS 서버: 8.8.8.8, 8.8.4.4
MetalLB IP 주소 풀: 192.168.10.200 - 192.168.10.250
운영체제: Ubuntu 22.04 LTS
Kubernetes 버전: 1.27.x
1. Terraform 설정:
terraform.tf 수정:
terraform {
required_providers {
ipmi = {
source = "bmc-toolbox/ipmi"
version = "~> 0.3.0"
}
}
}
provider "ipmi" {
endpoint = "bmc-master1.example.com" # Master 노드 IPMI 엔드포인트
username = "admin"
password = "SecurePassword123"
}
resource "ipmi_boot" "master1" {
host = "master1.example.com"
boot_device = "network"
}
resource "null_resource" "network_config_master1" {
provisioner "local-exec" {
command = "sshpass -p 'SecurePassword123' ssh root@${self.triggers.ip} 'echo \"auto eth0\niface eth0 inet static\naddress 192.168.10.101\nnetmask 255.255.255.0\ngateway 192.168.10.1\ndns-nameservers 8.8.8.8 8.8.4.4\" > /etc/netplan/01-network-config.yaml && netplan apply'"
interpreter = ["/bin/bash", "-c"]
triggers = {
ip = "192.168.10.101"
}
}
}
# master2, master3, worker1, worker2 에 대해서도 위와 유사하게 설정합니다.
# provider 블록을 각 IPMI endpoint 에 대해 별도로 정의하거나, 루프를 사용하여 동적으로 생성할 수 있습니다.
provider "ipmi" {
alias = "master2"
endpoint = "bmc-master2.example.com" # Master 노드 IPMI 엔드포인트
username = "admin"
password = "SecurePassword123"
}
resource "ipmi_boot" "master2" {
provider = ipmi.master2
host = "master2.example.com"
boot_device = "network"
}
resource "null_resource" "network_config_master2" {
provisioner "local-exec" {
command = "sshpass -p 'SecurePassword123' ssh root@${self.triggers.ip} 'echo \"auto eth0\niface eth0 inet static\naddress 192.168.10.102\nnetmask 255.255.255.0\ngateway 192.168.10.1\ndns-nameservers 8.8.8.8 8.8.4.4\" > /etc/netplan/01-network-config.yaml && netplan apply'"
interpreter = ["/bin/bash", "-c"]
triggers = {
ip = "192.168.10.102"
}
}
}
# worker 들도 similar 하게 반복
terraform init: Terraform 초기화
terraform plan: 변경 사항 확인
terraform apply: 리소스 생성 및 적용
2. PXE 서버 설정:
Ubuntu 22.04를 위한 PXE 설정 파일 (/tftpboot/pxelinux.cfg/default) 수정:
DEFAULT menu.c32
TIMEOUT 300
ONTIMEOUT local
MENU TITLE PXE Boot Menu
LABEL ubuntu
MENU LABEL Install Ubuntu 22.04
KERNEL ubuntu/vmlinuz
APPEND initrd=ubuntu/initrd quiet splash -- ip=dhcp url=http://pxe_server_ip/preseed.cfg
LABEL local
MENU LABEL Boot from local disk
LOCALBOOT 0
preseed.cfg 파일 (자동 설치 설정): /var/www/html/preseed.cfg 에 위치한다고 가정
d-i debian-installer/locale string en_US
d-i console-setup/ask_vga boolean false
d-i keyboard-configuration/xkb-keymap select us
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string <hostname> # Ansible 에서 hostname 변경 예정
d-i netcfg/get_domain string example.com # Ansible 에서 domain 변경 예정
d-i netcfg/dhcp_failed boolean false
d-i netcfg/dhcp_options select Configure network manually
d-i netcfg/disable_autoconfig boolean true
d-i netcfg/confirm_static boolean true
d-i netcfg/get_ipaddress string <ipaddress> # Ansible 에서 IP 변경 예정
d-i netcfg/get_netmask string 255.255.255.0
d-i netcfg/get_gateway string 192.168.10.1
d-i netcfg/get_nameservers string 8.8.8.8,8.8.4.4
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-auto/choose_recipe select atomic
d-i grub-installer/only_debian boolean false
d-i grub-installer/with_other_os boolean true
d-i grub-installer/bootdev string default
d-i finish-install/reboot_in_progress note
IPMI를 사용하여 각 서버 전원 켜고 PXE 부팅:
ipmitool -I lanplus -H bmc-master1.example.com -U admin -P SecurePassword123 power on
(나머지 노드에 대해서도 반복)
3. Ansible 설정:
ansible.cfg:
[defaults]
inventory = hosts
remote_user = root
ask_pass = false
host_key_checking = false
hosts:
[masters]
master1.example.com ansible_host=192.168.10.101 ansible_ssh_pass=SecurePassword123
master2.example.com ansible_host=192.168.10.102 ansible_ssh_pass=SecurePassword123
master3.example.com ansible_host=192.168.10.103 ansible_ssh_pass=SecurePassword123
[workers]
worker1.example.com ansible_host=192.168.10.104 ansible_ssh_pass=SecurePassword123
worker2.example.com ansible_host=192.168.10.105 ansible_ssh_pass=SecurePassword123
[all:vars]
ansible_python_interpreter=/usr/bin/python3
kube_version=1.27.0-00
playbook.yml:
---
- hosts: all
become: true
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install required packages for kubernetes
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
state: present
- name: Add Kubernetes apt key
apt_key:
url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
state: present
- name: Add Kubernetes apt repository
apt_repository:
repo: deb https://apt.kubernetes.io/ kubernetes main
state: present
filename: kubernetes
- name: Install kubeadm, kubelet and kubectl
apt:
name:
- kubeadm={{ kube_version }}
- kubelet={{ kube_version }}
- kubectl={{ kube_version }}
state: present
update_cache: yes
notify:
- Restart kubelet
handlers:
- name: Restart kubelet
systemd:
name: kubelet
state: restarted
daemon_reload: yes
- hosts: masters[0] # master 노드 중 첫 번째 노드에서 실행
become: true
tasks:
- name: Initialize Kubernetes cluster
kubeadm:
state: present
config: kubeadm-config.yaml # 수정된 kubeadm-config.yaml 파일 사용
- name: Create .kube directory for user
file:
path: /home/ubuntu/.kube
state: directory
mode: 0755
owner: ubuntu
group: ubuntu
- name: Copy kubeconfig to user's home directory
copy:
src: /etc/kubernetes/admin.conf
dest: /home/ubuntu/.kube/config
owner: ubuntu
group: ubuntu
mode: 0644
- name: Install Calico CNI
command: kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml # Calico 버전 확인 및 업데이트
become: true
become_user: ubuntu
- name: Get join command
command: kubeadm token create --print-join-command
register: join_command
become: true
- hosts: workers
become: true
tasks:
- name: Join Kubernetes cluster
shell: "{{ hostvars['masters'][0]['join_command']['stdout'] }}" # 마스터 노드에서 생성된 join 명령어 사용
- hosts: masters
become: true
tasks:
- name: Apply MetalLB Manifests
command: kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
- name: Deploy metallb configuration
kubernetes.core.k8s:
state: present
definition:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.10.200-192.168.10.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
kubeadm-config.yaml:
apiVersion: kubeadhttp://m.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.27.0
controlPlaneEndpoint: "192.168.10.101:6443" # Master 노드 IP 주소 고정
networking:
podSubnet: "192.168.0.0/16"
serviceSubnet: "10.96.0.0/12"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ansible-playbook playbook.yml: Ansible playbook 실행
4. MetalLB 확인:
LoadBalancer 타입 서비스 배포 (kubectl apply -f my-service.yaml - 이전 예제와 동일)
kubectl get svc my-service -n default: 서비스 정보 확인 (EXTERNAL-IP 확인)
변경 사항 설명:
IPMI 정보 업데이트: 실제 IPMI 엔드포인트, 사용자 이름, 비밀번호로 변경했습니다.
네트워크 설정: IP 주소, 게이트웨이, DNS 서버 정보를 실제 네트워크 환경에 맞게 설정했습니다. netplan 을 사용하도록 변경.
preseed.cfg 업데이트: 자동 설치 설정 파일에서 IP, hostname 등을 Ansible 에서 변경하도록 설정
Kubernetes 버전: kube_version 변수를 사용하여 쉽게 버전을 변경할 수 있도록 했습니다.
Calico CNI 버전: Calico CNI 버전을 명시적으로 지정하고, 최신 버전을 사용하도록 업데이트했습니다.
Join 명령어: kubeadm token create 명령어를 사용하여 Join 명령어를 동적으로 생성하도록 변경했습니다.
MetalLB 설정: MetalLB IP 주소 풀을 실제 사용할 IP 주소 범위로 변경했습니다.
오류 처리: Ansible playbook에 오류 처리 로직을 추가하여 오류 발생 시 playbook 실행을 중단하도록 설정할 수 있습니다.
cgroup driver: kubelet 에 cgroupDriver: systemd 설정 추가
중요 고려 사항:
보안: SSH 키를 사용하여 비밀번호 노출을 최소화하고, 방화벽 설정을 통해 불필요한 포트를 차단하십시오.
Idempotency: Ansible playbook을 idempotent하게 작성하여 여러 번 실행해도 동일한 결과를 보장하도록 해야 합니다.
모니터링: Prometheus, Grafana 등을 사용하여 Kubernetes 클러스터 및 베어메탈 서버를 모니터링하십시오.
로그 관리: Elasticsearch, Fluentd, Kibana (EFK 스택) 등을 사용하여 로그를 수집하고 분석하십시오.
백업: etcd 데이터 및 애플리케이션 데이터를 정기적으로 백업하십시오.
이 시나리오와 명령어를 기반으로 실제 환경에 맞게 설정을 조정하고 테스트하여 안정적인 베어메탈 Kubernetes 클러스터를 구축하십시오. 각 설정 항목에 대한 자세한 내용은 관련 공식 문서를 참조하는 것이 좋습니다.
베어메탈 Kubernetes 구축 명령어 설정 항목 상세 시나리오
시나리오: (이전과 동일)
베어메탈 서버: 5대 (마스터 3대, 워커 2대)
IPMI 정보:
마스터 노드: bmc-master1.example.com, bmc-master2.example.com, bmc-master3.example.com
워커 노드: bmc-worker1.example.com, bmc-worker2.example.com
IPMI 사용자 이름: admin, 비밀번호: SecurePassword123
네트워크 정보:
IP 주소 범위: 192.168.10.101 - 192.168.10.105 (마스터: 101-103, 워커: 104-105)
게이트웨이: 192.168.10.1
DNS 서버: 8.8.8.8, 8.8.4.4
MetalLB IP 주소 풀: 192.168.10.200 - 192.168.10.250
운영체제: Ubuntu 22.04 LTS
Kubernetes 버전: 1.27.x
1. Terraform 설정 (terraform.tf):
terraform {} 블록:
required_providers {}: Terraform에서 사용할 Provider 정의.
ipmi {}: IPMI Provider 정의. source는 Provider 소스, version은 사용할 버전 지정.
source = "bmc-toolbox/ipmi": IPMI Provider의 공식적인 소스 위치 (Terraform Registry). bmc-toolbox 라는 조직에서 제공하는 ipmi provider 임을 명시.
version = "~> 0.3.0": 사용할 IPMI Provider 버전 지정. ~> 는 "0.3.0 이상, 0.4.0 미만"의 호환 가능한 버전을 의미. 버전을 명시적으로 지정하여 Terraform이 예상대로 동작하도록 보장.
provider "ipmi" {} 블록:
IPMI Provider의 설정 정보를 정의. 각 베어메탈 서버의 IPMI 인터페이스에 접속하기 위한 정보를 설정.
endpoint = "bmc-master1.example.com": 첫 번째 마스터 노드의 IPMI 엔드포인트 (IP 또는 호스트 이름). IPMI 인터페이스에 접속하기 위한 주소.
username = "admin": IPMI 사용자 이름. IPMI 인터페이스에 접속하기 위한 계정 이름.
password = "SecurePassword123": IPMI 비밀번호. IPMI 인터페이스에 접속하기 위한 계정 비밀번호. 주의: 실제 환경에서는 비밀번호를 Terraform 코드에 직접 저장하지 않고, 환경 변수 또는 Terraform Secrets 관리 시스템을 사용하는 것이 좋습니다.
alias = "master2": provider 블록의 별칭을 지정. 여러 개의 IPMI provider 설정을 구분하기 위해 사용.
resource "ipmi_boot" "master1" {} 블록:
IPMI를 사용하여 부팅 설정을 변경하는 Terraform 리소스 정의.
host = "master1.example.com": 베어메탈 서버의 호스트 이름. Terraform이 IPMI 명령을 수행할 대상 서버를 식별하는 데 사용.
boot_device = "network": 부팅 장치를 네트워크 (PXE)로 설정. 베어메탈 서버가 네트워크를 통해 부팅되도록 설정하여 PXE 서버에서 운영체제를 설치할 수 있도록 함.
provider = ipmi.master2: provider 블록에 지정한 별칭을 사용하여, 특정 provider 설정을 사용하도록 지정.
resource "null_resource" "network_config_master1" {} 블록:
운영체제 설치 후 네트워크 설정을 변경하는 Terraform 리소스 정의 (null_resource는 아무런 리소스도 생성하지 않고 Provisioner만 실행).
provisioner "local-exec" {}: 로컬 시스템에서 명령어를 실행하는 Provisioner. 이 경우, SSH를 통해 베어메탈 서버에 접속하여 네트워크 설정을 변경.
command = "sshpass -p 'SecurePassword123' ssh root@${self.triggers.ip} 'echo \"...\" > /etc/netplan/01-network-config.yaml && netplan apply'": SSH를 통해 베어메탈 서버에 접속하여 netplan 설정 파일을 변경하고 네트워크를 재시작하는 명령어.
sshpass -p 'SecurePassword123': SSH 비밀번호를 사용하여 SSH 접속을 자동화. 주의: 실제 환경에서는 SSH 키 기반 인증을 사용하는 것이 보안상 더 안전합니다.
ssh root@${self.triggers.ip}: root 사용자로 베어메탈 서버에 SSH 접속.
'echo \"...\" > /etc/netplan/01-network-config.yaml && netplan apply': 베어메탈 서버에서 실행될 명령어. netplan 설정 파일을 생성하고 적용하여 네트워크 설정을 변경.
auto eth0\niface eth0 inet static\naddress 192.168.10.101\nnetmask 255.255.255.0\ngateway 192.168.10.1\ndns-nameservers 8.8.8.8 8.8.4.4: 고정 IP 주소, 넷마스크, 게이트웨이, DNS 서버를 설정하는 netplan 설정 내용.
interpreter = ["/bin/bash", "-c"]: 명령어를 실행할 인터프리터 지정 (Bash).
triggers = {}: 리소스가 다시 생성되어야 하는 조건을 정의. ip 트리거가 변경되면 local-exec Provisioner가 다시 실행되어 네트워크 설정이 업데이트됩니다.
ip = "192.168.10.101": 베어메탈 서버의 IP 주소.
2. PXE 서버 설정 (/tftpboot/pxelinux.cfg/default):
DEFAULT menu.c32: PXE 부팅 메뉴를 표시하는 데 사용되는 기본 메뉴 모듈.
TIMEOUT 300: PXE 부팅 메뉴가 표시되는 시간 (초). 300초 동안 아무런 선택이 없으면 ONTIMEOUT에 지정된 동작이 수행됩니다.
ONTIMEOUT local: 지정된 시간 동안 아무런 선택이 없으면 로컬 디스크에서 부팅합니다.
MENU TITLE PXE Boot Menu: PXE 부팅 메뉴의 제목.
LABEL ubuntu: PXE 부팅 메뉴 항목 정의.
MENU LABEL Install Ubuntu 22.04: PXE 부팅 메뉴에 표시될 항목 이름.
KERNEL ubuntu/vmlinuz: 부팅에 사용될 커널 이미지 경로. PXE 서버의 /tftpboot 디렉토리 기준으로 상대 경로를 지정합니다.
APPEND initrd=ubuntu/initrd quiet splash -- ip=dhcp url=http://pxe_server_ip/preseed.cfg: 커널 파라미터를 지정.
initrd=ubuntu/initrd: 사용할 initrd (initial ramdisk) 이미지 경로.
quiet splash: 부팅 화면을 간소화하고 오류 메시지를 숨깁니다.
ip=dhcp: DHCP를 사용하여 IP 주소를 자동으로 할당받도록 설정.
url=http://pxe_server_ip/preseed.cfg: 자동 설치 설정을 위한 preseed 파일의 URL. pxe_server_ip는 PXE 서버의 IP 주소로 대체해야 합니다.
3. Ansible 설정:
ansible.cfg:
[defaults]: Ansible의 기본 설정을 정의하는 섹션.
inventory = hosts: 사용할 inventory 파일 지정.
remote_user = root: SSH 접속에 사용할 사용자 이름 (root).
ask_pass = false: SSH 비밀번호를 묻지 않도록 설정 (비밀번호는 inventory 파일에 저장).
host_key_checking = false: SSH 호스트 키 검사를 비활성화. 주의: 실제 환경에서는 SSH 호스트 키 검사를 활성화하고, 알려진 호스트 키를 사용하여 보안을 강화하는 것이 좋습니다.
hosts:
Ansible이 관리할 대상 호스트 목록과 접속 정보를 정의하는 inventory 파일.
[masters]: 마스터 노드 그룹 정의.
master1.example.com ansible_host=192.168.10.101 ansible_ssh_pass=SecurePassword123: 마스터 노드 호스트 이름, IP 주소, SSH 비밀번호를 정의.
ansible_host: 접속할 IP 주소.
ansible_ssh_pass: SSH 비밀번호. 주의: 실제 환경에서는 SSH 키 기반 인증을 사용하는 것이 보안상 더 안전합니다.
[workers]: 워커 노드 그룹 정의 (마스터 노드와 동일한 형식).
[all:vars]: 모든 호스트에 적용될 변수 정의.
ansible_python_interpreter=/usr/bin/python3: 사용할 Python 인터프리터 경로 지정 (Python 3).
kube_version=1.27.0-00: 사용할 Kubernetes 버전 정의.
playbook.yml:
Ansible이 수행할 작업을 정의하는 playbook 파일.
- hosts: all: playbook을 실행할 대상 호스트 그룹 (all: 모든 호스트).
become: true: root 권한으로 명령어를 실행 (sudo).
tasks:: 수행할 작업 목록 정의.
- name: Update apt cache: APT 패키지 캐시 업데이트.
apt: update_cache=yes cache_valid_time=3600: apt 모듈을 사용하여 APT 패키지 캐시를 업데이트하고, 캐시 유효 시간을 3600초 (1시간)로 설정.
- name: Install required packages for kubernetes: Kubernetes 설치에 필요한 패키지 설치.
apt: name=[...] state=present: apt 모듈을 사용하여 지정된 패키지를 설치. state=present는 패키지가 설치되어 있는지 확인하고, 설치되어 있지 않으면 설치합니다.
- name: Add Kubernetes apt key: Kubernetes APT 저장소 키 추가.
apt_key: url=... state=present: apt_key 모듈을 사용하여 지정된 URL에서 APT 저장소 키를 추가.
- name: Add Kubernetes apt repository: Kubernetes APT 저장소 추가.
apt_repository: repo=... state=present filename=kubernetes: apt_repository 모듈을 사용하여 지정된 APT 저장소를 추가. filename은 저장소 파일 이름 지정.
- name: Install kubeadm, kubelet and kubectl: kubeadm, kubelet, kubectl 설치.
apt: name=[...] state=present update_cache=yes: apt 모듈을 사용하여 kubeadm, kubelet, kubectl을 지정된 버전으로 설치하고, APT 패키지 캐시를 업데이트합니다.
notify: Restart kubelet: kubeadm, kubelet, kubectl 설치 후 Restart kubelet 핸들러를 실행합니다.
handlers:: 특정 이벤트 발생 시 실행되는 작업 정의.
- name: Restart kubelet: kubelet 서비스 재시작.
systemd: name=kubelet state=restarted daemon_reload=yes: systemd 모듈을 사용하여 kubelet 서비스를 재시작하고, systemd 데몬을 다시 로드합니다.
- name: Initialize Kubernetes cluster: Kubernetes 클러스터 초기화.
kubeadm: state=present config=kubeadm-config.yaml: kubeadm 모듈을 사용하여 Kubernetes 클러스터를 초기화하고, kubeadm-config.yaml 파일을 사용하여 설정을 구성합니다.
- name: Create .kube directory for user: 사용자 홈 디렉토리에 .kube 디렉토리 생성.
file: path=... state=directory mode=... owner=... group=...: file 모듈을 사용하여 디렉토리를 생성하고, 권한, 소유자, 그룹을 설정합니다.
- name: Copy kubeconfig to user's home directory: kubeconfig 파일을 사용자 홈 디렉토리에 복사.
copy: src=... dest=... owner=... group=... mode=...: copy 모듈을 사용하여 파일을 복사하고, 권한, 소유자, 그룹을 설정합니다.
- name: Install Calico CNI: Calico CNI 설치.
command: kubectl apply -f ...: command 모듈을 사용하여 kubectl apply 명령어를 실행하여 Calico CNI를 설치합니다.
- name: Get join command: 워커 노드가 클러스터에 Join하기 위한 명령어 획득
command: kubeadm token create --print-join-command: command 모듈을 사용하여 kubeadm token create 명령어를 실행하고, 결과를 join_command 변수에 등록합니다.
- name: Join Kubernetes cluster: Kubernetes 클러스터에 Join.
shell: "{{ hostvars['masters'][0]['join_command']['stdout'] }}": shell 모듈을 사용하여 마스터 노드에서 획득한 Join 명령어를 실행하여 워커 노드를 클러스터에 Join합니다.
- name: Apply MetalLB Manifests: MetalLB 매니페스트 적용.
command: kubectl apply -f ...: command 모듈을 사용하여 kubectl apply 명령어를 실행하여 MetalLB 매니페스트를 적용합니다.
- name: Deploy metallb configuration: MetalLB 설정 배포.
kubernetes.core.k8s: state=present definition=...: kubernetes.core.k8s 모듈을 사용하여 MetalLB 설정을 Kubernetes 클러스터에 배포합니다.
kubeadm-config.yaml:
kubeadm init 명령어에 사용될 설정 파일.
apiVersion: kubeadhttp://m.k8s.io/v1beta3: 사용할 kubeadm API 버전.
kind: ClusterConfiguration: 설정 종류를 클러스터 구성으로 지정.
kubernetesVersion: v1.27.0: Kubernetes 버전 지정.
controlPlaneEndpoint: "192.168.10.101:6443": Control Plane 엔드포인트 지정 (마스터 노드의 IP 주소와 API 서버 포트).
networking:: 네트워크 관련 설정.
podSubnet: "192.168.0.0/16": Pod 네트워크 CIDR 블록 지정 (Calico CNI에서 사용).
serviceSubnet: "10.96.0.0/12": Service 네트워크 CIDR 블록 지정.
apiVersion: kubelet.config.k8s.io/v1beta1: 사용할 kubelet API 버전
kind: KubeletConfiguration: Kubelet 설정 종류 지정
cgroupDriver: systemd: 사용할 cgroup 드라이버 지정. Docker나 containerd 와 같은 컨테이너 런타임이 systemd cgroup 드라이버를 사용하도록 구성.
apiVersion: kubeproxy.config.k8s.io/v1alpha1: 사용할 kubeproxy API 버전
kind: KubeProxyConfiguration: KubeProxy 설정 종류 지정
mode: "ipvs": KubeProxy 모드를 IPVS로 지정. IPVS는 iptables보다 더 나은 성능을 제공합니다.
4. MetalLB 설정:
MetalLB 매니페스트 적용 (kubectl apply -f ...): MetalLB를 Kubernetes 클러스터에 배포합니다.
MetalLB 설정 배포 (Ansible playbook의 kubernetes.core.k8s 모듈): MetalLB IP 주소 풀을 정의하고, L2Advertisement를 생성하여 MetalLB가 LoadBalancer 서비스를 광고할 수 있도록 합니다.
이러한 설정 항목들을 실제 환경에 맞게 조정하고, 각 단계별로 테스트하여 안정적인 베어메탈 Kubernetes 클러스터를 구축하십시오.