이번 장의 목표는 직접 만든 컨테이너 이미지를 쿠버네티스에서 사용하는 것이다. 쿠버네티스에서 이미지를 사용하려면 쿠버네티스가 이미지를 불러올 수 있는 공간에 이미지를 넣어 두어야 한다.
쿠버네티스는 컨테이너를 효과적으로 다루기 위해서 만들어졌고 컨테이너인 파드도 쉽게 부를 수 있다. 따라서 직접 만든 컨테이너 이미지도 kubectl 명령으로 쿠버네티스 클러스터에서 바로 구동할 수 있다.
이전에 실습했던 multistage-img 사용
--image를 옵션으로 주어 multistage-img 이미지를 사용하게 하고 이름은 failure1로 설정
kubectl create deployment failure1 --image=multistage-img
kubectl get pods -w
파드 상태가 정상이라면 STATUS에 Running으로 표시돼야 한다. 하지만 이미지를 내려받는 데 문제가 발생해 ErrorImagePull과 ImagePullBackOff라는 오류 메시지가 번갈아 표시된다. 이는 이미지가 호스트에 존재함에도 기본 설정에 따라 이미지를 외부(도커 허브)에서 받으려고 시도하기 때문이다.
kubectl create deployment failure2 --dry-run=client -o yaml \
--image=mutistage-img > failure2.yaml
사용자가 원하는 형태의 디플로이먼트를 만드는 가장 좋은 방법은 현재 수행되는 구문을 야믈 형태로 뽑아내는 것이다. --dry-run=client 옵션은 해당 내용을 실제로 적용하지 않은 채 명령을 수행하고, -o yaml은 현재 수행되는 명령을 야믈 형태로 바꾼다. 두 옵션을 조합하면 현재 수행되는 명령을 야믈 형태로 출력해 사용자가 원하는 형태로 변경할 수 있다.
마지막에 > failure2.yaml을 붙여 실행 결과를 파일로 저장
failure2.yaml을 열어 컨테이너 설정에 imagePullPolicy: Never 옵션을 다음과 같이 추가한다. 이 옵션은 외부에서 이미지를 가죠오지 않고 호스트에 존재하는 이미지를 사용하게 한다.
형태는 바뀌었지만 여전히 오류가 발생한다.
정확하게 실습하기 위해 현재 디플로이먼트 모두 삭제 후 워커 노드 3번인 w3-k8s에 접속
kubectl delete deployment failure1
kubectl delete deployment failure2
curl -O \
https:raw.githubusercontent.com/sysnet4admin/_Book_k8sInfra/main/ch4/4.3.4/Dockerfile
docker build -t multistage-img .
cp failure2.yaml success1.yaml
sed -i 's/replicas: 1/replicas: 3/' success1.yaml
sed -i 's/failure2/success1/' success1.yaml
kubectl apply -f success1.yaml
kubectl get pods -o wide
컨테이너 이미지가 워커 노드 3번에만 있기 때문에 워커 노드 3번만 배포에 성공했다. 워커 노드 1번과 2번에는 multistage-img가 없어서 파드를 생성할 수 없다.
해결 방법은 크게 두 가지이다. 기본으로 사용하는 도커 허브에 multisgate-img를 올려서 다시 내려받거나 쿠버네티스 클러스터가 접근할 수 있는 곳에 이미지 레지스트리를 만들고 그것에서 받아오도록 설정하는 것이다.
이번엔 이미지 레지스트리를 만드는 방식으로 실습해본다.
호스트에서 생성한 이미지를 쿠버네티스에서 사용하려면 모든 노드에서 공통으로 접근하는 레지스트리가 필요하다. 도커나 쿠버네티스는 도커 허브라는 레지스트리에서 이미지를 내려받을 수 있다. 인터넷이 연결 돼 있다면 이곳을 이용하면 된다.
때로는 직접 만든 이미지가 외부에 공개되기를 원하지 않는 경우도 있다. 도커 허브에서 제공하는 사설 저장소가 있지만, 사설 저장소는 무료 사용자에게는 1개밖에 허용되지 않으며 비공개 저장소를 사용하려면 유료 구독이 필요하다. 또한 무료 사용자는 이미지를 내려받는 횟수에 제약이있다.
제약없이 사용할 수 있는 저장소가 필요하면 레지스트리를 직접 구축하는 방법이 있다. 이경우 인테넷을 연결할 필요가 없으므로 보안이 중요한 내부 전산망에서도 구현이 가능하다.
이번 실습에서는 도커에서 제공하는 도커 레지스트리 이미지를 사용해 사설 도커 레지스트리를 만든다. 도커 레지스트리는 컨테이너를 하나만 구동하면 돼서 설치가 간편하고 내부에서 테스트 목적으로 사용하기에 적헙하다. 전문적인 기능이 필요하면 다른 레지스트리를 사용하는 것이 좋다.
Quary(키): 레드햇에서 제공하는 이미지 레지스트리. 오픈 소스로 제공되는 무료 버전과 구입한 후 보유한 서버에 직접 설치해 사용할 수 있는 유료 버전, 비용을 지불하고 클라우드에서 이용할 수 있는 서비스형 상품이 있다. 유료 버전이나 서비스형 상품은 제품에 대한 신뢰성 보증과 기술 지원 서비스를 받을 수 있으므로 안정적인 서비스를 운영하고 싶은 사용자에게 적합
Harbor(하버): 클라우드 네이티브 컴퓨팅 재단의 지원을 받는 Project Harbor에서 오픈 소스로 제공하는 레지스트리이다. 도커 이미지 외에도 헬름 차트도 저장할 수 있다. 이미지와 헬름 차트를 함께 저장할 수 있어 두가지 모두를 사용하는 사용자에게 알맞다.
Nexus Repository(넥서스 리포지터리): Sontype에서 만든 레지스트리로, 오픈 소스로 제공되는 무료 버전과 유료 버전이 있다. 유료 버전은 기술 지원과 다양한 기능을 제공받을 수 있다 .도커 이미지 외에도 리눅스 설치 패키치, 자바 라이브러리, 파이썬 라이브러리 등 다양한 형식의 파일을 저장할 수 있어서 여러 형식의 패키지를 하나의 저장소에 관리하려는 사용자에게 안성맞춤이다. 다양한 형식을 지원하는 매력적인 특성 덕분에 레지스트리 중 가장 많은 사용자를 보유하고 있다.
Docker Registry(도커 레지스트리): 도커에서 제공하는 레지스트리이다. 무료로 사용할 수 있고 도커 이미지만 저장할 수 있다. 도커 허브에서 제공하는 레지스트리 전용 컨테이너로 간편하게 설치할 수 있다. 기능이 매우 간단해서 개인용이나 테스트용으로 적합
구분 | 키 | 하버 | 넥서스 리포지터리 | 도커 레지스트리 |
---|---|---|---|---|
가격 | 유/무료 | 무료 | 유/무료 | 무료 |
저장 형식 | 도커 이미지, 헬름 | 도커 이미지, 헬름 | 다양함 | 도커 이미지 |
설치 방법 | 직접 설치, 클라우드 | 직접 설치 | 직접 설치 | 직접 설치 |
기능 | 부가 기능 있음 | 부가 기능 있음 | 매우 많음 | 최소 |
관련 자료 | 적음 | 보통 | 많음 | 많음 |
레지스트리를 생성하고 구동하는 과정이 담긴 스크립트로 인증서 생성과 배포, 레지스트리 생성과 구동의 순서로 이루어져 있다.
create-registry.sh
#!/usr/bin/env bash
certs=/etc/docker/certs.d/192.168.1.10:8443도커는 /etc/docker/certs.d 디렉터리 하위 경로에서 레지스트리 주소와 일치하는 디렉터리에 위치한 인증서를 찾아 레지스트리에 HTTPS로 접속한다. 따라서 마스터 노드와 워커 노드에 인증서 디렉터리를 생성할 때 변수 certs를 인증서 디렉터리 경로로 사용
mkdir /registry-image # 레지스트리 이미지가 저장되는 디렉터리
mkdir /etc/docker/certs # 레지스트리 서버의 인증서들을 보관하는 디렉터리
mkdir -p $certs # 변수 certs에 입력된 경로를 이용해 인증서를 보관할 디렉터리를 생성
openssl req -x509 -config $(dirname "$0")/tls.csr -nodes -newkey rsa:4096 \
-keyout tls.key -out tls.crt -days 365 -extensions v3_reqHTTPS로 접속 하려면 서버의 정보가 담긴 인증서와 주고 받는 데이터를 암호화와 복호화할 때 사용하는 키가 필요하다. 인증서를 생성하는 요청서가 담긴 tls.csr 파일로 HTTPS 인증서인 tls.crt 파일과 암호화와 복호화에 사용하는 키인 tls.key 파일을 생성 $(dirname "$0")는 현재 셸 파일이 실행되는 경로를 치환해준다.
yum install sshpass -y # SSH 접속을 위한 비밀번호를 자동으로 입력하는 sshpass 설치
별도의 설정이 없다면 SSH 접속 시 비밀번호를 사용자가 키보드로 직접 입력해야 한다. 사용자가 직접 비밀번호를 입력하면 자동화에 제약이 생긴다.
for i in {1..3}
do
sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.1.10i mkdir -p $certs sshpass -p vagrant scp tls.crt 192.168.1.10i:$certs
done워커 노드에 인증서 디렉터리를 생성하고 인증서를 복사하는 작업
cp tls.crt $certs
mv tls.* /etc/docker/certs
docker run -d \
--restart=always \
--name registry \
-v /etc/docker/certs:/docker-in-certs:ro \
-v /registry-image:/var/lib/registry \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/docker-in-certs/tls.crt \
-e REGISTRY_HTTP_TLS_KEY=/docker-in-certs/tls.key \
-p 8443:443 \
registry:2
인증서를 생성하려면 서명 요청서(CSR, Certificate signing request)를 작성해야 한다. 서명 요청에서는 인증서를 생성하는 개인이나 기관의 정보와 인증서를 생성하는데 필요한 몇 가지 추가 정보를 기록한다. 이후 CSR을 기반으로 인증서와 개인키를 생성하는데, 이 예제에서 사용하는 CSR이 tls.csr 파일이다.
[req]
distinguished_name = private_registry_cert_req
x509_extensions = v3_req
prompt = noprivate_registry_cert_req의 정보를 이용해 인증서 생성
[private_registry_cert_req]
C = KR
ST = SEOUL
L = SEOUL
O = gilbut
OU = Book_k8sInfra
CN = 192.168.1.10인증서 요청자의 국가, 도시, 소속, 이름, 인증서를 설치하는 서버의 주소 정보
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names키의 사용 목적을 기입
[alt_names]
DNS.0 = m-k8s
IP.0 = 192.168.1.10
이 명령을 인증서 생성 및 배포 작업과 함께 레지스트리를 구동한다. 직접 생성하고 자체적으로 검증하는 인증서를 자체 서명 인증서라고 한다.
docker ps -f name=registry
multistage:latest 이미지를 레지스트리에서 읽으려면 레지스트리가 서비스되는 주소(IP와 도메인)와 제공되는 이미지 이름을 레지스트리에 등록될 이름으로 지정해야 한다. 그래야만 해당 정보를 읽어 들여 정상적으로 레지스트리에 등록된다. 따라서 docker tag 명령으로 multistage-img 사본을 만든다. 이때 새로운 이미지를 만드는 것이 아니라 이미지의 레이어를 공유하는 사본이 만들어진다.(윈도우의 바로가기, 리눅스의 하드 링크와 거의 같다)
docker tag multistage-img 192.168.1.10:8443/multistage-img
docker push 192.168.1.10:8443/multistage-img
curl <레지스트리 주소>/v2/_catalog로 요청을 보내면 레지스트리에 등록된 이미지 목록을 보여준다. 이를 통해 이미지가 정상적으로 등록됐는지 확인
자체 서명 인증서를 쓰는 사이트이기 때문에 -k 옵션으로 보안 검증을 생략하고 접속해야한다.
curl https://192.168.1.10:8443/v2/_catalog -k
호스트에 생성한 이미지는 더 이상 사용하지 않으니 삭제. 이미지를 삭제하기 위해 이미지 id를 알아낸다.
docker images | grep multi
삭제시 -f 명령을 사용해서 같은 id를 바라보고 있는 2개의 이미지를 한번에 삭제
쿠버네티스 클러스터에 속해 있는 노드 어디에서든지 이미지를 내려받을 수 있는 레지스트리를 구성했다. 마지막으로 직접 만든 이미지를 쿠버네티스에서 불러서 파드를 만들 차례이다. 쿠버네티스에서 파드를 생성할 때 직접 구성한 레지스트리에서 가지고 온다.
cp success1.yaml success2.yaml
기존 파일 success2.yaml을 아래와 같이 변경
워커 노드 3번에 배포한 이미지와 중복되지 않게 success2.yaml에 설정된 이름인 success1을 모두 success2로 바꾼다.
sed -i 's/success1/success2/' success2.yaml
kubectl apply -f success2.yaml