「시작하세요! 도커/쿠버네티스」 학습 정리 - 07장 ~ 08장.

toto9602·2024년 2월 4일
0

Docker 공부하기

목록 보기
8/10

용찬호. 「 시작하세요! 도커/쿠버네티스」. 위키북스 를 읽으며, 학습한 내용을 정리하는 글입니다.
→ 본문의 내용은 모두 책의 내용에 대한 직/간접적 인용임을 밝힙니다.

7. 쿠버네티스 리소스의 관리와 설정

7.1 네임스페이스(Namespace) : 리소스를 논리적으로 구분하는 장벽

포드, 레플리카셋, 디플로이먼트, 서비스 등과 같은 쿠버네티스 리소스들이 묶여 있는 하나의 가상공간, 또는 그룹

kubectl get namespaces

--namespace 옵션을 명시하지 않으면 기본적으로 default 네임스페이스를 사용!

kube-system 네임스페이스는 쿠버네티스 클러스터 구성에 필수적인 컴포넌트, 설정값 등이 존재하는 네임스페이스.

** 각 네임스페이스의 리소스들은 논리적으로만 구분된 것일 뿐, 물리적으로 격리된 것은 아님!

apiVersion: v1
kind: Namespace
metadata:
	name: production    
  • kubectl apply -f production-namespace.yaml
  • kubectl create namespace production 으로도 생성 가능!
apiVersion: apps/v1
kind: Deployment
metadata:
	name: hostname-deployment-ns
    namespace: production
spec:
...
--- # 하나의 YAML 파일에 ---로 여러 리소스 정의 가능. 여기선 디플로이먼트와 서비스
apiVersion: v1
kind: Service
metadata:
	name: hostname-svc-clusterip-ns
    namespace: production
spec:
  • 다른 네임스페이스에 존재하는 서비스에는 서비스 이름만으로 접근할 수 없다.
  • <서비스 이름>.<네임스페이스 이름>.svc처럼, 서비스 이름 뒤에 네임스페이스 이름 붙여서 접근해야 된다.

→ 모든 리소스가 네임스페이스에 의해 구분되지는 않는다.

  • 특정 오브젝트는 네임스페이스에 속하며, 이 경우 namespaced=true
  • 다만, 역시 쿠버네티스 오브젝트 중 하나인 노드, 네임스페이스 등은 네임스페이스에 종속되지 않는다!

7.2 컨피그맵(Configmap), 시크릿(Secret) : 설정값을 포드에 전달

  • 쿠버네티스는 YAML 파일과 설정값을 분리할 수 있는 컨피그맵(Configmap)과 시크릿(Secret) 오브젝트를 제공
  • 컨피그맵에는 설정값을, 시크릿에는 노출되어서는 안되는 비밀값을 저장

7.2.1 컨피그맵(Configmap)

kubectl create configmap

해당 명령어로 컨피그맵 생성 가능

  • --from-literal 옵션을 사용하여 여러 개의 키-값을 사용하도록 설정할 수 있다.
kubectl create configmap start-k8s --from-literal k8s=kubernetes \ --from-literal container=docker

[ 컨피그맵을 포드에서 사용하는 방법 ]
1. 컨피그맵의 값을 컨테이너의 환경 변수로 사용

  • 애플리케이션이 시스템 환경 변수로부터 설정값을 가져올 때 권장
  1. 컨피그맵의 값을 포드 내부의 파일로 마운트해 사용
  • 애플리케이션이 nginx.conf 등의 파일을 통해 설정값을 읽어 들일 때 권장

< 컨피그맵의 데이터를 컨테이너의 환경 변수로 가져오기 >

apiVersion: 1
kind: Pod
metadata:
	name: container-env-example
spec:
	containers:
    - name: my-cluster
      image: busybox
      args: ['tail', '-f', '/dev/null']
      envFrom:
      - configMapRef:
      	name: log-level-configmap
      - configMapRef:
         name: start-k8s
  • 아래와 같이, valueFromconfigMapKeyRef를 사용하여 특정 데이터만을 선택해 환경 변수로 가져올 수도 있음.
	env:
    - name: ENV_KEYNAME_1
      valueFrom:
      	configMapKeyRef:
        	name: log-level-configmap
            key: LOG_LEVEL

< 컨피그맵의 내용을 파일로 포드 내부에 마운트하기 >

apiVersion: v1
kind: Pod
metadata: 
	name: configmap-volume-pod
spec:
	containers: 
    	- name: my-container
          image: busybox
          args: ["tail", "-f", "/dev/null" ] 
          volumeMounts:
          - name: configmap-volume. # volumes에서 정의한 컨피그맵 볼륨 이름
            mountPath: /etc/config #컨피그맵의 데이터가 위치할 경로
            
	volumes:
      - name: configmap-volume. # 컨피그맵 볼륨 이름
        configMap:
        	name: start-k8s. # 키-값 쌍을 가져온 컨피그맵 이름

