k8s

docker야 이사가자 k8s로! - 1

network, postgresql

by HOON


1

Last updated on Feb. 12, 2025, 10:30 a.m.


random_image

안녕하세요, 오늘은 docker에서 운영중이던 제 블로그를 하이퍼바이저를 이용해 k8s 클러스터를 구축하고 옮기는 작업을 진행해보겠습니다. 꽤 긴 내용이 될 것 같아서 여러 포스트로 나누어 작성 할 예정입니다.

큰 주제로는 우선

  1. VirtualBox로 k8s 클러스터 구축하기.
  2. Docker-compose 로 운영하던 서비스를 k8s로 마이그레이션
  3. 실제 접속 테스트 해보기

우선 오늘은 1번 클러스터 구축으로 시작해보겠습니다.


1. 네트워크 구성

아무래도 저는 집에서만 작업하는게 아닌, 카페를 자주 이용하기때문에 네트워크가 변동되는데요,
물론 NAT네트워크를 사용하면 네트워크 변경에 제약없이 가상머신을 사용 할 수 있습니다.
다만 k8s는 ip가 변경됨에따라 수정해야 할 부분이 많은 것 같더라구요, (kubelet, kubeadm, kubectl,etcd 등) 따라서 k8s의 ip는 변경되지 않는게 좋을 것 같네요. (k8s에서 host기반 인식하는게 있다고 하는데, 저는 네트워크 구성 자체를 설정하겠습니다.)

제가 생각한 네트워크 구조는 NAT + Host Only 구조입니다.
큰 그림은 다음과 같습니다.

이렇게 구성하면 저는 어디서 작업을 하든 외부 인터넷은 NAT 네트워크를 사용하고,
내부 kubernetes의 통신은 192.168.220.x 로 지정함으로써 고정된 IP로 사용이 가능한거죠.

그럼 실제 VirtualBox에서 설정해보겠습니다.
우선 저는 기존에 사용하던 2개의 가상머신이 있습니다. ubuntu22 버전이에요.
호스트 이름을 각각 k8s-master, k8s-node1로 지정했습니다. (master와 node1의 차이는 ssh 접속 포트번호밖에 없는 것 같아서 master로만 설명 하겠습니다.

우선 마스터노드부터 진행하겠습니다.
가상머신 접속 후 ip를 고정해줄게요.

network:
  version: 2
  renderer: networkd
  ethernets:
    # NAT 인터페이스(예: enp0s3)는 DHCP 켜두는 게 일반적입니다.
    enp0s3:
      dhcp4: true

    # Host-Only 인터페이스(예: enp0s8)에 고정 IP 할당
    enp0s8:
      addresses:
        - 192.168.220.100/24
      # gateway4: 192.168.220.1  # 보통 Host-Only에는 게이트웨이를 지정 안 해도 됨
      nameservers:
        addresses: [8.8.8.8, 1.1.1.1]

인터넷 연결이 잘 되나 확인해볼까요??

k8s-master@k8s-master:~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=255 time=55.0 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=255 time=53.4 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=255 time=53.8 ms

이상없이 잘 되네요! 이 인터넷은 NAT 네트워크를 통한거겠죠??

저는 ssh로 접속하기위해 NAT 네트워크에서 포트포워딩을 하겠습니다.

이렇게 되면 2222번으로 들어온 TCP 연결을 VM 내부의 22번으로 전달하겠다는 뜻입니다.
따라서 ssh -p 2222 @127.0.0.1 로 접속하면 접속이 가능하게 됩니다.

ssh -p 2222 k8s-master@127.0.0.1                                                      ✔
. . . 
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:2222' (ED25519) to the list of known hosts.
k8s-master@127.0.0.1's password:
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-144-generic x86_64)
. . .
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
New release '22.04.5 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Sun Feb  9 04:01:12 2025
k8s-master@k8s-master:~$

2. 클러스터 초기설정 및 연결

자, 이제 ssh 접속도 확인했으니, kubernetes 클러스터 환경을 구축해보겠습니다.
우선 저는 아까 그림과 같이 master-node , worker-node1 로 구성하겠습니다.
클러스터 환경 구성은 docs를 따라하면 쉽습니다.

k8s docs

큰 틀은, 우선 master 노드를 주로 설정해주면 됩니다. 설치 후 아래 명령어를 수행해줄게요.

$ kubeadm init
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a Pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  /docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>

내용을 보면, .kube/config 환경을 설정해줘야합니다. 따라서 그대로 입력합니다.

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

또한 master node를 설정했으니, 실제 작업을 수행 할 worker node도 설정해줘야겠죠??
설치까지 똑같으나 worker node는 kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash> 를 수행해주면 됩니다.

추가로, 저희는 고정된 Host Only 네트워크를 통해 ip를 고정해주기로 했죠??
따라서 /var/lib/kubelet/kubeadm-flags.env 파일에 —node-ip 옵션을 추가할게요. (worker node도 동일합니다.)

$ vim /var/lib/kubelet/kubeadm-flags.env

KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.9 --node-ip=192.168.220.100"

그럼 아래와 같이 성공적으로 연결 된 상황을 볼 수 있어요. 둘 다 Ready 상태로 이제 클러스터가 구성되었습니다.

