kubesrapy로 k8s offline 설치 - kubesrapy-offline 도구

진웅·2026년 2월 15일

k8s deploy

목록 보기
18/20

kubespray-offline 도구를 사용해서 외부망에서 필요한 파일을 모두 내려받고, 폐쇄망 내부에 로컬 레포지토리와 레지스트리를 구성한 뒤 클러스터를 배포하는 전체 과정을 정리했다.


작업 구조

크게 두 단계로 나뉜다.

  • 외부망(Online): 필요한 리소스를 모두 다운로드
  • 폐쇄망(Offline): 내부 서버 구성 후 클러스터 배포


사전 요구 사항

지원 OS

구분버전
RHEL / AlmaLinux / Rocky Linux9.x
Ubuntu22.04, 24.04

주의할 점은 Online Node와 Offline Target Node의 OS 종류와 버전이 반드시 같아야 한다는 것이다. 다르면 패키지 의존성 문제가 생긴다.

RHEL 8은 Kubespray 2.29.0부터 지원이 중단됐다.

하드웨어 권장 사양

구분최소 사양
Installer NodeRAM 4GB, Disk 50GB 이상
Target NodesRAM 2GB, vCPU 2개 이상

Phase 1 - 외부망: 리소스 다운로드

인터넷이 되는 리눅스 서버에서 진행한다.

config.sh 수정

먼저 config.sh를 열어 버전과 런타임 설정을 확인한다.

# config.sh

# 설치할 Kubespray 버전
KUBESPRAY_VERSION=${KUBESPRAY_VERSION:-2.30.0}

# 컨테이너 런타임 (RHEL 계열은 podman, Ubuntu는 docker 권장)
docker=${docker:-podman}

전체 다운로드 실행

$ ./download-all.sh

내부적으로 아래 순서로 동작한다.

  1. prepare-pkgs.sh - pip, podman 등 필요한 도구 설치
  2. get-kubespray.sh - 지정 버전의 Kubespray 소스코드 다운로드
  3. pypi-mirror.sh - Python 라이브러리(.whl) 다운로드
  4. download-kubespray-files.sh - 컨테이너 이미지 및 바이너리(kubectl, cni 등) 다운로드
  5. create-repo.sh - OS 패키지(RPM/Deb) 다운로드 및 로컬 레포 메타데이터 생성

완료되면 outputs/ 디렉토리에 모든 파일이 쌓인다.


Phase 2 - 파일 이관

outputs/ 디렉토리를 압축해서 폐쇄망 Installer Node로 옮긴다.

# 압축
$ tar czf kubespray-offline-outputs.tar.gz outputs/

# Installer Node에서 압축 해제
$ tar xzf kubespray-offline-outputs.tar.gz

USB나 망연계 솔루션을 통해 이동시키면 된다.


Phase 3 - 폐쇄망: 인프라 구성 및 배포

이제부터는 폐쇄망 Installer Node에서 진행한다.

로컬 인프라 구축

$ cd outputs
$ ./setup-all.sh

이 스크립트가 하는 일은 다음과 같다.

  1. setup-container.sh - containerd 설치, Nginx와 Registry 이미지 로드
  2. start-nginx.sh - 80번 포트로 Nginx 실행 (패키지 파일 서버)
  3. setup-offline.sh - Installer Node가 로컬 Nginx를 바라보도록 repo 설정 변경
  4. start-registry.sh - 35000번 포트로 Docker Registry 실행
  5. load-push-all-images.sh - 이미지를 containerd에 로드 후 로컬 Registry에 푸시

Kubespray 환경 구성

# Kubespray 소스 압축 해제
$ ./extract-kubespray.sh
$ cd kubespray-{version}

# Python 가상환경 생성 및 활성화
$ source ../venv.sh

# 라이브러리 설치 (오프라인 PyPI 미러 사용)
$ pip install -r requirements.txt

인벤토리 및 오프라인 설정

인벤토리를 만들고 오프라인 설정을 적용한다.

# 인벤토리 생성
$ cp -rfp inventory/sample inventory/mycluster
$ declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)
$ CONFIG_FILE=inventory/mycluster/hosts.yaml \
  python3 contrib/inventory_builder/inventory.py ${IPS[@]}

outputs/offline.ymlinventory/mycluster/group_vars/all/offline.yml로 복사한 뒤 Installer Node IP를 수정한다.

# inventory/mycluster/group_vars/all/offline.yml

# YOUR_HOST를 Installer Node IP로 변경
http_server: "http://192.168.1.100"
registry_host: "192.168.1.100:35000"

# 로컬 레지스트리 미러 설정 (중요)
containerd_registries_mirrors:
  - prefix: "{{ registry_host }}"
    mirrors:
      - host: "http://{{ registry_host }}"
        capabilities: ["pull", "resolve"]
        skip_verify: true

클러스터 배포

Step 1. 타겟 노드 레포지토리 설정

타겟 노드들이 Installer Node의 Nginx에서 패키지를 받도록 설정한다.

$ cp -r ../playbook/* .
$ ansible-playbook -i inventory/mycluster/hosts.yaml --become offline-repo.yml

Step 2. 클러스터 설치

$ ansible-playbook -i inventory/mycluster/hosts.yaml \
  --become --become-user=root cluster.yml

download-all.sh 내부 스크립트 상세 분석

기준 레포: garlicKim21/kubespray-offline-install-guide
원본 upstream: kubespray-offline/kubespray-offline


download-all.sh — Internal Script Flow

download-all.sh 실행 구조

download-all.sh는 직접 로직을 수행하지 않는다. 아래 순서로 서브스크립트를 순차 호출하는 오케스트레이터 역할이다.

#!/bin/bash

run ./prepare-pkgs.sh || exit 1   # 실패 시 전체 중단
run ./prepare-py.sh
run ./get-kubespray.sh

if $ansible_in_container; then
    run ./build-ansible-container.sh  # 컨테이너 방식
else
    run ./pypi-mirror.sh              # 일반 방식
fi

run ./download-kubespray-files.sh
run ./download-additional-containers.sh
run ./create-repo.sh
run ./copy-target-scripts.sh

|| exit 1prepare-pkgs.sh에만 적용된다. 이 스크립트가 실패하면 이후 모든 과정이 불가능하기 때문이다.


서브스크립트 전체 분석

1. prepare-pkgs.sh

항목내용
역할다운로드 작업에 필요한 시스템 도구 설치
실행 환경Online Node (인터넷 연결 필수)
실패 시exit 1 — 전체 프로세스 중단
주요 작업pip, git, podman (또는 docker/nerdctl) 설치
OS 분기RHEL 계열: yum install / Ubuntu: apt install
런타임 선택config.shdocker 변수로 podman / docker / nerdctl 결정
출력물없음 (시스템 패키지 설치만 수행)
주의사항Online Node와 Target Node의 OS가 동일해야 함

핵심 설치 패키지:

패키지용도
podman (기본)컨테이너 이미지 pull/save
gitKubespray 소스 클론
python3, pipPython 환경 구성
createrepo / dpkg-dev로컬 repo 메타데이터 생성용

2. prepare-py.sh

항목내용
역할Python 가상환경(venv) 생성 및 기본 패키지 설치
실행 환경Online Node
실패 시경고만, 프로세스는 계속 진행
주요 작업venv 생성, pip 업그레이드, 기본 의존성 설치
Python 버전OS별 자동 감지 (target-scripts/pyver.sh 활용)
출력물outputs/venv/ 디렉토리
주의사항Ubuntu 24.04는 Python 3.12 → 호환성 주의

동작 예시:

python3 -m venv outputs/venv
source outputs/venv/bin/activate
pip install -U pip setuptools wheel

3. get-kubespray.sh

항목내용
역할지정 버전의 Kubespray 소스코드 확보
실행 환경Online Node
실패 시경고 후 계속 (이미 존재하면 스킵)
주요 작업GitHub에서 Kubespray tarball 다운로드 및 압축 해제
버전 결정config.shKUBESPRAY_VERSION 변수
조건KUBESPRAY_DIR가 없을 때만 실행
다운로드 소스https://github.com/kubernetes-sigs/kubespray/archive/refs/tags/v{VERSION}.tar.gz
출력물outputs/kubespray-{VERSION}/ 디렉토리

주의사항:

  • master 브랜치나 release 브랜치를 직접 사용하면 안 된다.
  • 반드시 태그(v2.xx.y) 기준으로 확보해야 한다.

4. pypi-mirror.sh (또는 build-ansible-container.sh)

항목내용
역할Kubespray 실행에 필요한 Python 라이브러리 오프라인 미러 구성
실행 환경Online Node
실패 시경고 후 계속
주요 작업requirements.txt 기반 .whl 파일 전체 다운로드
다운로드 소스PyPI (pypi.org)
출력물outputs/pypi/ 디렉토리 (.whl 파일 다수)
분기 조건config.shansible_in_container=true이면 build-ansible-container.sh 실행

다운로드되는 주요 패키지:

패키지용도
ansible, ansible-corePlaybook 실행
jinja2템플릿 렌더링
netaddrIP 주소 처리
cryptographySSH 키 관련
jsonpatchK8s manifest 패치
ruamel.yamlYAML 파싱

build-ansible-container.sh (대안):

  • Ansible을 컨테이너로 실행하는 방식
  • pypi-mirror 없이 컨테이너 이미지로 의존성 해결
  • 사용 빈도 낮음 (실험적)

5. download-kubespray-files.sh

항목내용
역할K8s 구성에 필요한 바이너리 및 컨테이너 이미지 전체 다운로드
실행 환경Online Node
실패 시경고 후 계속 (개별 파일 단위로 재시도)
주요 작업 1Kubespray의 generate_list.sh 실행 → files.list, images.list 생성
주요 작업 2files.list 기반 바이너리 HTTP 다운로드
주요 작업 3images.list 기반 컨테이너 이미지 pull → .tar 저장
출력물outputs/files/ (바이너리), outputs/images/ (이미지 tar)

다운로드되는 바이너리:

파일출처
kubectl, kubelet, kubeadmdl.k8s.io
etcd tarballGitHub releases
cni-pluginsGitHub releases
crictlGitHub releases
helmget.helm.sh
calico, cilium 등 CNI 바이너리각 프로젝트 GitHub

다운로드되는 컨테이너 이미지:

이미지레지스트리
kube-apiserver, kube-schedulerregistry.k8s.io
corednsregistry.k8s.io
pauseregistry.k8s.io
calico/node, calico/cnidocker.io
quay.io/cilium/*quay.io
etcdregistry.k8s.io

6. download-additional-containers.sh

항목내용
역할사용자 정의 추가 컨테이너 이미지 다운로드
실행 환경Online Node
실패 시경고 후 계속
주요 작업imagelists/*.txt에 명시된 이미지 pull → .tar 저장
출력물outputs/images/ (추가 이미지 tar)
커스터마이징imagelists/ 디렉토리에 .txt 파일 추가로 원하는 이미지 지정 가능

imagelists/*.txt 형식:

# 예시: imagelists/custom.txt
nginx:1.25
redis:7.0
myregistry.example.com/myapp:latest

7. create-repo.sh

항목내용
역할OS 패키지(RPM/DEB) 다운로드 및 로컬 레포지토리 메타데이터 생성
실행 환경Online Node
실패 시경고 후 계속
주요 작업 (RHEL)reposync로 RPM 다운로드 → createrepo로 메타데이터 생성
주요 작업 (Ubuntu)apt-mirror로 DEB 다운로드 → dpkg-scanpackages로 메타데이터 생성
출력물outputs/rpms/ 또는 outputs/debs/ + repodata/
주의사항OS 종류에 따라 자동 분기 처리됨

다운로드 대상 패키지:

카테고리패키지 예시
Container Runtimecontainerd, runc
Networksocat, conntrack, ipset, ipvsadm
Storagenfs-utils, open-iscsi
기타curl, rsync, unzip

8. copy-target-scripts.sh

항목내용
역할폐쇄망 Installer Node에서 사용할 셋업 스크립트들을 outputs/로 복사
실행 환경Online Node (로컬 복사 작업)
실패 시경고 후 계속
주요 작업target-scripts/ 디렉토리의 파일들을 outputs/에 복사
출력물outputs/ 내 각종 *.sh 파일
인터넷불필요 (로컬 파일 복사만 수행)

복사되는 주요 스크립트:

스크립트역할
setup-container.shcontainerd 설치 + Nginx/Registry 이미지 로드
start-nginx.shNginx 컨테이너 실행 (:80)
setup-offline.shyum/apt repo를 로컬 Nginx로 변경
setup-py.shPython3 + venv 설치
start-registry.shDocker Registry 실행 (:35000)
load-push-all-images.sh이미지 tar → containerd 로드 → Registry 푸시
extract-kubespray.shKubespray tarball 압축 해제 + 패치 적용
offline.ymlAnsible 오프라인 설정 템플릿
offline-repo.yml타겟 노드 repo 설정 Playbook

전체 요약 테이블

순서스크립트실행 환경인터넷 필요주요 출력물실패 시
1prepare-pkgs.shOnline NodeO없음 (시스템 설치)전체 중단
2prepare-py.shOnline NodeOoutputs/venv/계속
3get-kubespray.shOnline NodeOoutputs/kubespray-{VER}/계속
4-apypi-mirror.shOnline NodeOoutputs/pypi/*.whl계속
4-bbuild-ansible-container.shOnline NodeOAnsible 컨테이너 이미지계속
5download-kubespray-files.shOnline NodeOoutputs/files/, outputs/images/계속
6download-additional-containers.shOnline NodeOoutputs/images/*.tar계속
7create-repo.shOnline NodeOoutputs/rpms/ or outputs/debs/계속
8copy-target-scripts.shOnline NodeXoutputs/*.sh, outputs/offline.yml계속

outputs/ 디렉토리 구조 (완료 후)

outputs/
├── venv/                          # Python 가상환경
├── kubespray-2.30.0/              # Kubespray 소스코드
├── pypi/                          # Python 패키지 (.whl)
│   ├── ansible-9.x.x-py3-none-any.whl
│   ├── jinja2-3.x.x-py3-none-any.whl
│   └── ...
├── files/                         # K8s 바이너리
│   └── kubernetes/
│       └── v1.30.x/
│           ├── kubeadm
│           ├── kubectl
│           └── kubelet
├── images/                        # 컨테이너 이미지 tar
│   ├── kube-apiserver_v1.30.x.tar
│   ├── coredns_v1.11.x.tar
│   ├── calico-node_v3.x.x.tar
│   └── ...
├── rpms/ (또는 debs/)             # OS 패키지 + repodata
│   ├── containerd.io-x.x.x.rpm
│   ├── repodata/
│   └── ...
├── setup-container.sh             # copy-target-scripts로 복사된 파일들
├── start-nginx.sh
├── start-registry.sh
├── setup-offline.sh
├── setup-py.sh
├── load-push-all-images.sh
├── extract-kubespray.sh
└── offline.yml

config.sh 주요 변수 정리

변수기본값설명
KUBESPRAY_VERSION2.30.0다운로드할 Kubespray 버전
dockerpodman컨테이너 런타임 (podman / docker / nerdctl)
ansible_in_containerfalseAnsible을 컨테이너로 실행할지 여부
NGINX_PORT80Nginx 포트 번호
REGISTRY_PORT35000Docker Registry 포트 번호

주의사항 정리

항목내용
OS 일치Online Node와 Target Node의 OS 및 버전이 반드시 동일해야 함
RHEL 8Kubespray 2.29.0부터 지원 중단. RHEL 9 이상 사용 권장
Python 버전Ubuntu 24.04는 Python 3.12 → pyver.sh가 자동 감지
디스크 용량outputs/ 완성 시 수 GB (이미지 포함 시 10~30GB 수준)
방화벽폐쇄망 Installer Node의 80, 35000 포트 오픈 필요
태그 버전Kubespray는 반드시 정식 태그(v2.xx.y) 기준으로 확보

트러블슈팅

Python 버전 문제
Ubuntu 24.04는 Python 3.12를 쓴다. prepare-pkgs.sh 실행 시 호환성 문제가 생길 수 있는데, target-scripts/pyver.sh에서 자동 감지하도록 되어 있어서 대부분 자동으로 처리된다.

방화벽
Installer Node의 80번(Nginx)과 35000번(Registry) 포트가 타겟 노드들에서 접근 가능한지 반드시 확인한다.

디스크 용량
outputs/ 디렉토리는 수 GB가 된다. Installer Node에 여유 공간이 충분한지 미리 확인해둔다.


마무리

처음에는 설정 파일이 많아서 복잡해 보이지만, 결국 흐름은 단순하다.

다운로드 → 이관 → 서버 구성 → 배포

kubespray-offline이 대부분의 번거로운 작업을 자동화해줘서 직접 처리할 부분은 IP 설정과 인벤토리 구성 정도다.

profile
bytebliss

0개의 댓글