멋쟁이사자처럼 오늘 공부 후기 챌린지 - 클라우드 엔지니어링 편
이런 고민을 하고 있다면, 지금 이 순간에도 멋쟁이사자처럼에서 클라우드 엔지니어링 부트캠프를 수강하며 자신만의 속도로 성장 중인 수강생들을 주목해보세요.
배우고 잊어버리는 건 누구나 겪는 일이에요. 하지만 멋쟁이사자처럼 부트캠프는 단순히 배우는 것에 그치지 않고, 배운 내용을 내 것으로 만드는 방법까지 고민하고 있어요. 그렇다면, 배운 것을 가장 효과적으로 습득하는 방법은 무엇일까요? 바로 기록하고 정리하는 것이죠. 배운 내용을 정리하고 기록하면, 기억은 오래 남고 실전에서도 활용할 수 있으니까요!
멋쟁이사자처럼 부트캠프는 수강생들이 배운 내용을 정리하고 공유할 수 있도록 TIL (Today I Learned) 블로그 챌린지를 진행하고 있어요. 그래서 오늘, 강사님과 멘토님에게 배운 내용을 체계적으로 기록하며 성장하고 있는 수강생의 이야기를 가져왔어요. 작고 사소해 보일지라도 배운 내용을 정리하고, 기록하면서 성장한 이들의 소중한 경험을 지금 확인해 보세요.
1. Spring Boot + NodePort
목표
Spring Boot 애플리케이션을 Docker 이미지로 빌드하고, Kubernetes의 Deployment & NodePort Service로 배포
sample-app.jar
sts maven build로 .jar 파일 생성
Dockerfile
FROM openjdk:17
COPY *.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
Docker Image 빌드 및 푸시
# 멀티 아키텍처 이미지 빌드
docker buildx build --platform linux/amd64,linux/arm64 -t app-k8s-basic .
# 태깅 및 Docker Hub 푸시
docker tag app-k8s-basic <username>/<repo-name>
docker push <username>/<repo-name>
Deployment
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: myapp
template:
metadata:
labels:
app.kubernetes.io/name: myapp
spec:
containers:
- name: myapp-container
image: <username>/<repo-name>
ports:
- containerPort: 8080
NodePort Service
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: myapp
template:
metadata:
labels:
app.kubernetes.io/name: myapp
spec:
containers:
- name: myapp-container
image: <username>/<repo-name>
ports:
- containerPort: 8080
2. MySQL 연결 실습
PersistentVolume
# db-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: db-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /mnt/data # 로컬 노드에 실제 파일 저장
PersistentVolumeClaim
# db-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1GiMySQL Service
# db-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
selector:
app: mysql
type: NodePort
ports:
- port: 3306
targetPort: 3306
nodePort: 31306ClusterIP로 설정하면 클러스터 내부에서 mysql-service 이름으로 접근 가능함
MySQL Deployment
# db-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql-container
image: mysql:8
env:
- name: MYSQL_ROOT_PASSWORD
value: k8s12345
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql-volume
volumes:
- name: mysql-volume
persistentVolumeClaim:
claimName: db-pvcSpring Boot 설정 파일
src/main/resources/application.properties
# 서버 기본 설정
server.port=8080
spring.application.name=k8s-basic-app
# MySQL 연결 정보 (mysql-service는 K8S의 서비스 이름)
spring.datasource.url=jdbc:mysql://mysql-service:3306/k8sdb?serverTimezone=Asia/Seoul
spring.datasource.username=appuser
spring.datasource.password=apppass123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA 설정
spring.jpa.hibernate.ddl-auto=update # 또는 create (초기 생성용)
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
요약 포인트
구성 요소 | 설명 |
Dockerfile | Spring Boot jar을 이미지로 만듦 |
Deployment | 애플리케이션 또는 DB Pod 복제 관리 |
Service | 외부 트래픽 연결 (NodePort로 포트 개방) |
PV/PVC | DB 데이터 영속 저장소 구성 |
MySQL 연동 | Spring Boot에서 내부 DB 접근 설정 완료 |
기본 개념
Kubernetes에서 API 리소스(Pod, Deployment, Service 등)를 논리적으로 그룹핑하여 관리할 수 있도록 제공되는 리소스
네임스페이스를 활용하면 여러 팀/환경/서비스를 서로 격리하여 관리할 수 있음
주로 사용하는 Namespace 구분 기준
팀 단위: team-a, team-b …
환경 단위: dev, stage, prod …
서비스 단위: auth, payment, frontend …
클러스터 내 리소스 범위 확인
명령어 | 설명 |
kubectl api-resources | 전체 리소스 종류 확인 |
kubectl api-resources --namespaced=true | 네임스페이스 단위 리소스만 확인 |
kubectl api-resources --namespaced=false | 클러스터 범위 리소스만 확인 |
1) 네임스페이스 종류 및 역할
Namespace | 설명 |
default | 명시하지 않으면 기본으로 사용되는 공간 |
kube-system | Kubernetes 시스템 컴포넌트(Pod 등) 관리 |
kube-public | 클러스터 내 모든 사용자가 접근 가능한 공용 정보 |
kube-node-lease | 노드의 상태(헬스체크 등)를 주기적으로 Lease 리소스로 관리 |
2) Namespace 기반 리소스 분리 - 실습
디렉터리 이동
cd ~/manifest
네임스페이스 생성
kubectl create namespace alpha
kubectl create namespace betaDeployment 예시
# deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 2
selector:
matchLabels:
app: nginx-svc
template:
metadata:
labels:
app: nginx-svc
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
Service 예시
# service-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
type: ClusterIP
selector:
app: nginx-svc
ports:
- port: 8080
targetPort: 80
리소스 적용
kubectl apply -f deploy-nginx.yaml -n alpha
kubectl apply -f service-nginx.yaml -n alpha
kubectl apply -f deploy-nginx.yaml -n beta
kubectl apply -f service-nginx.yaml -n beta
확인 명령어
ResourceQuota & LimitRange
리소스 | 설명 |
ResourceQuota | 네임스페이스 단위로 사용 가능한 전체 리소스 총량 제한 |
LimitRange | Pod/Container 단위로 기본/최대/최소 자원 제한 |
실습
네임스페이스 생성
# ns-gamma.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-gammakubectl apply -f ns-gamma.yaml
LimitRange 예시
# limitrange-gamma.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: lr-gamma
namespace: ns-gamma
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: 1
memory: 512Mi
min:
cpu: 50m
memory: 64Mi
- type: PersistentVolumeClaim
max:
storage: 2Gi
min:
storage: 200Mi
ResourceQuota 예시
# quota-gamma.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-gamma
namespace: ns-gamma
spec:
hard:
limits.cpu: "4"
limits.memory: "6Gi"
requests.storage: "10Gi"
count/pods: 15
count/services: 5
count/secrets: 10
count/configmaps: 10
테스트용 Pod
# pod-gamma1.yaml
apiVersion: v1
kind: Pod
metadata:
name: gamma-pod-default
namespace: ns-gamma
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80# pod-gamma2.yaml
apiVersion: v1
kind: Pod
metadata:
name: gamma-pod-limit
namespace: ns-gamma
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80
resources:
limits:
cpu: 1
memory: 512Mi
개요
key:value 형태로 데이터를 저장하는 리소스
환경 설정을 Pod 외부에서 분리하여 관리할 수 있도록 지원
민감하지 않은 설정 정보 저장용 (예: DB 이름, 이메일 등)
ConfigMap 생성방법
1) 리터럴 방식
kubectl create configmap user-config \
--from-literal=APP_NAME=myapp \
--from-literal=ADMIN_EMAIL=admin@k8s.io
kubectl get configmap user-config -o yaml
2) 파일 또는 디렉토리로 생성
APP_NAME=myapp
ADMIN_EMAIL=admin@k8s.iokubectl create configmap file-config --from-file=./app.config
kubectl get configmap file-config -o yaml
3) 선언 방식(YAML)
apiVersion: v1
kind: ConfigMap
metadata:
name: declared-config
data:
APP_NAME: myapp
ADMIN_EMAIL: admin@k8s.io
Pod에서 ConfigMap 활용 방법
1) 직접 환경 변수 지정
apiVersion: v1
kind: Pod
metadata:
name: pod-v1
spec:
containers:
- name: web
image: nginx
env:
- name: APP_NAME
value: myapp
- name: ADMIN_EMAIL
value: admin@k8s.io
2) ConfigMap 전체를 환경 변수로 가져오기
apiVersion: v1
kind: Pod
metadata:
name: pod-v2
spec:
containers:
- name: web
image: nginx
envFrom:
- configMapRef:
name: declared-config
3) ConfigMap의 특정 key만 참조
apiVersion: v1
kind: Pod
metadata:
name: pod-v3
spec:
containers:
- name: web
image: nginx
env:
- name: CONTACT_EMAIL
valueFrom:
configMapKeyRef:
name: declared-config
key: ADMIN_EMAIL
4) Volume으로 마운트
apiVersion: apps/v1
kind: Deployment
metadata:
name: configmap-vol
spec:
selector:
matchLabels:
app: cm-volume
template:
metadata:
labels:
app: cm-volume
spec:
containers:
- name: web
image: nginx
volumeMounts:
- mountPath: /etc/config
name: config-volume
volumes:
- name: config-volume
configMap:
name: declared-config
개요
ConfigMap과 유사하지만 민감한 정보 저장을 위한 리소스
모든 값은 base64로 인코딩되어 저장됨
내부적으로 etcd에 저장되며, TLS 미적용 시 노출 위험 있음
민감한 정보 예시: PASSWORD, TOKEN, SSH_KEY, API_KEY 등
Secret 타입
타입 | 설명 |
Opaque | 기본 타입, 일반 키-값 저장 |
kubernetes.io/dockerconfigjson | Docker 이미지 레지스트리 인증 정보 |
kubernetes.io/tls | TLS 인증서 (cert/key) 저장 |
kubernetes.io/service-account-token | ServiceAccount 토큰 저장용 |
Secret 생성 방법
1. 리터럴
kubectl create secret generic user-secret \
--from-literal=DB_USER=admin \
--from-literal=DB_PASS=secret123
2. YAML 선언 (base64 인코딩 필요)
apiVersion: v1
kind: Secret
metadata:
name: encoded-secret
type: Opaque
data:
DB_USER: YWRtaW4= # admin
DB_PASS: c2VjcmV0MTIz # secret123인코딩: echo -n 'admin' | base64
Pod에서 Secret 활용 방법
1. envFrom 전체 가져오기
apiVersion: v1
kind: Pod
metadata:
name: secret-pod-v1
spec:
containers:
- name: app
image: nginx
envFrom:
- secretRef:
name: encoded-secret
2. 특정 Key 참조
apiVersion: v1
kind: Pod
metadata:
name: secret-pod-v2
spec:
containers:
- name: app
image: nginx
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: encoded-secret
key: DB_PASS
3. 볼륨으로 마운트
apiVersion: v1
kind: Pod
metadata:
name: secret-pod-v3
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: secret-vol
mountPath: /etc/secret
volumes:
- name: secret-vol
secret:
secretName: encoded-secret
Private Docker Registry에서 이미지 Pull
Secret 생성
kubectl create secret docker-registry regcred \
--docker-username=<username> \
--docker-password=<token> \
--docker-email=<email>
Deployment에 imagePullSecrets 적용
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-private
spec:
replicas: 1
selector:
matchLabels:
app: private-app
template:
metadata:
labels:
app: private-app
spec:
containers:
- name: nginx
image: <username>/<repo>:latest
imagePullSecrets:
- name: regcred
홈 : 멋사 부트캠프
멋쟁이사자처럼의 13년 교육 노하우로 IT 취업의 꿈을 현실로!