k8s-master@k8s-master:~$ k get nodes -o wide
NAME         STATUS   ROLES           AGE     VERSION    INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
k8s-master   Ready    control-plane   7h4m    v1.29.11   192.168.220.100   <none>        Ubuntu 20.04.6 LTS   5.4.0-144-generic   containerd://1.7.24
k8s-node1    Ready    <none>          6h54m   v1.29.11   192.168.220.110   <none>        Ubuntu 20.04.6 LTS   5.4.0-144-generic   containerd://1.7.24

3. 리소스 생성 테스트

그럼 간단히 postgresql 리소스만 한번 생성 해 볼까요??
우선 pvc, pv, secret, service, deployment.yaml 을 생성할게요.

#postgres-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

#postgres-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgres-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/data/postgres


$ k apply -f postgres-pvc.yaml
$ k apply -f postgres-pv.yaml

$ k get pvc,pv
NAME                                 STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/postgres-pvc   Bound    postgres-pv   1Gi        RWO                           <unset>                 6h53m

NAME                           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/postgres-pv   1Gi        RWO            Retain           Bound    default/postgres-pvc                  <unset>                          6h53m

pvc와 pv가 정상적으로 Bound 됐네요!
그럼 나머지 마저 생성해볼게요.

# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  POSTGRES_USER: "<DB_USER>"
  POSTGRES_PASSWORD: "<DB_PASSWORD>"

# postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432
      protocol: TCP

# postgres-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:12.0-alpine
          env:
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: POSTGRES_USER
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: POSTGRES_PASSWORD
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: postgres-data
              mountPath: /var/lib/postgresql/data
      volumes:
        - name: postgres-data
          persistentVolumeClaim:
            claimName: postgres-pvc


$ k apply -f db-secret.yaml
$ k apply -f postgres-service.yaml
$ k apply -f postgres-deployment.yaml

$ k get pods
NAME                               READY   STATUS    RESTARTS   AGE
postgres-deploy-7bb6d74d79-vwsvt   1/1     Running   0          94m

정상적으로 생성되고 Running 상태라는걸 확인 할 수 있습니다!

그럼 실제 서버에서 운영되던 db 내용을 백업해서, k8s로 restore 해보겠습니다.

명령어는 차례대로 아래와 같습니다.

# 기존 서버에서
docker exec -it postgresql pg_dump -U <DB유저> -d <DB이름> > backup.sql

# masternode에서
# K8s 클러스터 내 Postgres Pod를 찾기
kubectl get pods -l app=postgres
# 예: postgres-deploy-xxx 형태가 있을 것

# 백업 파일을 Pod 안으로 복사
kubectl cp backup.sql default/postgres-deploy-xxx:/tmp/backup.sql

# Pod 내부에서 복원
kubectl exec -it postgres-deploy-xxx -- bash
psql -U <DB유저> -d <DB이름> -f /tmp/backup.sql
# 혹은 pg_restore -U <DB유저> -d <DB이름> /tmp/backup.sql

그럼 실제 서버에서 운영되던 db 내용을 백업해서, k8s로 restore 해보겠습니다.
명령어는 차례대로 아래와 같습니다.

# 기존 서버에서
docker exec -it postgresql pg_dump -U <DB유저> -d <DB이름> > backup.sql

# masternode에서
# K8s 클러스터 내 Postgres Pod를 찾기
kubectl get pods -l app=postgres
# 예: postgres-deploy-xxx 형태가 있을 것

# 백업 파일을 Pod 안으로 복사
kubectl cp backup.sql default/postgres-deploy-xxx:/tmp/backup.sql

# Pod 내부에서 복원
kubectl exec -it postgres-deploy-xxx -- bash
psql -U <DB유저> -d <DB이름> -f /tmp/backup.sql
# 혹은 pg_restore -U <DB유저> -d <DB이름> /tmp/backup.sql

다음은, 실제로 컨테이너에 접속해서 db가 restore 됐는지 확인해볼게요.

$ kubectl exec -it postgres-deploy-7bb6d74d79-vwsvt -- bash
bash-5.0# psql -U db_user -d postgres -f /tmp/backup.sql

SET
SET
SET
SET
SET
 set_config
------------

(1 row)

SET
SET
SET
SET
CREATE EXTENSION
COMMENT
SET
SET

. . .

ALTER TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

postgres=# SELECT * FROM blog_post;
 id |                   title                   |                           hook_text                            |                                                                                                                                                                                         content                                                                                                                                                                                          
----+-------------------------------------------+----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  5 | Django TODO List                          |                                                                | <h4>기본</h4>\r                                                                                                                                                                                                                                                                                                                                                                         
    |                                           |                                                                | - [x] 구글 Login 400 Error -> Google API 콘솔  Redirect url 설정에 도메인 추가로 해결\r

많은 부분을 생략했지만, db가 제대로 들어가있는걸 확인 할 수 있습니다!

다음 포스트는 실제 운영하던 web,nginx 등 기존 서비스를마저 만들어보겠습니다.

감사합니다.

×
k8s linux


Leave a Comment: