포스트

[K8S Deploy Study by Gasida] - Kubespray offline 설치 - 3 k8s 설치

[K8S Deploy Study by Gasida] - Kubespray offline 설치 - 3 k8s 설치

오프라인(폐쇄망) 환경에서 Kubespray를 사용해 Kubernetes 클러스터를 설치하려면, 설치에 필요한 바이너리/컨테이너 이미지/Python 패키지/RPM(deb) 패키지까지 사전에 모두 다운로드해 내부에 제공할 수 있어야 한다.

이번 단계에서는 kubespray-offline 오픈소스 스크립트를 활용해 이 모든 패키지를 원클릭으로 다운로드하고, 오프라인 프로비저닝에 최적화된 형태로 세팅하는 과정을 진행한다.

디스크 용량 확보

K8s 컴포넌트, Calico, CoreDNS, 각종 유틸리티 컨테이너 이미지의 Tarball과, OS 패키지(BaseOS, AppStream 등)의 의존성 파일을 모두 다운로드하면 outputs/ 디렉터리에만 최소 수십 GB가 쌓이게 됩된다. 여유로운 작업과 향후 이미지 추가를 위해 / 파티션을 넉넉히 증설한다.

  • 기본 60G에서 120G로 증설
1
2
lsblk
df -hT /

repo clone & 전체 다운로드 (약 3.3GB / 17분)

오프라인 설치에 필요한 파일/이미지/패키지/리포 구성을 전부 outputs/ 아래로 만들어 둔다.

  • 이 작업은 반드시 인터넷 통신이 가능한 PC(혹은 DMZ 서버)에서 수행되어야 한다.
1
2
3
git clone https://github.com/kubespray-offline/kubespray-offline
cd kubespray-offline

  • 변수 정보 확인
    • config.sh에는 다운로드할 K8s 컴포넌트들의 버전이 정의되어 있다.
1
2
3
4
5
6
7
8
9
10
11
12
source ./config.sh
echo -e "kubespary $KUBESPRAY_VERSION"
echo -e "runc $RUNC_VERSION"
echo -e "containerd $CONTAINERD_VERSION"
echo -e "nercdtl $NERDCTL_VERSION"
echo -e "cni $CNI_VERSION"
echo -e "nginx $NGINX_VERSION"
echo -e "registry $REGISTRY_VERSION"
echo -e "registry_port: $REGISTRY_PORT"
echo -e "Additional container registry hosts: $ADDITIONAL_CONTAINER_REGISTRY_LIST"
echo -e "cpu arch: $IMAGE_ARCH"

1
./download-all.sh
  • download-all.sh 의 흐름 : 여러 스크립트를 순차 실행한다.
    • config.sh target-scripts/config.sh : 버전 변수 로드
    • precheck.sh : 환경 점검 (SELinux 및 런타임 체크)
    • prepare-pkg.sh : 의존 패키지(rsync, createrepo 등) 설치
    • prepare-py.sh : Python venv 생성 및 requirements.txt 설치
    • get-kubespray.sh : 지정된 버전의 Kubespray Tarball 확보 및 패치
    • pypi-mirror.sh Pip 패키지 미러(PEP 503 호환 인덱스) 생성
    • download-kubespray-files.sh : kubespray offline 목록(files.list, images.list) 생성 후 파일/이미지 다운로드
    • download-additional-containers.sh : nginx, registry 등 오프라인 서빙에 필요한 인프라 이미지 추가 다운로드
    • create-repo.sh : RPM 다운로드 및 의존성 리포지토리 생성(createrepo)
    • copy-target-scripts.sh : 다운로드 완료 후 outputs/에 설치/시작 스크립트 복사

버전이 바뀌면 대부분 이 단계에서 다운로드 대상이 달라지므로 버전 변수는 target-scripts/config.sh 에서 관리하는 게 핵심이다. 즉 버전 변경 시엔 config에서 바꾸고 다시 download-all을 해야한다.

precheck / 패키지 / python venv

precheck.sh

  • podman 외 런타임 사용 시 설치 여부 확인
  • RHEL7 + SELinux enforcing이면 중단(미지원)

prepare-pkgs.sh

  • 다운로드와 리포지토리 생성에 필요한 호스트 패키지(rsync, gcc, createrepo_c 등)를 설치
1
dnf install -y rsync gcc libffi-devel createrepo git podman createrepo_c

prepare-py.sh → venv.sh

~/.venv/<python버전>/ 경로에 venv를 생성하고, Kubespray 구동에 필요한 파이썬 패키지를 격리된 환경에 설치

1
pip install -U pip setuptools & pip install -r requirements.txt

kubespray 소스 확보(get-kubespray.sh)

KUBESPRAY_VERSION 변수를 기반으로 분기 처리한다.

  • 커밋 해시, master 또는 release-... 일 경우: Git Branch Clone
  • 일반 릴리즈 버전(예: v2.30.0)일 경우: GitHub에서 .tar.gz Tarball 다운로드
  • 다운로드 후 outputs/files/kubespray-<ver>.tar.gz로 저장하고, 압축을 풀어 필요한 커스텀 패치(Patch)를 적용한다.

PyPI 미러 만들기(pypi-mirror.sh)

오프라인 노드에서 pip를 쓰려면 wheel/sdist를 내부에 모아두고 index를 만들어야 한다.

pypi-mirror.sh의 흐름

  • python-pypi-mirror 설치
  • kubespray requirements
    • binary 패키지(3.11, 3.12 대상) 다운로드
    • source 패키지 다운로드
    • pip/setuptools/wheel 등 추가 다운로드
  • pypi-mirror create 로 HTML 인덱스 생성

kubespray offline 목록 생성 + 파일/이미지 다운로드

