docker야 이사가자 k8s로! - 1
network, postgresql
by HOON
1
Last updated on Feb. 12, 2025, 10:30 a.m.
안녕하세요, 오늘은 docker에서 운영중이던 제 블로그를 하이퍼바이저를 이용해 k8s 클러스터를 구축하고 옮기는 작업을 진행해보겠습니다. 꽤 긴 내용이 될 것 같아서 여러 포스트로 나누어 작성 할 예정입니다.
큰 주제로는 우선
- VirtualBox로 k8s 클러스터 구축하기.
- Docker-compose 로 운영하던 서비스를 k8s로 마이그레이션
- 실제 접속 테스트 해보기
우선 오늘은 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
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를 따라하면 쉽습니다.
큰 틀은, 우선 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 등 기존 서비스를마저 만들어보겠습니다.
감사합니다.
Leave a Comment: