아쿠의 개발 일지

한화 시스템 부트 캠프 22주차 회고 본문

ETC/한화시스템

한화 시스템 부트 캠프 22주차 회고

디아쿠 2024. 9. 29. 00:08

아~ 집에 언제가냐

 

뭔가 요즘은 6시에 끝은 나지만 집에는 10시에 가는 것 같다 ,, 집이랑 강의장이 생각보다 멀어서 10시에 집에 가면 12시즈음 도착하게 된다. 뭔가 저녁 시간이니까 사람이 다 빠져서 빠르게 도착할 것 같지만 오히려 차가 별로 없어서 더 늦게 가는 기분...! 

얼른 멋지게 끝내서 칼퇴하는 날이 오면 좋겠다.

 

이번 주에는 현재 프로젝트에 CI/CD를 적용했다.

CI/CD

지속적 통합(Continuous Integration) 및 지속적 제공/배포(Continuous Delivery/Deployment)를 의미하며, 소프트웨어 개발 라이프사이클을 간소화하고 가속화하는 것을 목표로 한다.

지속적 통합이란 어플리케이션의 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트 되어 공유 레포지토리에 통합하는 것을 의미한다.

 

진행 순서를 정리 했을 때, 순차적으로 해야 될 것이라고 말씀 하셨다.

  1. Kubernetes 클러스터 배포 및 MetalLB 설정
  2. LoadBalancer 서비스 및 Ingress 설정
  3. 도메인 연결 및 SSL 설정
  4. CI/CD 파이프라인 설정 (Jenkins 사용)
  5. 무중단 배포 설정

나는 여기에서 Ingress 설정과 도메인 연결 및 SSL 설정을 맡게 되었다.

또한 Kafka또한 K8S를 통해 배포를 해야 하기 때문에 yaml파일을 작성했다.

 

순차적으로 하나씩 정리를 해 보겠다.

 

일단 K8S는 저번 4번째 토이 프로젝트 때 환경 설정을 해 둔 것이 있어서 그나마 편하게 할 수 있었다.

일단 달라진 것은 HTTPS로 적용을 해야 하기에 SSL을 추가해야 한다는 것이다.

HTTPS의 특징은

  • 암호화 통신: SSL(Secure Sockets Layer) 또는 TLS(Transport Layer Security)를 사용하여 데이터를 암호화하여 전송한다. 이를 통해 데이터의 기밀성과 무결성을 보장한다.
  • 포트 번호: 기본적으로 포트 443을 사용한다.
  • 인증서 필요: 신뢰할 수 있는 인증 기관(CA)에서 발급한 SSL/TLS 인증서가 필요하다. 이 인증서는 서버의 신원을 확인하는 데 사용된다.
  • 보안 강화: 중간자 공격, 데이터 도청, 변조 등의 보안 위협으로부터 데이터를 보호한다..
  • SEO 우대: 구글과 같은 검색 엔진은 HTTPS를 사용하는 웹사이트를 더 신뢰할 수 있는 사이트로 간주하여 검색 순위를 높게 평가한다.

HTTPS를 구현하기 위해서 SSL 인증서를 발급 받아야 한다. 

ZeroSSL에서 발급 받았다.

 

SSL 인증서 발급 받는 방법

 

New Certificate 클릭

이미 전 발급을 받았지만 ,, 언젠가 읽을 저를 위해 정리를 해 보겠습니다.

 

사용 할 도메인 입력

 

-> 도메인은 어디서 발급 받냐?

무료 도메인 인증 센터인 [ 내 도메인 한국 ] 에서 받을 수 있다.

https://xn--220b31d95hq8o.xn--3e0b707e/

 

내도메인.한국 - 한글 무료 도메인 등록센터

한글 무료 도메인 내도메인.한국, 웹포워딩, DNS 등 무료 도메인 기능 제공

xn--220b31d95hq8o.xn--3e0b707e

도메인을 생성 해 주고, IP연결에는 K8S에 배포한 frontend 서비스의 IP를 적어주면 된다.

 

위에 생성한 도메인 주소를 입력 해 주고 Next Step을 넘어간다.

 

90-Day 로 설정 해 주고 Next Step

추가 기능을 선택하는 칸도 그냥 아무것도 체크 안 하고 Next Step

무료 버전을 선택하고, Next

이제 다음으로 가면 검증 방법을 선택하라고 하는데, DNS를 선택하고

아래에 나오는 Name, Point To 를 잘 복사해서 내 도메인 한국에 있는 

이 칸에 잘 넣어주면 된다. 그럼 이제 키를 다운 받을 수 있는데, 이 키의 압축을 해제하고 내가 찾을 수 있는 폴더 안에 잘 넣어주면 된다. 나는 c드라이브에 넣어놨다.

 