< 파일로부터 컨피그맵 생성하기 >
--from-env-file 옵션으로, 여러 개의 키-값 형태의 내용으로 구성된 설정 파일을 한꺼번에 컨피그맵으로 가져올 수 있음!

kubectl create configmap from-envfile --from-env-file multiple-keyvalue.env
  • nginx.conf와 같이 정적 파일을 포드에 제공한다면, --from-file 옵션을 쓰는 게 편리할 수도!

7.2.2 시크릿(Secret)

  • SSH 키, 비밀번호 등과 같이 민감한 정보를 저장하기 위해 사용
kubectl create secret generic \ my-password --from-lieteral password=1q2w3e4r

→ my-password라는 이름의 시크릿 생성, password=1q2w3e3r 키-값을 생성

kubectl get secret my-password -o yaml

password: MXEydzNlNHI=
→ 시크릿에 값을 저장할 때, 쿠버네티스가 기본적으로 base64로 값을 인코딩
→ 시크릿을 포드의 환경 변수나 볼륨 파일로서 가져오면, base64로 디코딩된 원래의 값을 사용하게 된다.

apiVersion: v1
kind: Pod
metadata:
	name: secret-env-example
spec:
	containers:
    - name: my-container
      image: busybox
      args: ['tail', '-f', '/dev/null']
      envFrom:
      - secretRef:
      		name: my-password
  • 혹은 파일로 포드의 볼륨에 마운트하기!
	volumeMounts:
    - name: secret-volume   # volumes에서 정의한 시크릿 볼륨 이름 
      mountPath: /etc/secret # 시크릿의 데이터가 위치할 경로 
    volumes:
    - name: secret-volume    # 시크릿 볼륨 이름 
      secret:
      	secretName: our-password  # 키-값 쌍을 가져올 시크릿 이름!
    

[ 좀 더 쉽게 컨피그맵과 시크릿 시소스 배포하기 ]

  • 시크릿이나 컨피그맵을 배포하기 위해 YAML 파일을 작성할 때, 데이터를 YAML 파일로부터 분리할 수 있는 kustomize 기능을 사용 가능
secretGenerator:   # 시크릿을 생성하기 위한 지시문 cf. configMapGenerator
- name: kustomize-secret
  type: kubernetes.io/tls.  # tls 타입의 시크릿을 생성
  files: 
  - tls.crt=cert.crt    # tls.crt라는 키에 cert.crt 파일의 내용을 저장
  - tls.key=cert.key.   # tls.key라는 키에 cert.key 파일의 내용을 저장

kubectl apply -k ./로 해당 파일을 통해 시크릿 생성!

--- 3부. 쿠버네티스 고급 기능 활용 ---

08. 인그레스(Ingress)

  • 인그레스는 일반적으로 외부에서 내부로 향하는 것을 지칭하는 단어
  • 외부 요청을 어떻게 처리할 것인지 네트워크 7계층 레벨에서 정의하는 쿠버네티스 오브젝트
  • 기본 기능은 아래와 같다!
    • 외부 요청의 라우팅 : 특정 경로로 들어온 요청을 어떠한 서비스로 전달할지 정의하는 라우팅 규칙
    • 가상 호스트 기반의 요청 처리 : 같은 IP에 대해 다른 도메인 이름으로 요청이 도착했을 때, 어떻게 처리할지 정의
    • SSL/TLS 보안 연결 처리 : 보안 연결을 위한 인증서 적용!

8.1 인그레스를 사용하는 이유

  • 만약 애플리케이션이 3개의 디플로이먼트로 생성되어 있다면, NodePort 또는 LoadBalancer 타입의 서비스를 그에 맞게 3개를 생성해야 한다.

  • 이는 서비스마다 세부적인 설정을 할 때 추가적인 복잡성이 발생한다는 한계가 있음.

  • 인그레스를 사용한다면, 3개의 서비스에 대해 3개의 URL이 각각 존재하지 않고, 인그레스에 접근하기 위한 단 하나의 URL만 존재한다.

    • 클라이언트는 인그레스의 URL로만 접근하고, 해당 요청은 인그레스에서 정의한 규칙에 따라 처리 후 디플로이먼트의 포드로 전달!

→ 라우팅 정의, 보안 연결과 같은 세부 설정이 인그레스에 의해 처리!
→ 즉, 외부 요청에 대한 처리 규칙을 쿠버네티스 자체 기능으로 편리하게 관리 가능!

8.2 인그레스의 구조

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
	name: ingress-example
    annotations:
    	nginx.ingress.kubernetes.io/rewrite-target: /
        kubernetes.io/ingress.class: "nginx"
spec:
	rules:
    - host: alicek106.example.com
      http: 
      	paths:
        - path: /echo-hostname
          backend:
          	serviceName: hostname-service
            servicePort: 80
  • host: 해당 도메인 이름으로 접근하는 요청에 대해 처리 규칙을 적용
    • 위 예시에서는 alicek106.example.com 도메인으로 접근하는 요청만 처리
  • path : 해당 경로에 들어온 요청을 어느 서비스로 전달할 것인지 정의
    • 위 예시에서는 /echo-hostname이라는 경로의 요청을 backend에 정의된 서비스로 전달
  • serviceName, servicePort : path로 들어온 요청이 전달될 서비스와 포트
    • 위 예시에서는 /echo-hostname이라는 경로로 들어온 요청을 hostname-service 서비스의 80 포트로 전달
kubectl apply -f ingress-example.yaml
  • 이렇게 인그레스를 생성해도, 아무 일도 일어나지 않는다.
  • 인그레스는 단지 요청을 처리하는 규칙을 정의하는 선언적인 오브젝트일 뿐, 외부 요청을 받아들을 수 있는 실제 서버가 아니기 때문.
  • 인그레스는 인그레스 컨트롤러라고 하는 특수한 서버에 적용해아 그 규칙을 사용할 수 있음!
    • 실제 외부 요청을 받아들이는 것은 인그레스 컨트롤러 서버이고,
    • 이 서버가 인그레스 규칙을 로드해 사용한다.

[ Nginx 인그레스 컨트롤러 ]

kubectl apply -f \
https://raw.githubusercontent......

→ Nginx 인그레스 컨트롤러 설치

  • 실제 운영 환경으로 AWS, GKE 등을 사용 중이라면, LoadBalancer 타입의 서비스를 생성함으로써, Nginx 인그레스 컨트롤러에 DNS 이름을 할당해 사용하는 방법이 일반적!
kind: Service
apiVersion: v1
metadata:
	name: ingress-nginx
    namespace: ingress-nginx
spec:
	type: LoadBalancer
    selector:
    	app.kubernetes.io/name: ingress-nginx
        app.kuernetes.io/part-of: ingress-nginx
    ports:
    	- name: http
          port: 80
          targetPort: http
        - name: https:
          port: 443
          targetPort: https
  • 이상으로 서비스를 생성

  • Nginx 인그레스 컨트롤러의 포드에 기본적으로 설정된 라벨을 selector에 명시

  • 여기까지, 인그레스, Nginx 인그레스 컨트롤러 및 Nginx 포드에 접근하기 위한 서비스의 준비 완료-!

[ cf. ...elb.amazonaws.com/echo-hostname 접근 시의 에러 ]
→ 404 NOT_FOUND가 반환된다.

  • 인그레스를 생성할 때, Nginx 인그레스 컨트롤러에 alicek106.example.com으로 접근했을 때만 응답을 처리하도록 설정했기 때문!

[ 인그레스 컨트롤러의 동작 원리 이해 ]
1. 공식 깃허브에서 제공되는 YAML 파일로 Nginx 인그레스 컨트롤러를 생성
2. Nginx 인그레스 컨트롤러를 외부로 노출하기 위한 서비스 생성
3. 요청 처리 규칙을 정의하는 인그레스 오브젝트를 생성

→ Nginx 인그레스 컨트롤러로 들어온 요청은 인그레스 규칙에 따라 적절한 서비스로 전달된다.

  • 특정한 경로, 호스트 이름으로 들어온 요청은 인그레스에 정의된 규칙에 따라 서비스로 전달
  • 하지만, 요청이 실제로 hostname-service라는 서비스로 전달되는 것은 아니다.
  • Nginx 인그레스 컨트롤러는 서비스에 의해 생성된 엔드포인트로 요청을 직접 전달한다.
    • 이를 쿠버네티스에서는 bypass라고 한다.
    • 서비스를 거치지 않고 포드로 직접 요청이 전달되므로!

8.3 인그레스의 세부 기능 : annotation을 이용한 설정

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
	name: ingress-example
    annotations:
    	nginx.ingress.kubernetes.io/rewrite-target: /
        kubernetes.io/ingress.class: "nginx"
  • kubernetes.io/ingress.class
    • 해당 인그레스 규칙을 어떤 인그레스 컨트롤러에 적용할지!
  • nginx.ingress.kubernetes.io/rewrite-target
    • 인그레스에 정의된 경로로 들어오는 요청을 rewrite-target에 설정된 경로로 전달한다.
	nginx.ingress.kubernetes.io/rewrite-target: /   # 2
    
      paths:
      - path: /echo-hostname        # 1

→ /echo-hostname 경로로 들어온 요청은
→ hostname-service의 /로 전달한다.

profile
주니어 백엔드 개발자입니다! 조용한 시간에 읽고 쓰는 것을 좋아합니다 :)

0개의 댓글