k3s로 싱글 노드 쿠버네티스 구축해보기

Dierslair·2022년 5월 29일
1

kubernetes

목록 보기
1/5
post-custom-banner

k3sLightweight Kubernetes 라 불리우는 경량 버전의 쿠버네티스입니다.

kubeadm 과 같이 풀 스펙의 쿠버네티스를 구현하려면 마스터 노드 1개, 백업용 마스터 노드 3개, 기타 워커 노드를 합쳐 서버 인스턴스가 최소 5개 있어야 하는 조건이 있어(고가용 서버를 위한 권고사항입니다. HA Topology) 쿠버네티스의 편리한 기능은 사용하되 아주 큰 아키텍처가 아닌 경우 k3s 는 간단하게 사용하기에 좋습니다.

k3s 설치하기

  • 서버 인스턴스를 할당하고 k3s 를 설치합니다.
$ curl -sfL https://get.k3s.io | sh -
===
[INFO]  Finding release for channel stable
[INFO]  Using v1.23.6+k3s1 as release
[INFO]  Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.23.6+k3s1/sha256sum-amd64.txt
[INFO]  Downloading binary https://github.com/k3s-io/k3s/releases/download/v1.23.6+k3s1/k3s
...
[INFO]  systemd: Starting k3s
  • 현재 사용자(ubuntu) 에서 kubectl 명령어를 사용하기 위해 다음 추가 작업을 진행합니다.
$ mkdir ~/.kube
$ sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
$ sudo chmod 644 ~/.kube/config
$ sudo chown $(id -u):$(id -g) ~/.kube/config
$ echo 'export KUBECONFIG="/home/ubuntu/.kube/config"' >> ~/.bashrc
  • kubectl 명령어를 사용하여 정상적으로 설치되었는지 확인합니다.
$ kubectl get node
===
NAME              STATUS   ROLES                  AGE   VERSION
ip-[  YOUR-IP ]   Ready    control-plane,master   54s   v1.23.6+k3s1

kubectl 단축어 등록

  • kubectl 명령어는 비교적 길어 불편하니 단축어를 추가해 줍니다.
$ echo 'alias k="kubectl"' >> ~/.bashrc
$ source ~/.bashrc
  • 이제 명령어는 k 로 사용할 수 있습니다.

Ingress 사용해 보기

  • Ingress 는 외부에서 쿠버네티스 클러스터에 접근하기 위한 오브젝트를 가리키며 NGINX, Traefik 등의 구현이 있습니다. k3sTraefik 을 번들로 제공하고 있습니다. 위에서 생성한 서버 인스턴스에 도메인을 할당하고 접속하면 404 page not found 메시지가 표시되는데, 이 메시지는 Traefik 이 생성한 메시지입니다. 아직 아무런 서비스가 없기 때문에 정상입니다.

테스트 애플리케이션 - 에코서버 배포

  • 테스트를 위해 도커 애플리케이션 이미지를 만들기는 번거로우니 적절히 에코서버 이미지를 가져와서 디플로이먼트를 사용하여 배포해 보겠습니다.
$ mkdir ~/k3s
$ cd ~/k3s
$ vi echo-server.yml
# echo-sever.yml

# 서비스
---
apiVersion: v1
kind: Service
metadata:
  name: echo-server
  labels:
    app: echo-server
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  selector:
    app: echo-server

# 디플로이먼트
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-server
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: echo-server
  template:
    metadata:
      labels:
        app: echo-server
    spec:
      containers:
        - name: echo-server
          image: ealen/echo-server:0.5.2
          imagePullPolicy: Always
          ports:
            - containerPort: 80
          resources:
            limits:
              cpu: "0.5"
              memory: "1Gi"
$ k apply -f echo-server.yml # 서비스와 디플로이먼트를 적용합니다.
===
service/echo-server created
deployment.apps/echo-server created

$ k get pods # 포드 목록을 나열합니다.
===
NAME                          READY   STATUS    RESTARTS   AGE
echo-server-bcbdd76c4-gkhtx   1/1     Running   0          22s

Traefik을 사용해 외부로 서비스 노출하기

  • 파드는 서비스의 형태로 배포되었지만, 호스트에서 해당 파드로 직접 접근할 수는 없습니다.
    Ingress 를 사용하여 Ingress Controller 에게 생성한 서비스를 연결해 주어야 외부에서 80 포트로 접근이 가능합니다.
$ cd ~/k3s
$ vi traefik.yml
# traefik.yml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-routers
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
    - host: [YOUR_DOMAIN]
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: echo-server
                port:
                  number: 80
$ k apply -f traefik.yml
===
ingress.networking.k8s.io/traefik-routers created
  • 외부에서 도메인 이름으로 접근하면 200 응답과 함께 다음 내용을 볼 수 있습니다.
{"host":{"hostname":"{domain}","ip":"::ffff:10.42.0.8","ips":[]},"http":{"method":"GET","baseUrl":"","originalUrl":"/","protocol":"http"},"request":{"params":{"0":"/"},"query":{},"cookies":{},"body":{},"headers":{"host":"{domain}","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15","accept":"text/html,application/xhtml+xml...

cert-manager 와 Let's Encrypt로 TLS 구현하기

  • 이번에는 cert-managerletsencrypt 를 사용하여 TLS 인증서를 적용해 보도록 하겠습니다.

helmcert-manager 설치

  • 쿠버네티스 패키지 매니저 helm 이 필요합니다. 리눅스 우분투이니 apt-get 을 사용해서 설치합니다.
$ curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
$ sudo apt-get install apt-transport-https --yes
$ echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
$ sudo apt-get update
$ sudo apt-get install helm
  • helm 이 설치되면 helm 을 사용하여 cert-manager 를 설치합니다.
$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ curl -L -o cert-manager.yml https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml
$ k apply -f cert-manager.yml
$ helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.8.0
$ k get pods --namespace=cert-manager
===
NAME                                       READY   STATUS      RESTARTS   AGE
cert-manager-cainjector-5c55bb7cb4-schmh   1/1     Running     0          5m16s
cert-manager-76578c9687-jgqmp              1/1     Running     0          5m16s
cert-manager-webhook-556f979d7f-7l99s      1/1     Running     0          5m16s
cert-manager-startupapicheck-xt556         0/1     Completed   0          5m15s

issuer 등록

  • 인증서를 만들기 전, 발급자를 등록해 주어야 합니다. letsencrypt 에 대한 tls-issuer.yml 를 작성합니다.
# tls-issuer.yml
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: tls-issuer # 마음대로 지정합니다
  namespace: default
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [YOUR_EMAIL]
    privateKeySecretRef:
      name: tls-key # 마음대로 지정합니다
    solvers:
      - selector: {}
        http01:
          ingress:
            class: traefik
  • tls-issuer.yml 를 등록하고 상태를 확인합니다. Ready: True 상태로 변경되기 까지 시간이 조금 걸릴 수 있습니다.
$ k create -f tls-issuer.yml
$ k get issuer -o wide
===
NAME         READY   STATUS                                                 AGE
tls-issuer   True    The ACME account was registered with the ACME server   4m31s

certificate 생성

  • 인증서를 만듭니다.
# tls-cert.yml
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: tls-cert
  namespace: default
spec:
  secretName: tls-secret # 마음대로 작성
  issuerRef:
    name: tls-issuer # 위에서 지정한 이름
  commonName: [YOUR_DOMAIN]
  dnsNames:
    - [YOUR_DOMAIN]
    # 서브도메인 등록 가능
    # - sub.example.com
  • 이제 인증서를 발급합니다. 편리하게도 더미 인증서 제작 -> acme 핸드쉐이크 -> 실제 인증서 발급 및 적용 -> 더미 인증서 파기 의 과정을 자동으로 처리해 줍니다.
$ k create -f tls-cert.yml
$ k get certificate -o wide
===
NAME         READY   SECRET       ISSUER       STATUS                                          AGE
tls-secret   True    tls-secret   tls-issuer   Certificate is up to date and has not expired   7m57s
tls-cert     True    tls-secret   tls-issuer   Certificate is up to date and has not expired   6s
  • 마찬가지로 Ready: True 상태가 되기까지 시간이 조금 걸릴 수 있습니다.

Ingress Controller 에 인증서 정보 전달하기

  • 인증서 발급이 성공적으로 처리되었으니 이제 traefik.yml 에서 인증서와 비밀 키 정보를 전달하면 TLS를 사용할 수 있습니다.
# traefik.yml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-routers
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
    - host: [YOUR_DOMAIN]
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: echo-server
                port:
                  number: 80
  tls:
    - secretName: tls-secret # tls-cert 에서 지정한 키 이름
      hosts:
        - [YOUR_DOMAIN]
  • cert-manager 플러그인이 인증서 파기 1개월 전에 자동갱신 처리해 주니 신경 쓸 필요가 없어 아주 좋습니다. describe 명령어를 통해 인증서 만료일과 갱신 예정일을 확인해 볼 수 있습니다.
$ k describe certificate tls-cert
===
Status:
  Conditions:
    ...
  Not After:               2022-08-27T05:17:51Z
  Not Before:              2022-05-29T05:17:52Z
  Renewal Time:            2022-07-28T05:17:51Z
  Revision:                1
Events:
  Type    Reason     Age   From                                       Message
  ----    ------     ----  ----                                       -------
  ...
  Normal  Issuing    12m   cert-manager-certificates-issuing          The certificate has been successfully issued

해당 포스트는 k3s, Traefik Ingress를 참고하여 작성되었습니다.

profile
Java/Kotlin Backend Developer
post-custom-banner

0개의 댓글