이제 이 키를 인증서를 생성하기 위해 쿠버네티스 환경을 만들어 놓은 마스터 계정으로 들어왔다.

key파일을 옮기기 위해서 < 파일 질라 > 프로그램을 사용 했으며, 내 c드라이브에 있는 파일을 파일 질라를 통해 k8s환경을 구축 해 놓은 마스터 계정 home 안에 넣어놨다.

 

이제 K8s 클러스터에서 ingress-nginx를 사용하여 HTTPS를 설정하고, SSL 인증서를 적용하기 위한 단계를 차근차근 정리하겠다.

 

1. 인증서 파일을 준비한다.

위에 앞서 말 했던 것 처럼 key 파일을 옮긴 폴더 안으로 간다. 

인증서 파일은

certificate.crt, ca_bundle.crt, private.key가 준비되어 있어야 한다.

 

2. 인증서 파일을 병합한다.

cat certificate.crt ca_bundle.crt > fullchain.crt

이 명령어는 서버 인증서와 CA 번들을 하나의 파일인 fullchain.crt로 병합하는 것이다. 이는 SSL 인증서를 제대로 검증하기 위해서 필요하고, fullchain.crt 파일은 클라이언트가 서버의 SSL 인증서를 신뢰할 수 있도록 모든 필요한 중간 인증서를 포함한다.

 

3. Secret 생성

kubectl create secret tls tls-secret --cert=fullchain.crt --key=private.key -n default

default 네임 스페이스에 tls-secret 라는 이름의 TLS Secret를 생성한다. 

 

4. Ingress 리소스 설정 확인

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: calit-ingress
  namespace: default
spec:
  ingressClassName: "nginx"
  tls:
    - hosts:
        - www.calit.kro.kr
      secretName: tls-secret
  rules:
    - host: www.calit.kro.kr
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-svc
                port:
                  number: 80
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: backend-svc
                port:
                  number: 8080

 

1. ingressClassName: "nginx": ingress-nginx 컨트롤러를 사용하도록 지정합니다.

2. tls: TLS 설정을 정의하며, www.calit.kro.kr 호스트에 대해 tls-secret을 사용하도록 지정합니다.

3. rules: HTTP 및 HTTPS 요청을 해당 서비스로 라우팅합니다.

 

혹여나 ingress 리소스를 수정했거나, 새로 생성한 경우 Kubernetes 클러스터에 적용 하기 위해서는

kubectl apply -f calit-ingress.yaml

명령어를 통해 적용할 수 있다.

 

이제 브라우저에서 [https:// 도메인 주소] 에 접근하여 SSL 인증서가 올바르게 적용 됐는지 시각적으로 확인 가능하다.

 


앞서 말씀 드린 것 처럼, 채팅 기능을 배포하기 위해서 공부하고 준비한 방법을 설명 드리겠습니다.

 

Kubernetes 클러스터에 Zookeeper와 Kafka를 배포하고, 백엔드 애플리케이션과 연결하는 과정

 

1. zookeeper 먼저 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: zookeeper-deployment
  labels:
    app: zookeeper
spec:
  replicas: 1  # Zookeeper 인스턴스 수
  selector:
    matchLabels:
      app: zookeeper
  template:
    metadata:
      labels:
        app: zookeeper
    spec:
      containers:
        - name: zookeeper
          image: zookeeper:3.8.0
          ports:
            - containerPort: 2181  # Zookeeper 클라이언트 포트
          env:
            - name: ALLOW_ANONYMOUS_LOGIN
              value: "yes"  # 익명 로그인 허용 (기본 설정)
            - name: ZOOKEEPER_CLIENT_PORT
              value: "2181"  # Zookeeper 클라이언트 연결 포트
            - name: ZOOKEEPER_SERVER_ID
              value: "1"  # Zookeeper 서버 ID
---
apiVersion: v1
kind: Service
metadata:
  name: zookeeper-service
  labels:
    app: zookeeper
spec:
  ports:
    - port: 2181
      targetPort: 2181
  selector:
    app: zookeeper

 

2. Kafka 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kafka-deployment
  labels:
    app: kafka
spec:
  replicas: 1  # Kafka 브로커의 수 (하나의 브로커로 설정)
  selector:
    matchLabels:
      app: kafka
  template:
    metadata:
      labels:
        app: kafka
    spec:
      containers:
        - name: kafka
          image: confluentinc/cp-kafka:7.4.6
          ports:
            - containerPort: 9092  # Kafka 브로커 포트
          env:
            - name: KAFKA_BROKER_ID
              value: "1"  # Kafka 브로커의 ID
            - name: KAFKA_ZOOKEEPER_CONNECT
              value: "zookeeper-service:2181"  # Zookeeper 서비스와 연결
            - name: KAFKA_ADVERTISED_LISTENERS
              value: "PLAINTEXT://kafka-service:9092"  # Kafka의 광고 주소
            - name: KAFKA_LISTENERS
              value: "PLAINTEXT://0.0.0.0:9092"  # 모든 인터페이스에서 수신 대기
            - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
              value: "PLAINTEXT:PLAINTEXT"  # 보안 프로토콜 설정
            - name: KAFKA_INTER_BROKER_LISTENER_NAME
              value: "PLAINTEXT"  # 브로커 간 통신에 사용할 리스너 이름
            - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
              value: "1"  # 카프카 토픽 오프셋 복제 계수
            - name: KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS
              value: "0"  # 초기 리밸런스 지연 시간
---
apiVersion: v1
kind: Service
metadata:
  name: kafka-service
  labels:
    app: kafka
spec:
  ports:
    - port: 9092  # Kafka 브로커가 클라이언트에게 노출될 포트
  selector:
    app: kafka

 

그럼 이제 백엔드 애플리케이션과 Kafka를 어떻게 연결하면 좋을지,,,

jenkins - 시스템 - 환경변수를 사용해서 배포 과정에서 해당 환경 변수를 주입할 수 있게 해준다.
jenkins /setting/system에서 KAFKA_SERVER 안에 kafka-service(k8s kafka 서비스 이름):9092 를 해주면
-> kafka-service:9092

dockerFile에서

# ARG 선언과, ENV 설정을 해 젠킨스 파일에서Docker Build & Push 할 때 --build-arg KAFKA_SERVER=${KAFKA_SERVER} \

 

를 해주면 applicaion.yml 에서 잘 받아오게 해준다.

  kafka:
    bootstrap-servers: ${KAFKA_SERVER}
    producer:
      bootstrap-servers: ${KAFKA_SERVER}
    consumer:
      bootstrap-servers: ${KAFKA_SERVER}

 

Kafka가 잘 실행 됐는지 알기 위해서는 Pod 이벤트를 확인 해 보면 된다.

 

schedduled : 배치할 노드를 선택하고, pod의 스케쥴링이 완료
Pulling : 컨테이너 이미지 다운로드 작업을 시작
Pulled : 컨테이너 이미지가 성공적으로 다운로드
Created : 컨테이너 생성 완료
Started : 컨테이너가 실행 → 서비스 정상적 실행 시작

 

이렇게 뜨면 성공 한 것이다. 백엔드 파드 안으로 가서 정상 실행이 됐는지, kafka 로그가 뜨는지를 보며 확인 할 수 있다.

 


 

이렇게 22주차의 회고록이 끝나게 되고, 직접 배포를 하려고 하니 많이 어려웠다. 이번 주는 개발을 멈추고 only 배포만 한 것 같다.

저번 4번째 토이 프로젝트 때 한 차례 했던 것이라 편할 줄 알았는데, 그때 기반을 잡아놓지 않았더라면 이 시간 안에 하지 못 했을 것 같다는 생각이 들었다.

 

개발만 하는 게 중요한 것이 아니라 CI/CD, K8S, Jenkins와 같은 도구를 잘 다뤄야 하는 이유를 뼈저리게 느끼게 됐다.

아쉬운 것이 있다면 아무래도 시간이 부족하다 보니 저번 토이 프로젝트 때 K8S yaml이나, JenkinsFile을 작성하는 것을 같이 맡았다는 점이다..! 나중에 따로 공부를 해 해 보는 시간을 가져야 할 것 같다.

Kafka를 배포하면서 yaml을 찾아보고 작성했는데, 뭔가 개발에서 효율적으로 확장 가능함을 느낄 수 있었다. 자원을 할당해주고 운영하는 것에 편리함을 확실하게 느꼈다.

 

무중단 배포를 통해 사용자에게 영향을 주지 않고, 새로운 기능을 배포할 수 있게 도와주는 작업을 했고, 아직 많은 테스트를 거치지는 않았지만 했다는 것에 많이 신기했다. 

 

현대 소프트웨어 개발에서 신속한 배포, 서비스 안정성은 이제 필수로 잡혀가는 것 같다. 이를 통해 생산성과 협업을 극대화 할 수 있기 때문에 ,, 꼭 갖춰야 할 기술인 것 같다. 오늘도 적으면서 많은 것을 느꼈다. 열심히 살아야겠다...!

 

내일은 팀끼리 만나 발표 준비를 하기 때문에 일요일에 적지 못할 것 같아 먼저 적었다..!

다들 주말 잘 보내시고, 행복한 하루 보내셔요.

 

 

728x90