Kubernetes 버전 : Kubernetes 1.28 (master 1대, worker3대)
OS : Ubuntu 22.04
[Korifi - 소개글 일부]
Korifi 는 빌드, 테스트, 배포 및 모니터링 단계를 지원하는 DevOps 툴체인에 통합되어 애플리케이션 개발자의 배포 환경을 단순화합니다. 또한 팀이 기존 CI/CD, 로깅 및 관찰 가능 도구를 확장할 수 있도록 하는 동시에 Provile, Kpack 과 같은 Kubernetes 네이티브 도구가 포함되어 있습니다. 소프트웨어 엔지니어링 팀은 Korifi 를 통해 포괄적인 Kubernetes 전략을 수립하고 개발, 테스트 및 배포 단계 전반에 걸쳐 모범 사례를 채택할 수 있습니다.
Korifi 는 단일 cf push 명령으로 모든 언어나 프레임워크로 작성된 앱을 배포할 수 있는 기존의 Cloud Foundry 경험을 그대로 유지하고 있습니다. Pak to build pack 을 사용하여 OCI 호환 컨테이너로 앱을 배포함으로써 앱 개발자 경험을 더욱 향상시킵니다. 앱 개발자들은 더 이상 Kubernetes 에 컨테이너화된 배포를 위해 복잡한 YAML 이나 Dockerfile 과 씨름할 필요가 없습니다.
Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.27.3) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with:
kubectl cluster-info --context kind-kind
Thanks for using kind! 😊
* 참고 : 클러스터 생성 오류
클러스터 재설치 등의 작업으로 아래와 같은 에러가 출력된 경우 기존의 클러스터를 삭제해야 다시 생성이 가능합니다.
ERROR: failed to create cluster: node(s) already exist for a cluster with the name "kind" 클러스터 재설치 전에 'kind delete cluster --name kind' 명령으로 삭제를 먼저 한 뒤에 클러스터 생성 명령을 실행해 주세요.
클러스터가 잘 설치 되었는지 확인합니다.
# kubectl cluster-info --context kind-kind Kubernetes control plane is running at https://127.0.0.1:40321 CoreDNS is running at https://127.0.0.1:40321/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
3. 환경 변수 설정
설치가 편리하도록 자주 사용하는 이름은 변수에 입력합니다.
# ROOT_NAMESPACE="cf" // CF 네임스페이스 #KORIFI_NAMESPACE="korifi-system" // Korifi 네임스페이스 #ADMIN_USERNAME="kubernetes-admin" // Admin 계정 아이디 #BASE_DOMAIN="az1.sysdocu.kr" // 기본 도메인
4. CF 설치
Cloud Foundry 는 개발자가 애플리케이션 코드를 작성하고 구축한 후 애플리케이션을 클라우드 환경에 배포하고 실행하는 데 도움이 되는 플랫폼입니다.
# kubectl get pods -n cert-manager NAME READY STATUS RESTARTS AGE cert-manager-cainjector-65c7bff89d-kjwpr 1/1 Running 0 24s cert-manager-cbcf9668d-7gd8w 1/1 Running 0 24s cert-manager-webhook-594cb9799b-b48w2 1/1 Running 0 24s
7. Kpack 설치
Kpack 은 Cloud Foundry 컨테이너 빌드 도구로, Kubernetes 에서 컨테이너 이미지를 빌드하고 관리하는 오픈 소스 프로젝트입니다. Kpack 은 애플리케이션을 컨테이너 이미지로 변환하는 작업을 자동화하고 단순화하는 데 사용됩니다. # kubectl apply -f https://github.com/buildpacks-community/kpack/releases/download/v0.12.2/release-0.12.2.yaml
설치를 확인합니다.
# kubectl get pods -n kpack NAME READY STATUS RESTARTS AGE kpack-controller-7d544645c8-4h92h 1/1 Running 0 19s kpack-webhook-77c465c879-lmkx6 1/1 Running 0 19s
8. Contour 설치
Contour 는 Ingress 컨트롤러입니다. Ingress 컨트롤러는 클러스터 외부에서 클러스터 내의 서비스로의 HTTP 및 HTTPS 트래픽을 관리하고 라우팅하는 역할을 합니다.
--set=global.containerRepositoryPrefix 옵션에는 업로드 할 수 있는 Repository 주소를 적어야 합니다.
--set=kpack-image-builder.builderRepository 옵션에도 동일한 Repository 주소를 적어주고 뒤에 kpack-builder 디렉토리 하나 더 추가해주세요.
여기에서 약간의 시간이 소요됩니다.
설치를 확인합니다.
# kubectl get pods -n korifi-system NAME READY STATUS RESTARTS AGE korifi-api-deployment-5c747f489d-rc4dd 1/1 Running 0 49s korifi-controllers-controller-manager-6b7cdd98c-4h59q 1/1 Running 0 49s korifi-job-task-runner-controller-manager-f799b99fc-d26vb 1/1 Running 0 49s korifi-kpack-build-controller-manager-7cdc7fcc9-4r9rv 1/1 Running 0 49s korifi-statefulset-runner-controller-manager-c49c9997d-ccfvk 1/1 Running 0 49s
참고로 helm 으로 설치된 Korifi 삭제는 helm uninstall korifi -n $KORIFI_NAMESPACE 입니다.
14. 조직 및 공간 생성
조직과 공간 생성 후 그 안에서 애플리케이션이 배포 됩니다.
아래와 같이 Cloud Foundry API 를 통해 조직과 공간을 생성하고 타겟 (작업공간으로 적용) 설정을 합니다.
Cloud Foundry API 인증 작업을 진행합니다.
# cf api https://api.$BASE_DOMAIN --skip-ssl-validation # cf login API endpoint: https://api.az1.sysdocu.kr
1. kind-kind 2. kubernetes-admin
Choose your Kubernetes authentication info (enter to skip):1
Authenticating... OK
Warning: The client certificate you provided for user authentication expires at 2024-12-07T02:35:20Z which exceeds the recommended validity duration of 168h0m0s. Ask your platform provider to issue you a short-lived certificate credential or to configure your authentication to generate short-lived credentials automatically. API endpoint: https://api.az1.sysdocu.kr API version: 3.117.0+cf-k8s user: kubernetes-admin No org or space targeted, use 'cf target -o ORG -s SPACE'
API endpoint: https://api.az1.sysdocu.kr API version: 3.117.0+cf-k8s Not logged in. Use 'cf login' or 'cf login --sso' to log in. Unable to authenticate. FAILED
Kubernetes 환경 변수를 불러오지 않았을 경우가 있으므로 아래 명령을 통해 KUBECONFIG 환경 변수를 설정합니다.
Ansible 은 인프라스트럭처 관리와 소프트웨어 프로비저닝을 자동화하기 위한 오픈 소스 도구 및 프레임워크입니다. Ansible 은 다음 3가지의 핵심 구성 요소를 가지고 있습니다. - 인벤토리 : 관리 대상 호스트 (서버, 가상 머신 등) 의 목록 및 그룹을 정의하는 INI 또는 YAML 파일 - 플레이북 : 작업 (task), 역할 (role), 변수, 조건문 등을 포함한 YAML 파일로, 여러 대상 호스트에서 작업을 수행 - 모듈 : 특정 작업을 수행하기 위한 실행 가능한 코드 블록
Ubuntu 22.04 기반에서 Ansible 을 설치, 설정하고 실제로 실행하는 방법을 알아보겠습니다.
[테스트를 위한 사전 준비]
- Ubuntu 22.04 기반 서버 3대 (Ansible 서버 1대, 대상 호스트 2대)
1. 설치
Ansible 설치는 굉장히 간단합니다.
Ansible 명령을 수행할 Ansible 서버에만 몇 개의 패키지를 설치하면 되며, 작업을 수행할 서버에 설치할 패키지 또는 Agent 는 없습니다.
(그렇기 때문에 본 매뉴얼의 모든 명령은 Ansible 서버에서만 실행합니다)
Ansible 는 SSH 기반으로 명령을 수행하기 때문에 sshpass 패키지까지 설치해줘야 합니다.
그리고 Ansible 은 Python 으로 제작되었기 때문에 Ansible 설치시 Python 도 같이 설치가 됩니다.
ssh 공개키를 생성하고 대상 호스트에 설정하여두면 Ansible 명령 실행시마다 패스워드를 입력하는 번거로움을 줄일 수 있습니다.
# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): (그냥 엔터) Enter passphrase (empty for no passphrase): (그냥 엔터) Enter same passphrase again: (그냥 엔터) Your identification has been saved in /root/.ssh/id_rsa Your public key has been saved in /root/.ssh/id_rsa.pub The key fingerprint is: SHA256:2bKuWWJfCBqiNnkCYgKZRmI6GEZDynqWbGM41/TsbAk root@kuru80-223962 The key's randomart image is: +---[RSA 3072]----+ |=B | |X+. | |Oo . | |++ + o o | |B.@ E + S . | |=O.o * o + | |.= .. B + . | |. + o * . | | o.o | +----[SHA256]-----+
생성된 공개키를 대상 호스트로 복사합니다. 처음 호스트 접속시 패스워드가 필요하지만 키 복사가 완료된 후에는 패스워드가 필요 없게 됩니다.
# ssh-copy-id root@10.101.0.23
# ssh-copy-id root@10.101.0.34
3) 연결 테스트
Ansible 에서 주로 사용하는 옵션은 세가지가 있습니다. (help 에서는 더 많은 옵션이 출력됩니다)
-m : 모듈
-i : 인벤토리
-u : 유저명
유저명은 제외하고 아래와 같이 인벤토리 (servers.ini) 에 등록된 모든 호스트에 ping 테스트를 해봅니다.
참고로 all 말고 섹션명을 지정해주면 인벤토리 내의 특정 세션에 등록된 호스트로만 명령을 실행합니다.
아래는 중요하거나 자주 사용하는 옵션입니다. 모두 [default] 섹션에 넣어주면 됩니다.
- remote_user
: 원격 호스트에 연결할 때 사용할 SSH 사용자 이름을 지정합니다. 기본값은 현재 사용자의 이름입니다. 이 옵션을 설정하여 명시적으로 원격 사용자를 지정할 수 있습니다. 예) remote_user = myuser
- private_key_file
: SSH 키 파일의 경로를 지정합니다. 이 옵션을 사용하여 사용자 지정 SSH 키 파일을 사용할 수 있습니다. 예) private_key_file = /path/to/ssh/keyfile
- inventory
: 인벤토리 파일의 경로를 지정합니다. 기본적으로 ansible.cfg 파일이 있는 디렉토리에서 inventory 파일을 검색하며, 이 옵션을 사용하여 사용자 정의 인벤토리 파일을 지정할 수 있습니다. 인벤토리 파일의 경로를 지정하면 ansible 명령 실행시 -i 옵션을 이용해 인벤토리 파일을 일일이 명시하지 않아도 됩니다. 예) inventory = /root/servers.ini
- roles_path
: 역할 (roles) 디렉토리의 기본 경로를 지정합니다. 이 옵션을 사용하여 역할을 저장하는 디렉토리를 사용자 정의할 수 있습니다. 예) roles_path = /path/to/custom/roles
- forks
: 병렬로 실행될 작업 수를 지정합니다. 기본값은 5이며, 시스템 리소스에 따라 적절한 값을 설정할 수 있습니다. 예) forks = 10
- become
: 작업을 슈퍼 유저(루트) 권한으로 실행할지 여부를 지정합니다. yes로 설정하면 슈퍼 유저로 작업을 실행합니다. 예) become = yes
- become_user
: 슈퍼 유저(루트) 권한으로 작업을 실행할 때 사용할 사용자를 지정합니다. 예) become_user = root
- timeout
: SSH 연결 또는 명령 실행의 타임아웃을 지정합니다. 기본값은 10초입니다. 예) timeout = 30
4. 플레이북 설정
플레이북 (playbook) 을 활용한 다양한 예시를 준비했습니다.
1) 대상 서버로 파일 복사하기
아래와 같이 플레이북 파일을 작성합니다.
# vi copy.yaml
--- - name: Copy a file to a remote server hosts: web tasks: - name: Copy a file copy: src: /root/servers.ini dest: /root/
- 플레이북 파일의 시작은 --- 로 시작하고, 여러개의 작업이 있을 경우 작업 단위마다 - 으로 구분해줘야 합니다.
- hosts : 섹션을 지정합니다. hosts 를 web 섹션으로 하지 않고 all 로 입력 할 경우 인벤토리에 등록된 모든 호스트로 파일을 복사하게 됩니다.
- name: 플레이북의 이름을 정의합니다. 이 이름은 플레이북을 식별하기 위해 사용됩니다. -hosts: 플레이북이 실행될 호스트 그룹을 지정합니다. "all"은 모든 호스트를 대상으로 하는 것을 의미합니다. -tasks: 플레이북에서 실행할 작업 목록을 정의합니다. -name: 각 작업의 이름을 지정합니다. 이것은 작업을 식별하기 위한 레이블입니다. -user 모듈: 이 모듈은 사용자 관리 작업을 수행합니다. -name: root: user 모듈에 전달된 사용자 이름으로 "root" 사용자를 지정합니다. 이 플레이북은 "root" 사용자의 비밀번호를 변경합니다. -update_password: always: 사용자 모듈의 update_password 옵션을 "always"로 설정하면 항상 비밀번호를 업데이트하도록 강제합니다. -password: user 모듈에서 변경할 비밀번호를 정의합니다. 이 플레이북에서는 "12345678"을 password_hash 필터를 사용하여 SHA-512로 해싱한 값을 비밀번호로 설정합니다. 해싱된 비밀번호를 사용하면 보안성을 향상시킬 수 있습니다.
작성한 플레이북을 실행합니다.
# ansible-playbook -i servers.ini chpasswd.yaml
3) 패키지 설치하기
이 예시는 원격 서버의 APT 패키지 관리자를 사용하여 패키지를 설치합니다. # vi apt.yaml
--- - name: Install a package on a remote server hosts: web tasks: - name: Install package apt: name: apache2 state: present
- name: 플레이북의 이름을 정의합니다. 이 이름은 플레이북을 식별하기 위해 사용됩니다. - hosts: 플레이북이 실행될 호스트 그룹을 지정합니다. "web"은 모든 호스트를 대상으로 하는 것을 의미합니다. - tasks: 플레이북에서 실행할 작업 목록을 정의합니다. - apt 모듈: 패키지 설치 작업을 수행합니다.
작성한 플레이북을 실행합니다.
# ansible-playbook -i servers.ini apt.yaml
4) 데몬 컨트롤 하기
이 예제에서는 Ubuntu 에서 Apache 웹 서버를 시작하는 플레이북을 사용합니다. # vi apache2.yaml
--- - name: Start Apache Web Server hosts: web become: yes tasks: - name: Ensure Apache service is running service: name: apache2 state: started
- name: 플레이북의 이름을 지정합니다. -hosts: 플레이북을 실행할 호스트 그룹 또는 호스트 이름을 지정합니다. -become: yes: become 키워드를 사용하여 플레이북을 실행할 때 슈퍼유저(루트) 권한으로 실행합니다. 이는 데몬 또는 서비스를 시작하거나 중지할 때 필요한 권한을 얻기 위해 사용됩니다. -tasks: 수행할 작업 목록을 나열합니다. -name: 작업의 이름을 지정합니다. -service 모듈: 서비스 관리 작업을 수행하는 모듈입니다. -name: apache2: 서비스의 이름을 지정합니다. Ubuntu 에서 Apache 웹 서버는 apache2 로 알려져 있습니다. -state: started: 서비스를 시작하도록 지정합니다. 이 작업은 Apache 웹 서버가 이미 실행 중인 경우에는 아무 작업도 수행하지 않습니다.
작성한 플레이북을 실행합니다.
# ansible-playbook -i servers.ini apache2.yaml
5) 사용자 생성 및 그룹 할당 이 예시는 원격 서버에 사용자를 생성하고 그룹에 할당하는 플레이북입니다. user 및 group 모듈을 사용합니다.
# vi useradd.yaml
--- - name: Create a user and assign to a group hosts: web tasks: - name: Create a group group: name: developers state: present
- name: Create a user user: name: sysdocu groups: developers state: present
* 설명
- name: 플레이북의 이름을 지정합니다. -hosts: 플레이북을 실행할 호스트 그룹 또는 호스트 이름을 지정합니다. -tasks: 수행할 작업 목록을 나열합니다. -group 및 user 모듈: 그룹 및 사용자 생성 및 할당 작업을 수행합니다.
- name: Run a Docker container docker_container: name: my_nginx image: nginx:latest ports: - "80:80"
- name: 플레이북의 이름을 지정합니다. 이 이름은 플레이북을 식별하는 레이블입니다. -hosts: 플레이북을 실행할 호스트 또는 호스트 그룹을 지정합니다. 이 예시에서는 "db" 호스트 그룹에 대한 작업을 수행합니다. -tasks: 플레이북에서 실행할 작업 목록을 정의합니다. -name: 각 작업의 이름을 지정합니다. 이것은 작업을 식별하는 레이블입니다. -docker_image 모듈: 이 모듈은 Docker 이미지 관리 작업을 수행합니다. name 속성은 다운로드하려는 Docker 이미지의 이름을 지정합니다. 이 예시에서는 "nginx:latest" 이미지를 다운로드합니다. -docker_container 모듈: 이 모듈은 Docker 컨테이너 관리 작업을 수행합니다. name 속성은 컨테이너의 이름을 지정하고, image 속성은 사용할 Docker 이미지를 지정합니다. ports 속성은 컨테이너와 호스트 간의 포트 매핑을 설정합니다. 이 예시에서는 "my_nginx"라는 이름의 컨테이너를 생성하고 "nginx:latest" 이미지를 사용하며, 호스트의 80번 포트와 컨테이너의 80번 포트를 연결합니다.
Windows Container 는 Windows 10, 11 또는 Windows Server 2016 이후의 버전을 기반으로 실행해야 합니다.
저는 Windows 2019 Server 기반에서 진행하였습니다.
1. Hyper-V 설치
윈도우즈 파워쉘을 열고 아래 명령을 실행하여 Hyper-V 구성요소를 설치합니다.
PS C:\Users\Administrator> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All 지금 컴퓨터를 다시 시작하여 이 작업을 완료하시겠습니까? [Y] Yes [N] No [?] 도움말 (기본값은 "Y"): Y
'Y' 를 입력하여 리부팅을 합니다.
2. Docker Desktop for Windows 설치
부팅이 되었다면 아래 URL 에 접속하여 윈도우즈용 Docker 를 다운로드 받아 설치합니다.
부팅되어 윈도우즈에 다시 로그인을 하면 Docker Desktop 에서 아래와 같은 메세지가 출력됩니다.
-----
Windows 17763 is deprecated
You can still use Docker Desktop but you are on Windows 17763.
You will not be able to install further major updates (3.6.0 and above).
We recommend upgrading to the latest version of Windows.
-----
Windows 17763은 더 이상 사용되지 않습니다. Docker Desktop을 계속 사용할 수 있지만 Windows 17763을 사용하고 있습니다. 추가 주요 업데이트(3.6.0 이상)를 설치할 수 없습니다. 최신 버전의 Windows로 업그레이드하는 것이 좋습니다.
-----
[OK] 버튼을 누르고 사용 동의를 묻는 질문에 동의합니다.
그 다음 저는 로그인을 스킵하고 진행하였습니다. (맨 아래 밑줄 클릭)
직업을 묻는 창이 뜨는데 마찬가지로 스킵하고 진행하였습니다.
이제 Docker Desktop 사용준비가 완료되었습니다.
3. Windows Container 이미지 다운로드
Windows Container 는 latest TAG 를 지원하지 않으므로 아래 페이지에서 TAG 를 확인 후 정확하게 입력해줘야 합니다.
nanoserver:ltsc2022 버전을 다운로드 하기위해 파워쉘을 실행해 아래와 같이 명령어를 입력합니다.
PS C:\Users\Administrator> docker pull mcr.microsoft.com/windows/nanoserver:2022-amd64 [2023-10-10T06:40:43.321895600Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. 2022-amd64: Pulling from windows/nanoserver no matching manifest for linux/amd64 in the manifest list entries
위와 같은 메세지가 출력된다면 Linux 컨테이너를 실행하도록 되어 있는 것입니다. Windows 컨테이너로 실행하려면 플랫폼 옵션을 추가해 줍니다.
[2023-10-10T06:51:52.322714700Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. 2022-amd64: Pulling from windows/nanoserver no matching manifest for windows/amd64 10.0.17763 in the manifest list entries
플랫폼은 변경되었으나, 에러가 발생했습니다. 에러는 아래에서 잡도록 하고 우선 플랫폼 옵션이 번거로우므로 기본 설정으로 변경하여 옵션을 생략하도록 합니다.
윈도우 하단 우측의 트레이에서 Docker 아이콘을 우클릭하면 'Switch to Windows containers...' 옵션이 보입니다. 이를 클릭하고 다시 명령을 실행해 보겠습니다.
PS C:\Users\Administrator> docker pull mcr.microsoft.com/windows/nanoserver:2022-amd64 [2023-10-10T07:23:17.806412500Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. 2022-amd64: Pulling from windows/nanoserver no matching manifest for windows/amd64 10.0.17763 in the manifest list entries
옵션을 제외하고 Windows 컨테이너로 다운로드 시도한것이 보입니다. 하지만 에러가 해결되지는 않았습니다.
OS 버전을 확인합니다.
PS C:\Users\Administrator> docker info |findstr 'Operating System' Operating System: Microsoft Windows Server Version 1809 (OS Build 17763.107)
현재 OS 버전은 1809 이므로 1809 이후의 버전은 구동하지 못합니다.
원래 다운로드 받으려고 했던 2022-amd64 버전을 1809-amd64 로 변경하여 다운로드 합니다.
PS C:\Users\Administrator> docker pull mcr.microsoft.com/windows/nanoserver:1809-amd64 [2023-10-10T07:40:06.050064200Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. 1809-amd64: Pulling from windows/nanoserver f10ae9b68062: Pull complete Digest: sha256:1b377c168fe2aeef3acd02d3a654c1280b45e6151d66d71ca1d50292e1cce106 Status: Downloaded newer image for mcr.microsoft.com/windows/nanoserver:1809-amd64 mcr.microsoft.com/windows/nanoserver:1809-amd64
What's Next? [2023-10-10T07:40:14.293630700Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. [2023-10-10T07:40:14.369957100Z][docker-credential-desktop.system][W] Windows version might not be up-to-date: The system cannot find the file specified. View a summary of image vulnerabilities and recommendations → docker scout quickview mcr.microsoft.com/windows/nanoserver:1809-amd64
다운로드가 잘 되었습니다. 도커 이미지 목록에도 보이는지 확인합니다.
PS C:\Users\Administrator> docker images REPOSITORY TAG IMAGE ID CREATED SIZE mcr.microsoft.com/windows/nanoserver 1809-amd64 bd7fe7d0dddd 5 weeks ago 252MB
"Windows 컨테이너 이미지에서 제거되었으므로 지원되지 않습니다. 조만간 RDP 나 GUI 를 사용할 계획이 없기 때문에 Windows 컨테이너 구현 방식을 대대적으로 재설계해야 합니다. 애플리케이션에 GUI 나 RDP 가 필요한 경우 VM 을 계속 사용하는 것이 좋습니다. Azure Virtual Desktop 이나 Azure VM 과 같은 서비스가 더 적합할 수 있습니다."
Docker Registry 는 Docker 이미지를 업로드 하거나, 다운로드하여 컨테이너를 생성하는 등 이미지 저장소의 역할을 담당합니다. Docker Hub 와 같이 알려진 공개 Docker Registry 말고, 개인적으로 사용 가능한 Docker Registry 를 직접 만들어 보겠습니다.
보통은 Private Registry 라고 하며 Kubernetes 내에서 생성하고 사설 네트워크로 연결하도록 구성하지만, 여기에서는 별도의 단독 서버 1대 (공인IP) 로만 구성할 예정입니다. Registry 서버가 Kubernetes Cluster 와 동일한 스위치 내에 위치한다면 방화벽을 설치함으로써 Private Registry 과 같은 형태로 만들 수 있습니다. 이런 형태로 서비스에 적용할 예정이라면 스토리지 여러대로 GlusterFS 나 Ceph 를 구성하고 별도로 마운트하고 도커 서비스를 구동할 서버 1대로 구성하면 됩니다.
다시 말씀 드리면, 두가지 방식중 아래 방식으로 진행합니다.
- Kubernetes 설치, 스토리지 준비, PV 및 PVC 생성, Registry Pod 생성
- Docker 설치, Registry Container 생성
[환경 및 사전준비]
OS : Ubuntu 22.04
/data 디렉토리 생성 (로컬 호스트의 이미지 저장소)
1. SSL 인증서 생성
Registry 를 사용할때 파일을 업로드 하거나 다운로드 하게되는데, 이때 암호화 전송이 필요합니다.
(암호화 전송 없이 http 프로토콜을 사용하는 옵션도 있긴 합니다)
인증서가 없을 경우, Let's encrypt SSL 에서 무료 인증서를 발급받을 수 있습니다.
운영체제에 따라 인증서 발급 명령이 다르므로 아래 포스팅을 확인하여 자신의 운영체제에 맞는 명령을 참고하시기 바랍니다.
-v: command not found, -e: command not found 등의 에러 출력시 행 사이에 줄이 떨어져 있는 것이므로 메모장에 기입해 빈 행을 없애거나 역슬래시를 제거하여 한줄 명령으로 사용하면 됩니다.
* 설명
--name MyRegistry : 실행되는 컨테이너의 이름을 MyRegistry 로 설정합니다. --restart=always : 컨테이너가 종료되거나 실패할 경우 자동으로 다시 시작하도록 설정합니다.
-p 5000:5000 : 호스트의 포트 5000 과 컨테이너의 포트 5000 을 연결하여 Registry 에 엑세스할 수 있게 합니다.
-v /opt/registry/auth:/auth : 호스트의 /opt/registry/auth 디렉토리와 컨테이너 내의 /auth 디렉토리를 볼륨 마운트합니다. 이 디렉토리는 사용자 인증 정보를 저장하기 위한 것으로, htpasswd 형식의 사용자 인증 파일이 여기에 저장됩니다. -v /opt/registry/certs:/certs : 호스트의 /opt/registry/certs 디렉토리와 컨테이너 내의 /certs 디렉토리를 볼륨 마운트합니다. 이 디렉토리에는 TLS (SSL) 인증서 및 키 파일이 저장됩니다. -v /data:/var/lib/registry : 호스트의 /data 디렉토리와 컨테이너 내의 /var/lib/registry 디렉토리를 볼륨 마운트합니다. 여기에는 레지스트리의 이미지 데이터가 저장됩니다.
-e "REGISTRY_AUTH=htpasswd" : 환경 변수를 설정하여 레지스트리가 htpasswd 형식의 사용자 인증을 사용하도록 합니다. -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" : htpasswd 형식의 사용자 인증을 위한 Realm 을 설정합니다. -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd : 사용자 인증 정보를 저장하는 htpasswd 파일의 경로를 지정합니다. -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem : TLS (SSL) 인증서 파일의 경로를 설정합니다. -e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem : TLS (SSL) 인증서의 개인 키 파일의 경로를 설정합니다. -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true : Docker Registry v2의 호환성을 유지하고 Docker v1/v1 API를 사용할 수 있도록 활성화합니다. -d registry : 컨테이너를 백그라운드에서 실행하도록 설정하고, 다운로드 받아놓은 registry 라는 Docker Image 를 사용하여 컨테이너를 시작합니다.
구동된 컨테이너를 확인합니다.
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f246853edd47 registry "/entrypoint.sh /etc…" 6 seconds ago Up 5 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp MyRegistry
포트도 5000 번으로 정상적으로 열린것이 확인되었습니다.
# netstat -nltp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 23260/systemd-resol tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN 54372/docker-proxy tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 18912/sshd: /usr/sb tcp6 0 0 :::5000 :::* LISTEN 54379/docker-proxy tcp6 0 0 :::22 :::* LISTEN 18912/sshd: /usr/sb
만들어진 Registry 컨테이너로 로그인을 해봅니다.
계정은 위에서 htpasswd 로 생성했던 계정입니다.
# docker login -u sysdocu -p 12345678 https://registry.az1.sysdocu.kr:5000 WARNING! Using --password via the CLI is insecure. Use --password-stdin. WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store
두가지 방법이 있는데, 여기에서는 기본 컨테이너에서 내용을 변경해보는 아래 방식으로 진행합니다.
- Docker Hub 이미지 그대로 Registry 에 업로드
- Docker Hub 이미지를 받아서 수정하고 Registry 에 업로드
진행할 예제는 php:7.4-apache 기준으로 작성하였습니다. 우선 php:7.4-apache 이미지를 다운로드 합니다.
# docker pull docker.io/php:7.4-apache
테스트용으로 PHP 소스 파일을 만듭니다.
# mkdir ./source
# vi ./source/index.php
<?php echo "Good job"; ?>
Dockerfile 을 아래 내용으로 작성합니다. # vi Dockerfile
FROM docker.io/php:7.4-apache COPY ./source/ /var/www/html/ RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf CMD ["apache2-foreground"]
* 설명
FROM docker.io/php:7.4-apache : 기본 이미지를 지정하는 부분입니다. php2.4 와 apache 웹서버가 설치된 이미지 입니다. COPY ./source/ /var/www/html/ : 호스트 시스템의 ./source/ 디렉토리의 내용을 컨테이너 내부의 /var/www/html/ 디렉토리로 복사하는 명령입니다.
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf : Apache 웹서버에 ServerName 옵션을 추가합니다. CMD ["apache2-foreground"] : 컨테이너가 시작될 때 실행될 명령입니다. 여기에서는 Apache 웹 서버를 시작합니다.
만들어진 Dockerfile 을 사용하여 Docker 이미지를 새로 만듭니다.
형식)docker build --tag <새 이미지 이름><Dockerfile 위치>
# docker build --tagphp7.4-apache-update.
만들어진 새 이미지가 확인 되었습니다.
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE php7.4-apache-update latest b36ddfe193e1 28 seconds ago 453MB registry latest 0030ba3d620c 3 weeks ago 24.1MB
이번에는 로컬에 만들어져 있는 php7.4-apache-update 이미지를 Registry 에 올려 보겠습니다.
업로드 권한이 필요하므로 생성했던 htpasswd 계정을 이용해 Registry 에 로그인을 합니다.
- Kubernetes (Openshift, K-PaaS 등) 에서 Pod 생성, Service 생성
- Docker 에서 컨테이너 생성
# docker run -d -p 80:80 registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update
* 설명 -d : 컨테이너를 백그라운드에서 실행합니다. -p 80:80 : 호스트의 포트 80 을 컨테이너의 포트 80 으로 매핑합니다. 즉, 웹 서버가 동작하는 포트에 접근할 수 있게 됩니다. registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update : 실행할 Docker 이미지를 지정합니다.
컨테이너가 실행되면 웹 서버가 시작되어 호스트의 IP 또는 도메인과 80 번 포트로 웹서버에 접속할 수 있게 됩니다.
MetalLB 를 설치하면 LoadBalancer 를 사용할 수 있는데, 이는 외부에서 접근하는 공인 IP 를 Pod 에 부여함으로써 온전히 애플리케이션의 포트를 NodePort (30000~32767) 와 같이 임의 포트가 아닌 공식 표준 포트를 사용할 수 있게 됩니다.
아래 예제의 Kubernetes 환경은 1.28 버전이며, 모든 명령은 master (control-plane) 서버에서 진행하였습니다.
# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d nginx LoadBalancer 10.111.72.120 115.68.142.130 80:32088/TCP 20m
Kubernetes Cluster 외부의 네트워크에서 출력된 IP 로 접근하여 Nginx 가 열리는지 확인합니다.
시스템 장애 또는 OS 재설치 등의 이유로 worker 노드 하나를 제거해야 할 수 있습니다.
제거하기 전의 Cluster 상태는 아래와 같습니다.
# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane 2d22h v1.28.1 worker1 Ready <none> 2d22h v1.28.1 worker2 Ready <none> 2d22h v1.28.1
worker2 노드를 Kubernetes 클러스터에서 제거하고 다시 연결하는 프로세스는 다음과 같이 진행할 수 있습니다. 주의할 점이 하나 있는데, 노드를 클러스터에서 제거하면 해당 노드에서 실행 중인 모든 컨테이너와 Pod가 중지됩니다.
먼저 worker2 노드에서 실행 중인 Pod 를 다른 노드로 옮기거나 제거해야 합니다.
이 명령어는 worker2 노드에서 실행 중인 Pod 를 다른 노드로 옮기고, DaemonSet Pod 는 무시합니다.
이 상태로 node 리스트를 확인해보면, 해당 노드에 스케쥴링이 비활성화 된 것이 보입니다.
# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane 2d22h v1.28.1 worker1 Ready <none> 2d22h v1.28.1 worker2 Ready,SchedulingDisabled <none> 2d22h v1.28.1
# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane 2d23h v1.28.1 worker1 Ready <none> 2d23h v1.28.1 worker2 Ready <none> 3m44s v1.28.1
* 에러 조치
master 서버에서 Pod 생성시 에러가 발생한다면 추가한 worker 노드에서 다음과 같이 조치 가능합니다.
[ 에러 ]
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 37m default-scheduler Successfully assigned ceph-csi-rbd/ceph-csi-rbd-nodeplugin-n9b2v to worker3 Warning FailedCreatePodSandBox 31m (x26 over 37m) kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = cri-o configured with cgroupfs cgroup manager, but received systemd slice as parent: /kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podd3fc3e78_f49c_4239_b271_55e406fd0b76.slice
[ 해결 ]
아래 kubelet 설정 파일에서 cgroup driver 를 바꿔줍니다.
(추가된 worker 노드에서)
# vi /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf