Kubernetes 내부망 설치 - RedHat 버전

장쿠배·2025년 6월 14일

kubernetes

목록 보기
6/6

환경 정보

  • Bastion Host: 192.168.31.165, 192.168.56.165 (외부망 접속 가능)
  • Registry Node: 192.168.56.159 (프라이빗 레지스트리 전용)
  • Master Node: 192.168.56.160
  • Worker Node: 192.168.56.161
  • OS: Rocky Linux 9.6
  • CNI: Cilium

STEP 1: Bastion Host 작업 (192.168.31.165 또는 192.168.56.165)

1.1 필수 RPM 패키지 다운로드

# 작업 디렉토리 생성
mkdir -p ~/k8s-packages
cd ~/k8s-packages

# 기본 의존성 패키지들 (Rocky Linux 9 기준)
dnf download --downloadonly --downloaddir=. \
  curl wget socat conntrack ebtables \
  bash-completion tree net-tools \
  ca-certificates gnupg2

# Docker/Containerd 관련
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf download --downloadonly --downloaddir=. \
  docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Kubernetes 관련 (Rocky Linux 9 용)
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.32/rpm/repodata/repomd.xml.key
EOF

dnf download --downloadonly --downloaddir=. \
  kubelet-1.32.0 kubeadm-1.32.0 kubectl-1.32.0 cri-tools kubernetes-cni

# 패키지 압축
tar -czf k8s-packages.tar.gz *.rpm

echo "📦 다운로드된 RPM 패키지들:"
ls -la *.rpm
echo ""
echo "패키지 총 크기:"
du -h k8s-packages.tar.gz

1.2 Docker 설치 및 이미지 다운로드

# Docker 설치 (Bastion Host에서만)
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
# 로그아웃 후 재로그인 필요

# 이미지 저장 디렉토리 생성
mkdir -p ~/k8s-images
cd ~/k8s-images

# Kubernetes 핵심 이미지들
KUBERNETES_VERSION="v1.32.0"
IMAGES=(
  "registry.k8s.io/kube-apiserver:${KUBERNETES_VERSION}"
  "registry.k8s.io/kube-controller-manager:${KUBERNETES_VERSION}"
  "registry.k8s.io/kube-scheduler:${KUBERNETES_VERSION}"
  "registry.k8s.io/kube-proxy:${KUBERNETES_VERSION}"
  "registry.k8s.io/pause:3.10"
  "registry.k8s.io/pause:3.8"
  "registry.k8s.io/coredns/coredns:v1.11.3"
  "registry.k8s.io/etcd:3.5.16-0"
)

# Cilium 이미지들 (Calico 대신)
CILIUM_IMAGES=(
  "quay.io/cilium/cilium:v1.16.5"
  "quay.io/cilium/operator-generic:v1.16.5"
  "quay.io/cilium/hubble-relay:v1.16.5"
  "quay.io/cilium/hubble-ui:v0.13.1"
  "quay.io/cilium/hubble-ui-backend:v0.13.1"
  "quay.io/cilium/certgen:v0.2.0"
)

# 기타 유용한 이미지들
ADDITIONAL_IMAGES=(
  "quay.io/metallb/controller:v0.13.12"
  "quay.io/metallb/speaker:v0.13.12"
  "registry.k8s.io/ingress-nginx/controller:v1.12.0-beta.0"
  "registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.4"
  "registry.k8s.io/metrics-server/metrics-server:v0.7.2"
  "kubernetesui/dashboard:v2.7.0"
  "kubernetesui/metrics-scraper:v1.0.8"
  "nginx:1.27.2-alpine"
  "redis:latest"
  "registry:2"
)

# 모든 이미지 다운로드 및 저장
ALL_IMAGES=("${IMAGES[@]}" "${CILIUM_IMAGES[@]}" "${ADDITIONAL_IMAGES[@]}")

for image in "${ALL_IMAGES[@]}"; do
  echo "🔽 Pulling $image..."
  docker pull $image

  # 파일명 생성 (특수문자 제거)
  filename=$(echo $image | sed 's/[\/:]/-/g').tar
  docker save $image -o $filename
  echo "✅ Saved as $filename"
done

# 모든 이미지를 하나의 tar 파일로 압축
tar -czf k8s-images.tar.gz *.tar
echo "✅ All images compressed to k8s-images.tar.gz"

1.3 Cilium CLI 및 매니페스트 다운로드

# Cilium CLI 다운로드
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

# Cilium manifest 생성
curl -L https://raw.githubusercontent.com/cilium/cilium/v1.16.5/install/kubernetes/quick-install.yaml -o cilium-install.yaml

1.4 파일 전송 준비

# 전송할 파일들 확인
ls -la ~/k8s-packages/k8s-packages.tar.gz
ls -la ~/k8s-images/k8s-images.tar.gz
ls -la cilium-install.yaml

# 파일 크기 확인
du -h ~/k8s-packages/k8s-packages.tar.gz
du -h ~/k8s-images/k8s-images.tar.gz
du -h cilium-install.yaml

파일 전송

SCP (네트워크 연결 가능시)

# Bastion Host에서 Registry Node로 직접 전송
scp ~/k8s-packages/k8s-packages.tar.gz user@192.168.56.159:~/
scp ~/k8s-images/k8s-images.tar.gz user@192.168.56.159:~/
scp cilium-install.yaml user@192.168.56.159:~/

# Registry Node에서 다른 노드들로 분배
scp k8s-packages.tar.gz user@192.168.56.160:~/  # Master Node
scp k8s-packages.tar.gz user@192.168.56.161:~/  # Worker Node

STEP 2: Air-Gap 환경 공통 작업 (Master + Worker 모두)

2.1 호스트 설정

# /etc/hosts 파일 설정
sudo tee -a /etc/hosts <<EOF
192.168.56.159  k8s-registry
192.168.56.160  k8s-master
192.168.56.161  k8s-worker1
EOF

# 호스트명 설정 (각 노드에서 각각 실행)
# Master Node에서:
# sudo hostnamectl set-hostname k8s-master
# Worker Node에서:
# sudo hostnamectl set-hostname k8s-worker1

2.2 필수 패키지 설치

# 전송받은 패키지 압축 해제
tar -xzf k8s-packages.tar.gz

# RPM 패키지 설치 (Rocky Linux 방식)
sudo rpm -ivh *x86_64.rpm *noarch.rpm --force --nodeps

# 의존성 문제 발생 시 강제 설치
# sudo rpm -ivh *.rpm --force --nodeps
# sudo dnf install -y ./*.rpm --skip-broken

2.3 시스템 설정

# 스왑 비활성화
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# 스왑 비활성화 서비스 생성
sudo tee /etc/systemd/system/swapoff.service > /dev/null <<EOF
[Unit]
Description=Turn off all swap
DefaultDependencies=no
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/sbin/swapoff -a
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
WantedBy=graphical.target
EOF

sudo systemctl enable swapoff

# 방화벽 비활성화
sudo systemctl disable firewalld
sudo systemctl stop firewalld

# SELinux 비활성화
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# IP 포워딩 활성화
echo '1' | sudo tee /proc/sys/net/ipv4/ip_forward

# 커널 모듈 로드
sudo tee /etc/modules-load.d/containerd.conf > /dev/null <<EOF
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# sysctl 설정
sudo tee /etc/sysctl.d/99-kubernetes-cri.conf > /dev/null <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sudo sysctl --system

2.4 Docker 및 Containerd 설정

# Docker 설정
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo usermod -aG docker $USER

# Docker daemon.json 설정 (Private Registry 사용)
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "insecure-registries": ["192.168.56.159:5000"]
}
EOF

# Docker 서비스 시작
sudo systemctl daemon-reload
sudo systemctl enable docker
sudo systemctl start docker

# Containerd 설정
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml

# SystemdCgroup 활성화
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# Private Registry 설정을 위해 config.toml 수정
sudo sed -i 's|sandbox_image = "registry.k8s.io/pause:3.8"|sandbox_image = "192.168.56.159:5000/pause:3.10"|' /etc/containerd/config.toml

# Private Registry mirror 설정 추가
sudo tee -a /etc/containerd/config.toml <<EOF

[plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.56.159:5000"]
  endpoint = ["http://192.168.56.159:5000"]
[plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.56.159:5000".tls]
  insecure_skip_verify = true
EOF

sudo systemctl enable containerd
sudo systemctl restart containerd

# Kubelet 활성화
sudo systemctl enable kubelet

🗃️ STEP 3: Registry Node 구성 (192.168.56.159)

3.1 Docker 설치 및 Registry 구성

# Docker 설치 (Registry Node에서만)
tar -xzf k8s-packages.tar.gz
sudo rpm -ivh docker-ce*.rpm containerd.io*.rpm --force --nodeps
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER

# Docker daemon.json 설정
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "insecure-registries": ["192.168.56.159:5000"]
}
EOF

sudo systemctl restart docker

# Registry 데이터 디렉토리 생성
sudo mkdir -p /opt/registry/data
sudo chown -R $USER:$USER /opt/registry

# Registry 컨테이너 실행
docker run -d \
  --name registry \
  --restart=always \
  -p 5000:5000 \
  -v /opt/registry/data:/var/lib/registry \
  -e REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry \
  registry:2

# Registry 상태 확인
docker ps | grep registry
curl http://localhost:5000/v2/_catalog

3.2 이미지 로드 및 Push

# 이미지 압축 해제
tar -xzf k8s-images.tar.gz

# 모든 이미지 로드
for tar_file in *.tar; do
  echo "🔽 Loading $tar_file..."
  docker load -i $tar_file
done

REGISTRY_IP="192.168.56.159"

# Kubernetes 이미지들 태그 변경 및 Push
echo "📤 Pushing Kubernetes images..."
docker tag registry.k8s.io/kube-apiserver:v1.32.0 ${REGISTRY_IP}:5000/kube-apiserver:v1.32.0
docker tag registry.k8s.io/kube-controller-manager:v1.32.0 ${REGISTRY_IP}:5000/kube-controller-manager:v1.32.0
docker tag registry.k8s.io/kube-scheduler:v1.32.0 ${REGISTRY_IP}:5000/kube-scheduler:v1.32.0
docker tag registry.k8s.io/kube-proxy:v1.32.0 ${REGISTRY_IP}:5000/kube-proxy:v1.32.0
docker tag registry.k8s.io/pause:3.10 ${REGISTRY_IP}:5000/pause:3.10
docker tag registry.k8s.io/pause:3.8 ${REGISTRY_IP}:5000/pause:3.8
docker tag registry.k8s.io/coredns/coredns:v1.11.3 ${REGISTRY_IP}:5000/coredns:v1.11.3
docker tag registry.k8s.io/etcd:3.5.15-0 ${REGISTRY_IP}:5000/etcd:3.5.15-0

# Cilium 이미지들
echo "📤 Pushing Cilium images..."
docker tag quay.io/cilium/cilium:v1.16.5 ${REGISTRY_IP}:5000/cilium:v1.16.5
docker tag quay.io/cilium/operator-generic:v1.16.5 ${REGISTRY_IP}:5000/cilium-operator:v1.16.5
docker tag quay.io/cilium/hubble-relay:v1.16.5 ${REGISTRY_IP}:5000/hubble-relay:v1.16.5
docker tag quay.io/cilium/hubble-ui:v0.13.1 ${REGISTRY_IP}:5000/hubble-ui:v0.13.1
docker tag quay.io/cilium/hubble-ui-backend:v0.13.1 ${REGISTRY_IP}:5000/hubble-ui-backend:v0.13.1
docker tag quay.io/cilium/certgen:v0.2.0 ${REGISTRY_IP}:5000/cilium-certgen:v0.2.0

# 모든 이미지 Push
echo "🚀 Starting image push to private registry..."
docker push ${REGISTRY_IP}:5000/kube-apiserver:v1.32.0
docker push ${REGISTRY_IP}:5000/kube-controller-manager:v1.32.0
docker push ${REGISTRY_IP}:5000/kube-scheduler:v1.32.0
docker push ${REGISTRY_IP}:5000/kube-proxy:v1.32.0
docker push ${REGISTRY_IP}:5000/pause:3.10
docker push ${REGISTRY_IP}:5000/pause:3.8
docker push ${REGISTRY_IP}:5000/coredns:v1.11.3
docker push ${REGISTRY_IP}:5000/etcd:3.5.15-0
docker push ${REGISTRY_IP}:5000/cilium:v1.16.5
docker push ${REGISTRY_IP}:5000/cilium-operator:v1.16.5
docker push ${REGISTRY_IP}:5000/hubble-relay:v1.16.5
docker push ${REGISTRY_IP}:5000/hubble-ui:v0.13.1
docker push ${REGISTRY_IP}:5000/hubble-ui-backend:v0.13.1
docker push ${REGISTRY_IP}:5000/cilium-certgen:v0.2.0

echo "✅ All images pushed to registry successfully!"

# Registry 내용 확인
curl http://localhost:5000/v2/_catalog | jq .

⚙️ STEP 4: Master Node 구성 (192.168.56.160)

4.1 Kubeadm 설정 파일 생성

MASTER_IP="192.168.56.160"
REGISTRY_IP="192.168.56.159"

cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.32.0
imageRepository: ${REGISTRY_IP}:5000
networking:
  podSubnet: 10.244.0.0/16
controlPlaneEndpoint: "${MASTER_IP}:6443"
apiServer:
  certSANs:
  - "${MASTER_IP}"
  extraArgs:
    advertise-address: "${MASTER_IP}"
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
  criSocket: unix:///run/containerd/containerd.sock
  kubeletExtraArgs:
    pod-infra-container-image: ${REGISTRY_IP}:5000/pause:3.10
EOF

# Containerd 재시작
sudo systemctl restart containerd

4.2 클러스터 초기화

# Kubeadm으로 클러스터 초기화
sudo kubeadm init --config=kubeadm-config.yaml

# 성공 시 kubectl 설정
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 조인 토큰 저장 (워커 노드에서 사용)
kubeadm token create --print-join-command > worker-join-command.txt
echo "📝 Worker join command saved to worker-join-command.txt"

👥 STEP 5: Worker Node 작업 (192.168.56.161)

5.1 워커 노드 조인

# Master Node의 worker-join-command.txt 내용을 복사하여 실행
# 예시:
sudo kubeadm join 192.168.56.160:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash>

Cilium 에어갭 배포 완전 정리

1단계: 환경 준비

# === 환경 구성 ===
- Bastion Host: 192.168.56.159 (Private Registry 포함)
- Master Node: 192.168.56.160
- Worker Node: 192.168.56.161
- Registry: http://192.168.56.159:5000

2단계: 이미지 준비 (외부 → Bastion Host)

# === 외부 인터넷 환경에서 ===
# 필요한 이미지들 다운로드
docker pull quay.io/cilium/cilium:v1.16.5
docker pull quay.io/cilium/operator-generic:v1.16.5
docker pull quay.io/cilium/cilium-envoy:v1.30.8-xxxx

# tar 파일로 저장
docker save quay.io/cilium/cilium:v1.16.5 > cilium.tar
docker save quay.io/cilium/operator-generic:v1.16.5 > cilium-operator.tar
docker save quay.io/cilium/cilium-envoy:v1.30.8-xxxx > cilium-envoy.tar

# Bastion Host로 전송
scp *.tar root@192.168.56.159:/root/

🚀 3단계: Private Registry에 업로드

# === Bastion Host에서 ===
# 이미지 로드
docker load < cilium.tar
docker load < cilium-operator.tar
docker load < cilium-envoy.tar

# Private Registry용 태그 설정
docker tag quay.io/cilium/cilium:v1.16.5 192.168.56.159:5000/cilium:v1.16.5
docker tag quay.io/cilium/operator-generic:v1.16.5 192.168.56.159:5000/cilium-operator:v1.16.5
docker tag quay.io/cilium/cilium-envoy:v1.30.8-xxxx 192.168.56.159:5000/cilium-envoy:v1.30.8-xxxx

# Registry에 푸시
docker push 192.168.56.159:5000/cilium:v1.16.5
docker push 192.168.56.159:5000/cilium-operator:v1.16.5
docker push 192.168.56.159:5000/cilium-envoy:v1.30.8-xxxx

📄 4단계: Helm 차트로 매니페스트 생성

# === Bastion Host에서 ===
# Cilium Helm 차트 다운로드 (외부에서)
helm repo add cilium https://helm.cilium.io/
helm pull cilium/cilium --version 1.16.5
tar -xzf cilium-1.16.5.tgz

# 매니페스트 생성
cd cilium/
helm template cilium . \
  --namespace kube-system \
  --set image.repository=192.168.56.159:5000/cilium \
  --set image.tag=v1.16.5 \
  --set operator.image.repository=192.168.56.159:5000/cilium-operator \
  --set operator.image.tag=v1.16.5 \
  --set envoy.image.repository=192.168.56.159:5000/cilium-envoy \
  --set envoy.image.tag=v1.30.8-xxxx \
  > ../cilium-install.yaml

🔧 5단계: 매니페스트 수정

# === Bastion Host에서 ===
# SHA256 해시 제거 (호환성 문제 해결)
sed -i 's/@sha256:[a-f0-9]\{64\}//g' cilium-install.yaml

# 이미지 이름 통일 (generic → 실제 태그명)
sed -i 's/cilium-operator-generic:v1.16.5/cilium-operator:v1.16.5/g' cilium-install.yaml

# Public Registry 참조 제거
sed -i 's|quay.io/cilium/cilium-envoy|192.168.56.159:5000/cilium-envoy|g' cilium-install.yaml

🚀 6단계: 배포

# === Bastion Host → Master Node ===
scp cilium-install.yaml root@192.168.56.160:/root/

# === Master Node에서 ===
kubectl apply -f cilium-install.yaml

# 상태 확인
kubectl get pods -n kube-system
kubectl get nodes
  • ImagePullBackOff: Registry에 이미지 없음 → 업로드 필요
  • SHA256 불일치: sed -i 's/@sha256:[a-f0-9]{64}//g'로 해시 제거
  • DNS 타임아웃: Public Registry 참조 → Private Registry로 변경

🔧 STEP 6: 확인 및 문제 해결

6.1 클러스터 상태 확인

# Master Node에서 실행
kubectl get nodes
kubectl get pods --all-namespaces
kubectl cluster-info

# Cilium 연결 확인
kubectl exec -n kube-system -it ds/cilium -- cilium status --verbose

6.2 문제 해결

# 클러스터 초기화 실패 시 리셋
sudo kubeadm reset -f
sudo rm -rf /etc/kubernetes
sudo rm -rf /var/lib/etcd
sudo systemctl restart containerd
sudo systemctl restart kubelet

# 로그 확인
sudo journalctl -xeu kubelet
sudo journalctl -xeu containerd
sudo journalctl -xeu docker

# Private Registry 연결 테스트
curl -X GET http://192.168.56.159:5000/v2/_catalog

6.3 Rocky Linux 9.6 특이사항

  • yum 대신 dnf 사용
  • SELinux가 기본 활성화되어 있어 비활성화 필요
  • firewalld 서비스 비활성화 필요
  • systemd 기본 사용
profile
Kubernetes/AmazonAWS를 위한 나의 기록

0개의 댓글