- voronoi diagram
- 느리게 갱신되는 세그먼트 트리
- BOJ 30026
- 2023 Engineering Pair
- dx dy
- 오일러투어트리
- K8s
- BOJ17139
- 2025acpc
- 27173
- 컴퓨터융합학부
- 세그먼트 트리
- BOJ 30028
- 누텔라트리(hard)
- 수열과 쿼리 43
- hhs2003
- fortune's algorithm
- BOJ 30029
- 알고리즘
- 백준
- Delaunay triangulation
- BOJ 30027
- 2023 SW - IT Contest
- 충남대학교 2023 SW - IT
- boj 30788
- BOJ 31226
- boj23054
- 27114
- CodeForces
- solved.ac
황현석 일지
Kubernetes - Registry:2 적용기 본문
개요 및 상황
https://bada.anacnu.kr - 충남대학교 ANA 동아리 내의 실시간 추첨 결과 온보딩 페이지
위의 홈페이지에 필요한 정보를 백준에서 최소한으로 쿼리해서 처리하고 있었습니다. 하지만, 학내 IP가 solved.ac 에서 Cloudflare 단에서 차단되어, AWS Lambda에서 크롤러를 실행시키고 있었습니다.
그런데, AWS 실습과 더불어, AWS 에서 사용하는 서비스가 점차 늘어나, Crawler라도 줄이기 위해, Crawler를 동아리 내의 온프레미스 서버로 이전하는 과정이 이 포스팅이 되겠습니다.
시스템 설계
우선적으로는 저희의 동아리 서버에는 단일 클러스터 환경에서 돌아가는 K3s 기반의 쿠버네티스가 설치 되어 있습니다.
동아리 서버에 크롤러를 5분 마다 돌려야 하는 것이 이번의 Task 였습니다.
크롤러는 이미 AWS 에 올려놓기 위해, Image로 잘 만들어져 있었습니다. AWS Lambda에 올릴 때는, AWS ECR (Elastic Container Registry) 에 이미지를 올리고, 이미지를 pull 해오는 식으로 람다를 만들었습니다.
추후에, 동아리에 람다나 깃허브 액션과 같은 시스템을 구현하고 싶었습니다. 따라서, AWS Lambda 에 배포할 때와 같은 방식으로 동아리 서버에 배포해보는 과정을 거치는게 좋다고 생각했습니다.
첫 번째 과정은, 일련의 Docker Image 업로드 시스템을 직접 구축하는 것에 있었습니다. 따라서, K3s내에서 Registry:2 Image 를 Deploy하여, 이미지 저장소를 운영하는 것이 첫 번째 Task가 되었습니다. 찾아 본 결과, PVC 관련하여 서비스를 띄우고, 서비스를 참조하여, Registry:2 이미지를 운영해야 Persistance Volume을 유지 할 수 있음을 알았습니다.
또한 Registry:2 에서 사용할 계정을 만들기 위해, htpasswd 라는 파일형식을 공부 하였습니다. htpasswd 를 사용하여, 계정 정보를 관리하고, 이를 K3s 내의 Secret으로 만들었습니다. Secret을 Registry:2의 컨테이너에 마운트하여 사용하게 하였습니다.
두 번째 과정은, 이제 만들어놓은 Registry:2 서비스에 잘 접근하게 하는 것입니다. 모든 도커내의 pull과 push는 암호화를 위해 https 형식으로 진행된다는 것을 알고 있습니다. 외부 ip로 나가지 않고 내부에서 image 를 push 하는 것은 http 통신을 허용 설정을 추가로 해야합니다.
하지만, 외부 에서 접근가능한 Registry:2를 만드는게 더 좋아보였습니다. 이미 소유한 Domain이 있고, 이미 도메인에 대해 와일드카드 인증서를 발급받아서 Ingress에서 잘 사용 중 이었습니다.
따라서, 단순하게 Registry:2 에 대해서, Service를 만들고, Ingress Controller를 만들어서, https 통신으로 접근하게 하였습니다.
세 번째 과정은, 이제 단순하게 구축된 Registry:2에 현재 Docker Image 를 Push하는 것입니다. 이것은 아주 쉽습니다. Docker login 을 통해 로그인 후, docker tag 로 push할 도메인과 버전명을 적어주고 docker push를 하면 되는 아주 간단한 작업이었습니다.
네 번째 과정은, 이제 cronJob을 통해서, 5분마다 해당 이미지의 컨테이너를 띄워 실행시키는 것이었습니다.
Deployment 비슷한 걸 하면 되는 아주 기초적인 작업이었습니다. 후에, 크롤러가 잘 연산을 하는 것을 볼 수 있었습니다.
Registry:2 를 띄우기 위해, 우선은 인증정보 부터 생성했습니다.
htpasswd -Bc auth admin
admin 이라는 계정에 비밀번호는 임의로 설정하여, auth 라는 이름의 htpasswd 파일을 생성했습니다.
kubectl create secret generic registry-auth --from-file=<만들어진 htpasswd 파일 경로>
그리고 이름이 registry-auth 라는 secret Resource를 만들었습니다. 후에, 이 정보를 Registry:2 에 마운트하여 사용하게 할 것입니다.
선행작업을 모두 작업했습니다. 이제는 Registry:2 띄울 것입니다. 도커 이미지 저장소를 하는 프로그램을 띄운다고 생각하면 됩니다. 하지만, 모종의 이유로 파드가 죽고 부활 했을 때, 데이터가 소실 되면 안됩니다.
따라서, PersistentVolumeClaim (PVC)를 띄워, Docker Image가 저장될 공간을 예약 설정하였습니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
다음과 같은 PVC Resource를 생성하였습니다. 후에는 이 Resource 를 사용하는 Registry:2를 띄워야 합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-registry
spec:
replicas: 1 # 레플리카 1로 설정
selector:
matchLabels:
app: registry # 셀렉터 설정
template:
metadata:
labels:
app: registry # 레이블 설정
spec:
containers:
- name: registry
image: registry:2
ports:
- containerPort: 5000 # 컨테이너 포트 설정
env:
- name: REGISTRY_AUTH
value: "htpasswd" # 인증 방식 설정
- name: REGISTRY_AUTH_HTPASSWD_REALM
value: "Registry Realm" # 인증 방식 설정
- name: REGISTRY_AUTH_HTPASSWD_PATH
value: "/auth/htpasswd" # 인증에 필요한 아이디 정보가 담긴 파일
volumeMounts:
- name: storage
mountPath: /var/lib/registry # 컨테이너 내의 레지스트리 저장소 경로
- name: auth-volume
mountPath: /auth # 컨테이너 내의 인증 정보 경로
readOnly: true
volumes:
- name: storage
persistentVolumeClaim:
claimName: registry-pvc
- name: auth-volume
secret:
secretName: registry-auth # 인증 정보가 담긴 시크릿
deployment로 Registry:2 만 하면 편하겠으나, 파드가 죽었다가 다시 생성되면, 모든 저장소가 초기화됩니다. 따라서, PVC를 선언하고, 컨테이너의 파일을 PVC 에 Mount 시켜야 합니다.
추가로, 우리가 생성한 registry-auth 라는 secret Resource를 컨테이너 안에 mount 시켰습니다.
apiVersion: v1
kind: Service
metadata:
name: registry-service
spec:
type: NodePort
selector:
app: registry
ports:
- port: 5000
targetPort: 5000
nodePort: 32000
추가로, selector를 사용하여, Service를 하나 만들었습니다. 추후에, Ingress를 사용할 때는, 이 Service를 참조하여 사용하면 되겠습니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry-ingress
annotations:
kubernetes.io/ingress.class: traefik
# k3s 기본 Traefik 사용 시
# 이미지 업로드 용량이 크므로 제한을 늘려줍니다 (필요 시)
ingress.kubernetes.io/proxy-body-size: "0"
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
#traefik.ingress.kubernetes.io/router.tls.certresolver: "letsencrypt" # 또는 사용 중인 인증서 리졸버
# traefik Interceptor 설정. 기존 인클러스터 백엔드에 넘겨줌. (지금은 비활성화)
#traefik.ingress.kubernetes.io/router.middlewares: cloud-admin-vm-traffic-interceptor@kubernetescrd
spec:
tls:
- hosts:
- docker.anacnu.com
rules:
- host: docker.anacnu.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry-service
port:
number: 5000
이런식으로, pvc - deployment - service - Ingress 를 생성하면, 접속 할 수 있게 됩니다.

