이미지 레지스트리 구성
빌드한 이미지를 저장하고 관리할 수 있는 저장소를 만들어보자.
1. 도커가 공식적으로 제공하고 있는 레지스트리 컨테이너 이미지를 사용하여 실행한다.
registry:2 이미지를 이용하면 도커 레지스트리를 운용할 수 있다.
docker run -d --rm -p 8765:5000 --name registry registry:2
2. 이미지에 태그를 붙인다.
docker tag ubuntu:22.04 localhost:8765/ubuntu:22.04
3. 이미지를 push 한다.
docker push localhost:8765/ubuntu:22.04
4. 레지스트리에 저장되어 있는 이미지들의 목록을 확인한다.
curl localhost:8765/v2/_catalog
5. 해당 이미지의 태그 목록을 조회한다.
curl localhost:8765/v2/ubuntu/tags/list
이제 k8s 클러스터에 위의 이미지를 이용하여 포드를 배포하고, 서비스로 노출해보자.
1. k8s Manifest를 작성한다. 파일명은 registry.yaml으로 한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
labels:
run: registry
namespace: registry
spec:
replicas: 1
selector:
matchLabels:
run: registry
template:
metadata:
labels:
run: registry
spec:
containers:
- name: registry
image: registry:2
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: registry-service
namespace: registry
spec:
type: LoadBalancer
selector:
run: registry
ports:
- name: registry-tcp
protocol: TCP
port: 30100
targetPort: 5000
nodePort: 30100
2. kubectl로 registry라는 namespace를 만든다.
kubectl create namespace registry
3. 1에서 작성한 파일로 deployment와 service를 생성한다.
kubectl apply -f registry.yaml
4. 태그를 붙인다.
docker tag ubuntu:22.04 localhost:30100/ubuntu:22.04
5. 레지스트리로 push 한다.
docker push localhost:30100/ubuntu:22.04
6. 이미지 목록과 태그 목록을 확인한다.
curl localhost:30100/v2/_catalog
curl localhost:30100/v2/ubuntu/tags/list
이제 실습을 다 했으니 환경을 정리한다.
1. 실행하고 있던 컨테이너 registry를 중단한다. 실행할 때 rm 옵션을 줬었기 때문에 자동으로 소멸된다.
docker stop registry
2. 설치했던 포드와 서비스를 삭제한다.
kubectl delete -f registry.yaml
OpenSSL을 이용하여 인증서를 발급하고 설치해보자.
1. openssl이 설치되어 있는지 확인한다. 설치되어 있지 않다면 구글에 검색해서 다운로드하고, OpenSSL을 환경변수에 등록한다.
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/registry.key -add "subjectAltName=DNS:registry-service.registry.svc.cluster.local" -x509 -days 3650 -out certs/registry.crt
2. k8s의 secret으로 등록한다.
kubectl create secret tls registry-cert --cert=certs/registry.crt --key=certs/registry.key -n registry
3. registry.yaml 파일을 다음과 같이 수정한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
labels:
run: registry
namespace: registry
spec:
replicas: 1
selector:
matchLabels:
run: registry
template:
metadata:
labels:
run: registry
spec:
containers:
- name: registry
image: registry:2
ports:
- containerPort: 5000
env:
- name: REGISTRY_HTTP_TLS_CERTIFICATE
value: "/certs/tls.crt"
- name: REGISTRY_HTTP_TLS_KEY
value: "/certs/tls.key"
volumeMounts:
- name: registry-certs
mountPath: "/certs/"
readOnly: true
- name: registry-data
mountPath: "/var/lib/registry"
volumes:
- name: registry-certs
secret:
secretName: registry-cert
- name: registry-data
persistentVolumeClaim:
claimName: registry-data-pvc
---
apiVersion: v1
kind: Service
metadata:
name: registry-service
namespace: registry
spec:
type: LoadBalancer
selector:
run: registry
ports:
- name: registry-tcp
protocol: TCP
port: 30100
targetPort: 5000
nodePort: 30100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: registry-data-pv
namespace: registry
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "D:\pv"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-data-pvc
namespace: registry
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual
resources:
requests:
storage: 50Gi
4. 3에서 작성한 파일로 오브젝트들을 생성한다.
kubectl apply -f registry.yaml
4. 레지스트리에 push 한다.
docker push localhost:30100/ubuntu:22.04
5. 3에서 설정한 볼륨 호스트 경로를 확인해보면 파일들이 저장된 것을 확인할 수 있다.
인수 테스트
젠킨스 파이프라인에서의 인수 테스트
1. 개발자가 변경한 코드를 깃허브에 push 한다.
2. 젠킨스가 변경을 감지하여 빌드를 시작하고, 단위 테스트를 수행한다.
3. 젠킨스가 빌드를 완료하여 도커 이미지를 생성한다.
4. 젠킨스가 생성한 이미지를 레지스트리로 push 한다.
5. 젠킨스가 스테이징 환경을 구성하고 도커 컨테이너를 실행한다.
6. 스테이징 환경의 도커 호스트가 이미지를 pull 하여 컨테이너를 실행한다.
7. 젠킨스가 스테이징 환경에서 실행 중인 앱을 대상으로 인수 테스트를 실행한다.
빌드에 사용할 컨테이너 설정
1. Dockerfile-jnlp를 작성한다.
FROM jenkins/jnlp-agent-docker
USER root
COPY entrypoint.sh /entrypoint.sh
RUN chown jenkins:jenkins /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod 755 kubectl \
&& mv kubectl /bin
USER jenkins
ENTRYPOINT ["/entrypoint.sh"]
2. Dockerfile-dind를 작성한다.
이때 자가 서명 인증서를 사용한다. registry.crt 부분이 자가 서명 인증서이다.
FROM docker:latest
COPY registry.crt /usr/share/ca-certificates/registry/registry.crt
RUN echo "registry/registry.crt" >> /etc/ca-certificates.conf
RUN update-ca-certificates
3. Dockerfile-builder 파일을 작성한다.
우분투 위에 openjdk-17-jdk를 설치하는 명령이 작성되어 있다.
FROM ubuntu:22.04
RUN apt update
RUN apt install -y openjdk-17-jdk
4. 빌드한다.
성공적으로 빌드하고 나면 두 번째와 같은 파일이 생성된 것을 확인할 수 있다.
gradlew build
5. 도커 이미지를 빌드한다. 아래는 Dockerfile의 내용이다.
FROM openjdk:17
COPY build/libs/calculator-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
6. 아래 명령어를 입력하여 테스트해본다.
curl "localhost:8765/sum?a=12&b=35"
작업용 임시 파이프라인 만들기
1. 기존에 설정한 파이프라인에서 Poll SCM 옵션을 잠시 끈다.
2. 젠킨스에서 아이템을 만들어서 다음의 pipeline script를 입력한다.
pipeline {
agent {
kubernetes {
yaml'''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: sheayun/jnlp-agent-sample
env:
- name: DOCKER_HOST
value: "tcp://localhost:2375"
- name: dind
image: sheayun/dind
command:
- /usr/local/bin/dockerd-entrypoint.sh
env:
- name: DOCKER_TLS_CERTDIR
value: ""
securityContext:
privileged: true
- name: builder
image: sheayun/jenkins-agent-jdk-17
command:
- cat
tty: true
'''
}
}
environment {
REGISTRY_URI = 'registry-service.registry.svc.cluster.local:30100'
REGISTRY_TAG = '1.0'
}
stages {
stage("Checkout") {
steps {
git url: 'git@github.com:ncherryu/calculator.git',
branch: 'main',
credentialsId: 'github-credentials'
}
}
stage("Compile") {
steps {
script {
container('builder') {
sh "./gradlew compileJava"
}
}
}
}
stage("Unit Test") {
steps {
script {
container('builder') {
sh "./gradlew test"
publishHTML(target: [
reportDir: 'build/reports/tests/test',
reportFiles: 'index.html',
reportName: 'JUnit Report'
])
}
}
}
}
stage("Code Coverage") {
steps {
script {
container('builder') {
sh "./gradlew jacocoTestReport"
publishHTML(target: [
reportDir: 'build/reports/jacoco/test/html',
reportFiles: 'index.html',
reportName: 'JaCoCo Report'
])
sh "./gradlew jacocoTestCoverageVerification"
}
}
}
}
stage("Static Analysis") {
steps {
script {
container('builder') {
sh "./gradlew checkstyleMain"
publishHTML(target: [
reportDir: 'build/reports/checkstyle',
reportFiles: 'main.html',
reportName: 'Checkstyle Report'
])
}
}
}
}
stage("Package") {
steps {
script {
container('builder') {
sh "./gradlew build"
}
}
}
}
stage("Docker Build") {
steps {
script {
dockerImage = docker.build "calculator"
}
}
}
stage("Docker Push") {
steps {
script {
docker.withRegistry("https://${REGISTRY_URI}") {
dockerImage.push("${REGISTRY_TAG}")
}
}
}
}
}
}
3. 빌드를 수행하고 결과를 확인한다.
배운 점
- 이미지를 저장하고 관리할 수 있는 저장소를 만드는 방법을 배웠고, pv와 pvc를 이용하여 호스트에 저장하는 방법을 알게 되었다.
- 젠킨스 파이프라인에서 인수 테스트를 진행하는 방법에 대해서 알게 되었다.
'데브코스' 카테고리의 다른 글
[17주차 - DAY4] CD 파이프라인 (0) | 2024.06.20 |
---|---|
[17주차 - DAY3] 인수 테스트 정리 (0) | 2024.06.19 |
[17주차 - DAY2] CI 파이프라인 (0) | 2024.06.18 |
[17주차 - DAY1] 쿠버네티스 사용 방법 정리 (0) | 2024.06.17 |
[17주차 - DAY1] 쿠버네티스, 젠킨스 (0) | 2024.06.17 |