download-kubespray-files.sh는 kubespray repo 안의contrib/offline/generate_list.sh 를 실행해서 files.list, images.list 를 만든다.

  • outputs/files/files.list
    • kubeadm/kubelet/kubectl,etcd, cni, runc, containerd, nerdctl 등 URL 목록
  • outputs/images/images.list
    • 필요한 컨테이너 이미지 목록
  • files.list
    • 등록된 URL들을 curl로 다운로드
  • images.list
    • download-images.sh로 pull & save(압축) 수행
  • download-additional-containers.shimagelists/*.txt 기반으로 nginx/registry 같은 추가 이미지도 다운로드

로컬 repo 생성(create-repo.sh)

RHEL일 경우

  • scripts/create-repo-rhel.sh 실행
    • dnf download --resolve --alldeps ...
    • outputs/rpms/local/ 에 RPM 복사
  • createrepo 실행해 repodata를 생성한다.

참고: /bin/rm outputs/rpms/local/*.i686.rpm 같은 메시지는
i686 RPM이 없어서 “지울 게 없다”는 뜻이라 보통 무시해도 됨.

download-all 결과물 확인

다운로드 완료 후 outputs/ 용량은 약 3.3GB정도이다.

outputs/ 의 구조

  • files/
    • kubeadm/kubelet/kubectl, containerd 등 바이너리
  • images/
    • 컨테이너 이미지 tar.gz
  • pypi/
    • pip 패키지 (index.html, *.whl, *.tar.gz)
  • rpms/
    • dnf repo
  • playbook/
    • 오프라인 repo 설정용 role/playbook
  • 기타 설치 스크립트
    • setup-*, start-*, install-containerd.sh

outputs로 이동 후 containerd 설치 + 이미지 로드

1
2
cd /root/kubespray-offline/outputs
./setup-container.sh

setup-container.sh의 역할

  • install-containerd.sh 실행 (로컬 files에서 runc/containerd/nerdctl/cni 설치)
  • nginx/registry 이미지 tar.gz를 nerdctl로 load

  • 확인
1
2
3
4
which runc && runc --version
which containerd && containerd --version
which nerdctl && nerdctl --version
nerdctl images

nginx 기동 (files/images/pypi/rpms 제공)

1
./start-nginx.sh

nginx는 --network host 로 뜨고 outputs/ 전체를 /usr/share/nginx/html로 마운트해서 웹서버로 제공한다.

디렉터리 목록이 보이게 하려면 nginx-default.conf의 아래 옵션을 추가

  • autoindex on;
  • autoindex_exact_size off;
  • autoindex_localtime on;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat << EOF > nginx-default.conf 
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        # index  index.html index.htm;

        autoindex on;                 # 디렉터리 목록 표시
        autoindex_exact_size off;     # 파일 크기 KB/MB/GB 단위로 보기 좋게
        autoindex_localtime on;       # 서버 로컬 타임으로 표시
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # Force sendfile to off
    sendfile off;     
}
EOF

오프라인 repo / pip mirror 시스템 설정

1
./setup-offline.sh

RHEL 계열

  • /etc/yum.repos.d/*.repo.original로 바꿔 비활성화
  • /etc/yum.repos.d/offline.repo 생성
    • baseurl=http://localhost/rpms/local/

pip

  • ~/.config/pip/pip.conf
    • index-url=http://localhost/pypi/
    • trusted-host=localhost
  • 설정 확인
1
2
3
dnf repolist 
cat /etc/yum.repos.d/offline.repo # offline.repo 파일 확인
cat ~/.config/pip/pip.conf # pypi mirror 설정 확인

Python 설치로 offline repo 동작 검증

1
./setup-py.sh

Rocky 10에서는 python 버전이 3.12로 자동 설정되는 구조

  • (예: pyver.sh에서 10* → PY=3.12).

오프라인 설치 옵션

  • --disablerepo=* --enablerepo=offline-repo

registry 기동 + 이미지 push

registry 기동

  • 기본 포트 : REGISTRY_PORT=35000
  • 저장 경로 : /var/lib/registry (volume mount)
1
./start-registry.sh
  • 확인
1
2
nerdctl ps
ss -tnlp | grep registry
  • 현재는 registry 서버 내부에 저장된 (컨테이너) 이미지 없는 상태
    1
    
    tree /var/lib/registry/
    
1
2
curl 192.168.10.10:5001/metrics
curl 192.168.10.10:5001/debug/pprof/

`

이미지 load & push

1
./load-push-all-images.sh
1
vi load-push-all-images.sh

1
image might be filtered out (Hint: set --platform=... or --all-platforms)

ARM64 환경에서 tar에 멀티 플랫폼이 섞여 있으면 발생할 수 있어서, load 시에nerdctl load --all-platforms -i <image.tar.gz>를 쓰도록 스크립트를 수정해서 해결한다.

정상적으로 push 후에는 localhost:35000/<repo>:<tag> 형태로 레지스트리에 올라간다.

  • kube-proxy 컨테이너가 localhost:35000 과 registry.k8s.io 로 push 된 상태 확인
1
2
3
nerdctl images | grep -i kube-proxy
nerdctl images | grep localhost
nerdctl images | grep localhost | wc -l

  • 카탈로그 / 태그 확인
1
2
3
4
5
curl -s http://localhost:35000/v2/_catalog | jq
curl -s http://localhost:35000/v2/kube-apiserver/tags
curl -s http://localhost:35000/v2/kube-apiserver/tags/list | jq
curl -s http://localhost:35000/v2/kube-apiserver/manifests/v1.34.3 | jq
tree /var/lib/registry/ -L 5

kubespray tarball 압축 해제

1
./extract-kubespray.sh
  • files/kubespray-<ver>.tar.gz를 풀어 kubespray-<ver>/ 생성
  • 버전별 patch 디렉터리가 있으면 적용
  • kubespary 저장소 압축 해제된 파일들 확인
1
tree kubespray-2.30.0/ -L 1

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.