이런식으로, 이제 자체적인 Registry:2 저장소를 구축할 수 있게 되었습니다.
마지막으로는 docker tag를 통해 push 할 이미지에 태그를 달아주어야합니다.
<domain.com>/<Image Name>:<Version> 형식으로 태그를 달아주고 push 합니다.
kubectl create secret docker-registry regcred \
--docker-server=docker.anacnu.com \
--docker-username=<name> \
--docker-password=<password> \
--docker-email=<email>
하지만, 쿠버네티스가 이미지를 가져올 때, 이 이미지에 접근 할 수 있는 권리가 없습니다. 따라서, 접근 할 수 있는 정보들을 또 secret으로 만들고, Image를 끌어올 때, 필요한 정보들을 넘겨 주어야 합니다. 위에 명령어는 regcred라는 secret을 만드는 명령어 입니다.
apiVersion: batch/v1
kind: CronJob
metadata:
name: bada-crawler
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
imagePullSecrets:
- name: regcred
containers:
- name: bada-crawler-worker
image: docker.anacnu.com/bada-crawler:latest
# OnFailure: 실패했을 때만 재시작, Never: 재시작 안 함 (작업이 끝나면 끝)
restartPolicy: Never
이미지를 끌어 올 때, imagePullSecrets 에 해당 secret을 넘겨 사용할 수 있습니다. 이러면 Image 를 잘 끌어와서 실행 시키는 모습을 볼 수 있습니다.
후, CronJob이라는 컴포넌트를 만들어서, 컨테이너 실행을 스케줄링 화 시켰습니다. 따라서, 이제 선언적 구성으로, Image를 실행할 수 있게 되었습니다.

다음과 같이 모든 생성된 자원들 입니다. docker-registry 가 떠있고, crawler가 최대 3개까지 로그화 되어 보관되어 있는 것을 볼 수 있습니다.
레지스트리 저장소를 실행시키는 것은, 서버 환경에서 코드를 pull하고 env를 다 넣은다음에, 빌드하여 사용하는 것 보다는, 로컬 환경에서 빌드한 결과물을 push 하는 방식이 앞으로 생산성 측면에서 좋을 것이라고 생각했습니다.
또한, 다양한 사람들이 직접 서버에 와서 코드를 가져와서 이미지로 빌드하는 것보다는 각각의 컴퓨터에서 Image를 빌드해서 push하는 것이 더 편하고 좋을 것 같았습니다. 물론 docker build 시에 --platform은 linux/amd64로 해야합니다. (mac 기준)
'Kubernetes' 카테고리의 다른 글
| proto3 (gRPC) 에 대하여, (0) | 2026.04.19 |
|---|---|
| 클라우드 서버 구축 트러블 슈팅 - 01 K3s API Server Connection (0) | 2026.01.14 |
| Kubernetes - 01 (2) | 2025.07.19 |