최근 개인적으로 DevOps와 관련하여 프로젝트를 진행하고 있다. 개발자 둘과 협업하여 프로젝트를 진행 중인데, 그중 내가 담당하고 있는 부분은 인프라 제공과 CI/CD 파이프라인을 구성하는 것이다. 인프라는 Kubernetes를 기반으로 제공할 예정이고, 이미 구축을 완료한 상태이다. CI/CD 파이프라인에 대해서는 어느 정도 학습이 된 상태인데, 개발에 대한 이해가 거의 전무해서 이 부분에 대한 학습이 필요했다. 함께 프로젝트를 하고 있는 동료들에게 매번 물어볼 수 도 없는 일이어서 고민하던 차에 패스트캠퍼스의 「코딩 1:8 | 웹 개발 왕초보 입문」 과정을 발견하게 되었다.

 내일배움카드를 소지하고 있으면 신청이 가능한데, 국비지원교육으로 클라우드 엔지니어 과정을 이수했던 터라 신청이 어렵지는 않았다. 개인은 4만 원만 부담하면 되고 이것 역시도 미션을 달성하면 환급이 가능해서 당장 신청을 했고 선발될 수 있었다.

 

 강의는 비대면으로, 동영상을 시청하는 형식으로 약 10분 내외의 적당한 길이의 강의로 이루어져 있었다. 군더더기 없는 강사님의 설명과 속도감 있는 수업은 강의를 듣는 내내 지루할 틈이 없었다. 크게 5개의 파트로 이루어져 있고 본격적인 내용은 네 번째 파트에서 프로젝트를 진행하면서 이루어진다. 강의에 집중하고 코드를 잘 따라서 친다면 크게 무리 없이 진행이 가능하다.

 

 특히 좋았던 점은 Github에 개발한 코드를 업로드하고 Netlify를 통해 서비스를 론칭 하는 것까지 해 볼 수 있다는 점이었다. 사실 개발 과정도 과정이지만 이 부분이 나에게 가장 필요한 부분이었다. 강의에서는 작성한 코드를 Github에 push 하고 이를 웹 서비스로 연동하는 과정에서으로 진행하였지만 나는 이 부분을 좀 다르게 진행하기로 했다.

 

 바로 Home Lab 환경에 올려 보기로 한 것이다. 이미 Cilium의 BGP 기능과 OPNsense의 연동을 통해 Kubernetes의 Service의 한 종류인 Loadbalancer를 구성해 둔 상태였기 때문에 실제 작동할 서비스만 있으면 되었는데 이번 강의를 통해 그 내용을 얻을 수 있었다.

[사진1] Home Lab 환경 제대로 한번 써 보자...

 

 

내 안에 숨어있는 직업캐 찾기!

누구나 찰떡인 직업이 있어요! 내 안에 숨어있는 직업캐를 찾아보세요!

mbti.greenist.synology.me

 위 링크가 바로 그 결과물이다. Home Lab 환경의 Kubernetes가 Loadbalancer 기능을 통해 클러스터 외부로 서비스를 노출하고, 이를 리버스 프록시를 통해 인터넷으로 서비스를 하고 있는 것이다.

[사진 2] Netlify가 아닌 Synology DDNS를 통한 서비스

 구축해둔 Kubernetes 클러스터에서 위 프로젝트가 위치하고 있는 mbti 네임스페이스의 정보를 조회해 보면 아래와 같이 조회가 된다.

[사진 3] mbit 웹 서비스를 위한 Kubernetes의 각종 요소들

 Loadbalance에서 부여받은 가상 IP 주소인 10.150.0.3을 Reverse Proxy가 서비스하고 있다고 보면 된다. 아래는 관련 Yaml파일 내용이다.

#deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mbti-deploy
  namespace: mbti
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mbti
  template:
    metadata:
      labels:
        app: mbti
    spec:
      containers:
        - name: mbti
          image: nginx
          ports:
            - name: http
              containerPort: 80
          volumeMounts:
            - name: mbti-web
              mountPath: /usr/share/nginx/html
      volumes:
        - name: mbti-web
          persistentVolumeClaim:
              claimName: mbti-pvc

 우선 웹 서버 역할을 하는 Nginx의 deployment.yaml 파일의 내용이다. 사실 pvc까지는 필요 없지만 관련 내용 스터디와 테스트를 위해 작성해 봤다.

#service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mbti-service
  namespace: mbti
spec:
  selector:
    app: mbti
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80

 다음으로 service.yaml 파일의 내용이다. 간단한 내용으로 Nginx deployment를 Loadbalancer 형식으로 외부로 서비스해준다.

#volume.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mbti-pvc
  namespace: mbti
spec:
  storageClassName: sc-fast
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20M

 마지막으로 PVC의 내용인데 NAS를 바라보고 있는 Storageclass를 호출하여 PV를 생성한다. 해당 PVC 통해 생성된 PV가 Nginx 웹 서버의 html의 파일 볼륨을 제공한다.

 

 이를 통해 간단한 개발과정과 이를 직접 서비스하는 것까지 한번 경험해 볼 수 있는 소중한 시간이었다. 많은 부분을 학습할 수 있었고 협업 프로젝트를 진행하는데 많은 도움이 된 것 같다. 기회가 본격적인 백엔드 강의도 한번 들어볼 수 있는 시간을 가지고 싶다.

0. 들어가며

 지난 포스팅을 통해 Kubernetes 클러스터를 구축해 보았다. 그러나 CNI(Container Network Interface)가 설치되지 않아 각 노드의 상태가 NotReady인 것을 확인하였다.

 

[Ubuntu 22.04] Kubernetes Cluster 구축 - 2편

0. 들어가며 [Ubuntu 22.04] Kubernetes Cluster 구축 - 1편에서 이어지는 내용으로 전편을 참고한 후 해당 포스팅을 보는 것을 추천드린다. [Ubuntu 22.04] Kubernetes Cluster 구축 - 1편 0. 들어가며 Kubernetes 강의를

tech-recipe.tistory.com

 이번 포스팅에서는 Kubernetes 클러스터에 필수 Plug-in인 CNI에 대해 살펴보고 어떻게 구성할 수 있는지 알아보도록 하겠다.

 

1. CNI란?

  Kubernetes 클러스터에는 수많은 Pod들이 생성과 삭제를 반복한다. 어떠한 이유로 Pod가 작동 불능 상태가 되면 Kubernetes 클러스터는 이를 감지하고 Pod를 폐기한 후 새로운 Pod를 실행시킨다. Pod는 각각 고유의 IP 주소를 가지고 있지만, 이는 고정적인 것이 아니기 때문에 Pod가 새로 생성되면 이 주소 역시 변하게 된다. 이러한 유동적인 IP 주소를 관리자가 직접 관리하는 것은 거의 불가능한 일이다.

 게다가 Kuberntes는 멀티 노드 환경에서 구현되기 때문에 각 Pod들 간의 통신에 있어 노드를 넘나들어야 하는 경우도 빈번하다. 이런 경우에 각 Pod들이 서로 통신하기 위한 오버레이 네트워크가 필요하게 된다. 이 외에도 여러 가지 문제점들이 있는데 이를 해결하기 위해 만들어진 컨테이너 네트워킹 제어를 위한 표준이 바로 CNI라 생각하면 된다.

[사진 1] CNCF의 여러 프로젝트 중 CNI와 관련된 Plug-in

 CNCF Lnadscape에서 확인해 보면 CNI만 해도 여러 종류가 있다. 각 CNI는 각각의 기능과 특징에 차이는 있어 어떤 CNI를 사용해야 할지부터가 고민이다. 여러 Kubernetes 강의에서 자주 등장하는 Calico가 대표적인데 그 외에도 VMware에서 후원하는 Antrea도 있고, Flannel, Weave net 등 여러 가지가 있다.

 이 중, 이번 포스팅에 사용하게 될 CNI는 Cilium이다. 이를 선택하게 된 이유는 우선 CNCF에서 밀어주는 프로젝트이기도 하고, 현재 개인적으로 진행하는 프로젝트에 On-Premise 환경에서 BGP를 사용하여 LoadBalancer 기능을 사용할 수 있기 때문이기도 하다. (참고로 Calico 역시 BGP를 기반으로 하고 있어 On-Premise 환경에서 LoadBalancer 기능을 사용할 수 있다.)

 

2. 설치 진행

 1) Helm

 

Helm

Helm - The Kubernetes Package Manager.

helm.sh

 Kubernetes에는 여러가지 Add-on들이 존재한다. 이를 쉽게 설치하고 사용하기 위한 툴인 Helm이라는 것이 있는데, 이를 이용해 Cilium 설치를 간단히 수행해 보고자 한다. 먼저 Helm을 설치해 보자.

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
sudo apt-get install apt-transport-https --yes
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] 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 chart 설치는 비교적 간단하다. 위 다섯 줄 명령어를 차례로 실행시켜 줌으로써 Helm 설치가 완료된다.

 

 2) Cilium repo 추가 및 설치

 

Installation using Helm — Cilium 1.14.2 documentation

If you are running an ACK cluster, you should delete the ACK CNI. Cilium will manage ENIs instead of the ACK CNI, so any running DaemonSet from the list below has to be deleted to prevent conflicts. Note If you are using ACK with Flannel (DaemonSet kube-fl

docs.cilium.io

 위 링크를 통해 Cilium 설치를 확인할 수 있다. 공식 문서를 참고하는 것이 조금 더 도움이 될 것 같아 링크를 첨부했다. 아래는 그 내용을 정리한 것이다.

helm repo add cilium https://helm.cilium.io/
#helm의 cilium repo 추가

helm install cilium cilium/cilium --version 1.14.2 \
  --namespace kube-system
#cilium 설치

NAME: cilium
LAST DEPLOYED: Sun Oct 15 05:56:57 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
You have successfully installed Cilium with Hubble.

Your release version is 1.14.2.

For any further help, visit https://docs.cilium.io/en/v1.14/gettinghelp

[사진 2] Helm의 Cilium repo 추가 및 설치

 cilium 컨테이너가 모두 배포되는데 약간의 시간이 소요된다. 잠시 후 kubectl get pods -A 명령어를 실행해 보면 cilium 컨테이너들이 설치된 것을 볼 수 있고, 더하여 core-dns Pod들이 정상 작동 하는 것도 확인할 수 있다.

[사진 3] Kubernetes Pod와 Node 모두 정상 작동하는 모습 확인

 

 3) Cilium CLI 설치

 위 설치 과정만으로도 Cilium은 훌륭하게 작동한다. 그러나 더 Cilium의 더 많은 기능을 사용하기 위해서는 Cilium CLI를 설치해야 한다. 설치 방법은 역시 간단하다.

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

 위 명령어를 각각 한 줄씩 입력해 주면 설치가 완료된다. 설치가 잘 되었는지 확인하기 위해서 아래 명령어를 실행해 보면 다음과 같은 결과를 얻을 수 있다.

cilium status --wait

    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    disabled (using embedded mode)
 \__/¯¯\__/    Hubble Relay:       disabled
    \__/       ClusterMesh:        disabled

Deployment             cilium-operator    Desired: 2, Ready: 2/2, Available: 2/2
DaemonSet              cilium             Desired: 4, Ready: 4/4, Available: 4/4
Containers:            cilium             Running: 4
                       cilium-operator    Running: 2
Cluster Pods:          2/2 managed by Cilium
Helm chart version:    1.14.2
Image versions         cilium             quay.io/cilium/cilium:v1.14.2@sha256:6263f3a3d5d63b267b538298dbeb5ae87da3efacf09a2c620446c873ba807d35: 4
                       cilium-operator    quay.io/cilium/operator-generic:v1.14.2@sha256:52f70250dea22e506959439a7c4ea31b10fe8375db62f5c27ab746e3a2af866d: 2

[사진 4] Cilim CLI를 통한 Cilium 상태 확인

 

3. 마무리

 3편에 결친 긴 포스팅을 통해 Kubernetes 클러스터를 On-Premise 환경에서 구축해 보았다. 물론 누군가 만들어둔 스크립트를 명령어 한 번의 실행을 통해 Kubernetes 클러스터를 쉽게 구축할 수도 있을 것이다. 그 방법이 확실하게 더 편하고 쉬운 방법임에는 틀림이 없다. 또한, 직접 Kubernetes 클러스터를 구축한다고 하여 Kubernetes를 모두 이해할 수 있는 것은 절대로 아니겠지만, 그럼에도 이러한 수고로운 과정을 통해 Kubernetes에 대한 이해가 한층 올라갈 수 있다고 생각한다.

 

 그러면 긴 포스팅을 이쯤 마무리하도록 하겠다.

0. 들어가며

 [Ubuntu 22.04] Kubernetes Cluster 구축 - 1편에서 이어지는 내용으로 전편을 참고한 후 해당 포스팅을 보는 것을 추천드린다. 

 

[Ubuntu 22.04] Kubernetes Cluster 구축 - 1편

0. 들어가며 Kubernetes 강의를 들어보면 대부분 Vagrant나 Minikube와 같은 것으로 클러스터를 구축한다. 이 부분이 항상 아쉬운 부분이다. 물론 수강생들의 수강 환경이 천차만별이기 때문에 이를 통

tech-recipe.tistory.com

 Ubuntu 설치가 성공적으로 완료되었다면 ssh 툴을 이용하여 k8s-cp에 접속한 후 다음 작업을 실행하도록 한다. 본 포스팅에서는 Termius라는 ssh 툴을 사용하였으며, 다른 익숙한 툴이 있다면 어떤 것을 사용해도 무방하다. 바로 다음 설치 과정에 대하여 알아보도록 하겠다. 모든 과정은 admin 권한을 가지고 있는 sudo 유저로 진행되는데 전편에서 설치 중 생성한 계정이 이를 만족하므로 크게 신경 쓰지 않아도 된다.

 

1. 설치 진행

 2) Kubernetes 클러스터 구성을 위한 공통 설정 작업

  (1) /etc/hosts 파일 내용 수정

 ssh툴을 통해 k8s-cp 노드에 접속 후, /etc/hosts 파일에 내용을 아래와 같이 수정해주고 저장한다.

#/etc/hosts 파일 내용 수정

127.0.0.1 localhost
127.0.1.1 k8s-cp
192.168.0.150 k8s-cp
192.168.0.151 k8s-w01
192.168.0.152 k8s-w02
192.168.0.153 k8s-w03

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

[사진 1] /ect/hosts 파일 수정

 만약 hostname이 정상적이지 않으면 Kubernetes 클러스터 구성 시 문제가 생길 수 있다. 사소한 부분인 것 같지만 신경 써 줘야 한다. 이전 설치 과정에서 server name을 지정해 주었기 때문에 컨트롤 플레인 노드에서는 /etc/hosts 파일만 수정하면 되지만, 이후 VM 복사로 만들어지는 워커 노드의 경우 hostname 수정이 꼭 필요하다.

 

  (2) Swap 메모리 기능 끄기와 커널 파라미터 추가

 Kubernetes에서는 메모리 오버 커밋으로 인한 성능 저하 이슈를 피하고자 의도적으로 Swap 메모리 기능을 끄도록 권장한다. 물론 Kubernetes 1.22 버전 부터 Swap 메모리를 사용하여도 설치가 가능하도록 변경되긴 하였으나 그럼에도 불구하고 Swap 메모리를 끄는 것이 더 권장되고 있다. 아래 링크를 참고하거나 구글에서 'Swap off on Kubernetes'와 같은 키워드로 검색하면 Swap 메모리를 끄는 이유에 대해 좀 더 자세한 이유를 확인할 수 있다.

 

Why disable swap on kubernetes

Since Kubernetes 1.8, it seems I need to disable swap on my nodes (or set --fail-swap-on to false). I cannot find the technical reason why Kubernetes insists on the swap being disabled. Is this for

serverfault.com

sudo swapoff -a
#swap 메모리 기능 끄기

sudo vim /etc/fstab
#/etc/fstab 파일 편집

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation
/dev/disk/by-id/dm-uuid-LVM-x93Y2LQWPORE2IhzvLJa1nWivxAsIJYKgeZukll779GGILhsrRZN0ndEcYTJmfik / ext4 defaults 0 1
# /boot was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/e2778f13-50eb-4a1b-b6ff-e2608ac1cfa8 /boot ext4 defaults 0 1
#/swap.img      none    swap    sw      0       0

#가장 아래의 /swap.img행 맨 앞에 '#'를 추가하여 주석 처리

 우선 sudo swapoff -a를 통해 현재 활성화된 swap 메모리를 꺼주고, 재부팅시에도 해당 설정이 적용될 수 있도록 /etc/fstab 파일을 열어서 맨 아래 행에 있는 /swap.img를 주석처리 해 준다.

#커널 모듈 로드

sudo tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

 그리고 커널 모듈을 로드하기 위해 위 명령어를 입력해 준다. 이 후, tee 명령어를 통해 커널 파라미터 설정을 해 준다.

sudo tee /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

[사진 2] 커널 모듈과 관련된 설정을 위와 같이 입력

 이렇게 하면 /etc/modules-load.d 경로에 container.conf 파일과 /etc/sysctl.d 경로에 kubernetes.conf 파일이 생성되고 EOF 문자 사이의 내용이 입력되게 된다. 위 변경사항을 적용하기 위해 아래 명령어를 입력한다.

sudo sysctl --system

[사진 3] 하단 '* Applying /ect/sysctl.d/kubernetes.conf ...' 설정 확인 가능

 

  (3) 컨테이너 런타임 설치

 Kubernetes의 Pod 내부의 컨테이너는 컨테이너 런타임에 의해 생성된다. 해당 포스팅에서는 Kubernetes의 CRI(Container Runtime Interface) 표준을 만족하는 Containerd를 컨테이너 런타임으로 사용한다. 여담으로, 예전에는 Kubernetes에서는 컨테이너 런타임으로 Docker를 사용할 수 있었지만 1.20 버전 이후부터 Docker의 지원을 중단했다. 관련 내용은 아래 링크 및 'docker shim'에 관한 키워드로 구글링해 보면 자세한 내용을 알 수 있다.

 

Don't Panic: Kubernetes and Docker

Update: Kubernetes support for Docker via dockershim is now removed. For more information, read the removal FAQ. You can also discuss the deprecation via a dedicated GitHub issue. Authors: Jorge Castro, Duffie Cooley, Kat Cosgrove, Justin Garrison, Noah Ka

kubernetes.io

 이미 많은 분들이 해당 내용에 대해 이해를 하고 있을 것이라고 생각한다. 그럼에도 불구하고 이 내용을 언급하는데는, Kubernetes를 학습하는 데 있어 중요한 부분이라 생각하기 때문이다. 시간을 들여서 해당 내용을 이해한다면 Kubernetes에 대한 식견이 조금 더 넓어질 수 있을 것이다.

 

 먼저, 의존성이 있는 패키지를 먼저 설치하고 Containerd를 설치한다.

sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

 이후 docker 리포지터리를 enable 해 준다.

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
#진행을 위해 Enter 입력

 그리고, 아래 명령어를 실행하여 Containerd를 설치한다.

sudo apt update
sudo apt install -y containerd.io

 설치가 완료되면, Containerd가 systemd를 cgroup으로 사용하여 시작할 수 있도록 구성한다.

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

 Containerd 서비스를 재시작 하고 자동 실행 등록을 해 준다.

sudo systemctl restart containerd
sudo systemctl enable containerd

 

  (4) Kubernetes용 APT 리포지터리 추가 및 Kubelet, Kubeadm, Kubectl 설치

 Kubernetes 설치를 위한 사전 설정 작업이 모두 끝나고 본격적으로 Kubernetes 클러스터 구성을 위한 과정을 진행한다. 먼저 Kubernetes용 APT 리포지터리를 추가한다.

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/kubernetes-xenial.gpg
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
#진행을 위해 Enter 입력

 이제 Kubelet, Kubeadm, Kubectl을 설치할 차례이다. 아래 명령어를 입력해 준다.

sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

참고 : 포스팅 시점인 2023년 10월 기준 현재 Kubernetes 최신 버전인 1.28.2가 설치된다.

 

 3) 설정 작업이 끝난 k8s-cp용 VM 전원을 끈 후 워커 노드로 복사

  (1) k8s-cp 노드 복제

 각 노드에 공통으로 해 주어야 할 작업은 모두 마무리되었다. 이제 k8s-cp VM의 전원을 끄고 복제를 통해 워커 노드 3대를 생성해 준다.

[사진 4] k8s-cp를 복제하여 워커 노드 3대를 생성

 복제가 완료되면 모든 노드의 전원을 켠 후, 각각의 노드에 웹 콘솔로 접근하여(설정 전에는 동일한 IP주소를 사용하기 때문에 ssh로는 접근이 불가능하다. 따라서 각 Hypervisor가 직접 제공하는 가상 머신 콘솔을 통해 접속하여 IP주소를 변경해 주어야 한다.) IP 주소와 호스트 네임을 변경해 주어야 한다. k8s-cp를 복제하였기 때문에 기존 k8s-cp의 설정을 그대로 가지고 있기 때문이다.

 

 

 4) 각 노드별 호스트 이름과 IP 주소 변경

  (1) 호스트 이름 변경

 우선, /etc/hosts 파일부터 변경해 주도록 하자.

sudo vim /etc/hosts

127.0.0.1 localhost
==================================================================================
127.0.1.1 k8s-w01        #k8s-w01 설정 값
127.0.1.1 k8s-w02        #k8s-w02 설정 값
127.0.1.1 k8s-w03        #k8s-w01 설정 값
#호스트 별로 각각 한줄씩만 입력
==================================================================================
192.168.0.150 k8s-cp
192.168.0.151 k8s-w01
192.168.0.152 k8s-w02
192.168.0.153 k8s-w03

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

 그리고 각 워커 노드의 호스트 이름도 변경해 준다.

sudo hostnamectl set-hostname k8s-w01   #모든 워커 노드에서 작업 진행, 단 워커 노드의 번호에 주의
exec bash

====================================================================================

sudo hostnamectl set-hostname k8s-w02
exec bash

====================================================================================

sudo hostnamectl set-hostname k8s-w03   
exec bash

 

  (2) IP 주소 변경

다음으로 IP 주소를 변경해 준다. IP 주소는 /etc/netplan/00-installer-config.yaml 파일을 편집하여 변경할 수 있다.

sudo vim /etc/netplna/00-installer-config.yaml

# This is the network config written by 'subiquity'
network:
  ethernets:
    ens160:
      addresses:
      - 192.168.0.151/24     #w01의 경우 192.168.0.151/24, w02의 경우 192.168.0.152/24
      nameservers:           #w03의 경우 192.168.0.153/24로 각각 알맞은 IP 주소 입력  
        addresses:
        - 8.8.8.8
        search:
        - study.local
      routes:
      - to: default
        via: 192.168.0.1
  version: 2
#IP 주소 변경 후 저장하고 닫기

sudo netplan apply   #변경 내용 적용

 실수 없이 컨트롤 플래인과 워커 노드의 호스트 이름과 IP 주소를 모두 입력했으면 Kubeadm을 통해 Kubernetes 클러스터를 구성하는 작업을 수행한다.

 

 

5) Kubeadm을 통한 Kubernetes 클러스터 구성

  (6) 컨트롤 플레인 구성

 여기서부터 컨트롤 플레인 노드와 워커 노드에 입력하는 명령어가 다르기 때문에 실수하지 않도록 주의하여야 한다. 먼저 컨트롤 플레인 노드에서 아래와 같은 명령어를 입력한다

 

주의 : 컨트롤 플레인에서 작업할 것!

sudo kubeadm init --apiserver-advertise-address=192.168.0.150
#--apiserver-sdvertise-address의 경우 kubectl 명령어를 통해 
#kubernetes api server를 호출할 endpoint
#포스팅에서는 컨트롤 플레인 노드의 주소를 사용

[init] Using Kubernetes version: v1.28.2
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W1015 04:35:14.897758    2458 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image.

...(중략)

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
#위 3줄의 명령어를 입력하여 일반 사용자 권한으로 Kubernetes 클러서트를 사용할 수 있도록 허용

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

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

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.0.150:6443 --token tnbij4.klamn95e7dqb9koq \
        --discovery-token-ca-cert-hash sha256:c3012bb5ec60782b30dfc01b14a44774d0fb21ef8a41d47dbd5b03db581ab235
#위의 'kubeadm join 192.168.0.150:6443...' 명령어는 앞에 sudo를 붙여서 각 워커 노드에 입력
#이를 통해 컨트롤 플레인과 워커 노드가 Kubernetes 클러스터를 구성
#token값과 sha256값은 랜덤하게 생성되므로 실제 클러스터 구성 시에 출력되는 값을 복사하여야 함

[사진 5] Kubeadm init을 통해 컨트롤 플레인 구성을 성공하면 위와 같이 컨트롤 플레인 노드와 워커 노드에 입력해야할 명령어를 확인할 수 있음

컨트롤 플레인 구성이 끝나면 중간에 3줄의 명령어를 컨트롤 플레인 노드에 입력하여 일반 사용자 권한으로 Kubernetes 클러스터를 사용할 수 있도록 해주어야 한다.

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

 

  (2) 워커 노드 Join

 주의: 워커 노드에서 작업할 것!

이제 각 워커 노드에 ssh를 통해 접속하여 마스터 노드에 출력된 명령어를 입력해 주어야 한다. 이때 주의해야 할 점은 반드시 워커 노드에서 sudo를 붙여서 실행해야 한다는 것이다. 이 부분에서 실수하지 않도록 주의해야 한다.

#각 워커 노드에 아래 명령어 입력

sudo kubeadm join 192.168.0.150:6443 --token tnbij4.klamn95e7dqb9koq \
        --discovery-token-ca-cert-hash sha256:c3012bb5ec60782b30dfc01b14a44774d0fb21ef8a41d47dbd5b03db581ab235
        
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

 이때, 입력하는 token값과 sha256 값은 랜덤 하게 부여되므로, 실제 설치 시 컨트롤 플레인 노드의 화면에 출력되는 값을 복사하여 붙여 넣어야 한다.

 

  (3) Kubernetes 클러스터 구성 확인

 이제 다시 컨트롤 플레인 노드로 돌아와 아래와 같은 명령어를 입력한다.

kubectl cluster-info

#CoreDNS is running at https://192.168.0.150:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

#To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

kubectl get nodes

NAME      STATUS     ROLES           AGE     VERSION
k8s-cp    NotReady   control-plane   19m     v1.28.2
k8s-w01   NotReady   <none>          3m21s   v1.28.2
k8s-w02   NotReady   <none>          3m13s   v1.28.2
k8s-w03   NotReady   <none>          2m59s   v1.28.2
#Kubernetes 클러스터를 구성하는 노드들의 정보를 조회

[사진 6] Kubernetes Cluster 구성이 완료 된 상태

 kubectl get nodes 명령어를 통해 위와 같이 각 노드들이 조회가 되면 Kubernetes 클러스터 구성이 완료가 되었다. 그러나 각 노드의 상태값이 NotReady로 표시되는데 이는 바로 CNI(Container Network Interface)가 구성되지 않았기 때문이다. CNI란 Kubernetes 클러스터 운영에 필수 Plug-in으로 반드시 설치해야 한다. CNI와 그 설치 방법에 대해서는 다음 포스팅에서 다루어 보도록 하겠다.

[사진 7] CNI가 설치 되지 않아 Kubernetes Cluster 내의 coredns pod가 Pending 상태

 

2. 마무리

 다소, 많은 명령어를 입력해야 해서 복잡해 보일 수 있으나, 실제 작업을 진행해 보고, 또 익숙해지면 생각보다 그렇게 난이도가 높은 것은 아니다. 다음 포스팅에서는 CNI가 무엇인지에 대해 알아보고, CNI 설치를 위한 Helm 차트와 본격적인 설치 방법에 대해서도 알아보도록 하겠다.

0. 들어가며

 Kubernetes 강의를 들어보면 대부분 Vagrant나 Minikube와 같은 것으로 클러스터를 구축한다. 이 부분이 항상 아쉬운 부분이다. 물론 수강생들의 수강 환경이 천차만별이기 때문에 이를 통일해야 강의 진행에 무리가 없다는 점에서 이해가 되는 부분이 있지만, 그럼에도 불구하고 Kubernetes 클러스터를 한 땀 한 땀 구축해 나가는 건 매우 중요한 경험이라 생각한다.

 혹시라도, VM이나 Baremetal 환경에서 손수 Kubernetes 클러스터를 구축하고자 하는 분께 도움을 드릴 수 있다면 좋겠다는 생각과, 또 개인적으로 진행하고 있는 토이 프로젝트에 대한 작업 기록을 위해 해당 포스팅을 작성해 본다.

 

1. 인프라 구성

 본 포스팅에서는 VMware사의 서버용 가상화 솔루션인 vSphere를 사용하려고 한다. 이외에도 VMware Workstation이나 Oracle Virtual Box 등 VM을 활용할 수 있는 환경이라면 문제없이 Kubernetes 클러스터를 구성할  수 있을 것이라고 생각한다.

호스트  이름 IP 주소 OS 사양 역할
k8s-cp 192.168.0.150 Ubuntu 22.04.3 LTS
Live Server
vCPU : 4 EA

Memory : 4GB

Storage : 60GB
컨트롤 플레인
k8s-w01 192.168.0.151 워커 노드

k8s-w02 192.168.0.152
k8s-w03 192.168.0.153

 참고 : Kubernetes 구성을 위한 VM의 최소 사양은 2 vCPU와 2GB의 메모리가 필요

 

 Kubernetes 클러스터의 머리 역할을 하는 컨트롤 플레인 노드 1대와 실제 워크로드를 구동하는 워커 노드 3대로 클러스터를 구성할 예정이다. 네트워크의 경우 인터넷과 연결된 상태여야 Kubernetes 설치가 가능하다.

 

2. 작업 순서

 1) k8s-cp용 VM 생성 및 Ubuntu 22.04 설치

 2) Kubernetes 클러스터 구성을 위한 공통 설정 작업

 3) 설정 작업이 끝난 k8s-cp용 VM 전원 끈 후 워커 노드로 복사

 4) 각 노드별 호스트 이름과 IP 주소 변경

 5) kubeadm을 통한 kubernetes 클러스터 구성

 6) CNI 구성(Helm 차트를 통한 Cilium 설치)

 

3. 설치 진행

 1) k8s-cp용 VM 생성 및 Ubuntu 22.04 설치

[사진 1] vSphere 환경에서 k8s-cp용 VM 생성

 우선 k8s-cp용 VM을 생성하고 전원을 켜준다. Ubuntu 22.04.3 LTS의 경우 설치 과정 중 IP주소를 설정할 수 있는데 이때, 앞서 미리 준비해 두었던 IP주소를 아래 그림을 참고하여 입력해 주면 된다.

[사진 2] 네트워크 인터페이스의 IPv4 주소를 설정
[사진 3] DHCP 설정을 Manual로 변경
[사진 4] IP주소 입력 후 저장

 Name servers의 경우 Google DNS를 사용하였다. 선호하는 다른 DNS 서버 주소가 있으면 그것을 사용하여도 무방하다. Search domains의 경우 생략이 가능하다. 주소 입력이 완료 되면 다음 단계로 넘어간다. 간단한 mirror location에 대한 테스트 과정과 스토리지에 관한 설정 과정을 마치면 아래와 같이 Profile setup 단계에 들어간다.

[사진 5] Profile setup에서 미리 server의 이름을 정해 줄 수 있음

 이 과정에서 미리 서버 이름(Host name)을 정해줄 수 있다. 차후 /etc/hosts 파일을 편집할 때 유용하다. 본 포스팅에서는 username을 boot로 설정했으며 이는 다른 것으로 변경해도 무방하다.

[사진 6] SSH 접속을 위해 OpenSSH server 자동 설치

 Ubuntu 22.04.3 LTS Live Server의 경우 CLI 환경만을 지원하며, 원격에서 SSH를 통해 간편하게 제어를 하기 위해 OpenSSH server를 설치해 준다. 이 외, 다른 패키지의 경우 필요에 따라 선택하여 설치하면 된다. 설치가 완료되면 재부팅을 해준다.

 

4. 마무리

 해당 포스팅에서는 쿠버네티스 클러스터 구성 전 Ubuntu 22.04.3 LTS 버전을 설치하는 방법에 대해서 알아 보았다. 사실 Ubuntu 설치 과정은 기본적인 내용이기도 하고, 이미 많은 곳에 포스팅이 올라와 있으므로 자세하게 다루지 않았다. 다음 포스팅에서는 본격적인 Kubernetes 클러스터 구성을 위한 과정을 다뤄 보도록 하겠다.

환경

  • Ubuntu 20.04.6 LTS
  • Kubernetes 1.26.1

증상

  • Service Account를 생성해도 Secret이 생성되지 않음

원인

  • Service Account 생성시 자동으로 생성되는 Token이 Kubernetes 1.24 버전 이후로는 생성되지 않음
  • 따라서, Service Account 생성 시 따로 해당 Service Account의 Secret을 생성해 주어야 함

예제 YAML

---                    #Service Account가 속할 Namespace 생성
apiVersion: v1
kind: Namespace
metadata:
  name: test

---                    #Service Account 생성
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-account
  namespace: test

---                    #Service Account의 Secret 생성
apiVersion: v1
kind: Secret
metadata:
  name: test-account-token
  namespace: test
  annotations:
    kubernetes.io/service-account.name: test-account
type: kubernetes.io/service-account-token

[사진 1] Service Account와 Secret에 대한 조회 결과

 생성된 Service Account Secret의 Token값은 아래 명령어를 통해 조회가 가능

kubectl describe secret test-account-token -n test
#kubectl describe secret [Secret의 이름] -n [해당 Secret이 속한 Namespace의 이름)

[사진 2] kubectl describe로 해당 Token값을 조회할 수 있음

구동 환경

  • M1 Macbook Pro에 Docker Desktop으로 컨테이너 구동
  • Docker Desktop 컨테이너에서 구동되는 Ansible 서버
  • Docker Desktop에서 구동되는 Minikube 클러스터
  • Minikube 클러스터는 호스트인 M1 Macbook Pro의 IP 주소를 통해 접근하여 kubectl 명령어를 하달

증상

  • Docker Desktop에서 실행된 Ansible 서버 컨테이너에서 Ansible Playbook 실행
  • 대상 호스트는 minikube의 호스트인 M1 Macbook Pro이고, kubectl 명령어 실행 안됨
  • 단, Ansible 서버 컨테이너에서 SSH로 M1 Macbook Pro에 접속하고 수동으로 kubectl 명령은 실행됨 
[root@ansible-server k8s]# ansible-playbook -i hosts k8s-cicd-deployment-playbook.yaml
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details

PLAY [Create pods using deployment] *************************************************************

TASK [Gathering Facts] **************************************************************************
ok: [192.168.0.XXX]

TASK [create a deployment] **********************************************************************
fatal: [192.168.0.XXX]: FAILED! => {"changed": false, "cmd": "kubectl apply -f study/cicd/cicd-devops-deployment.yaml", "msg": "[Errno 2] No such file or directory: b'kubectl'", "rc": 2, "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

PLAY RECAP **************************************************************************************
192.168.0.XXX               : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

 

에러 내용

  • Ansible playbook 실행 시 호스트에서 kubectl 명령어 찾을 수 없음

 

파일 코드

  • hosts 파일
[kubernetes]
192.168.0.XXX    ansible_user="Macbook User Name"    ansible_python_interpreter=/usr/bin/python3

 

  • k8s-cicd-deployment-playbook.yaml 파일 내용
- name: Create pods using deployment
  hosts: kubernetes
  # become: true
  # user: ubuntu

  tasks:
  - name: create a deployment
    command: kubectl apply -f study/cicd/cicd-devops-deployment.yaml

수정

  • Ansible Playbook 파일의 kubectl 명령어를 절대 경로로 지정
- name: Create pods using deployment
  hosts: kubernetes
  # become: true
  # user: ubuntu

  tasks:
  - name: create a deployment
    command: /usr/local/bin/kubectl apply -f study/cicd/cicd-devops-deployment.yaml

 

결과

  • 정상 작동 함

원인 추측

  • Ansible playbook 실행이 단순 ssh 접속이 아닌 것 같음
  • 환경 변수 PATH 값을 다르게 읽어 들이는 것으로 보임
  • PATH 설정에서 kubectl을 등록하면 해결할 수 있을 것 같음

0. 들어가며

 지난 포스팅에서 VM에 Tomcat 서버를 구축해 보았습니다. 이번 포스팅은 Tomcat 서버를 외부에서 접근할 수 있도록 구성한 후, Jenkins를 통해 웹 애플리케이션을 배포하고, 배포된 웹 페이지에 접속해 보는 과정을 다뤄보겠습니다. 아직 Tomcat 서버가 준비되지 않았다면 아래의 이전 포스팅 링크를 참고하여 구축 후 이번 포스팅 내용을 따라 해 보는 것을 추천드리겠습니다.

[Ubuntu 20.04] Tomcat 서버 구축 - 1편 : https://tech-recipe.tistory.com/4

 

[Ubuntu 20.04] Tomcat 서버 구축 - 1편

0. 들어가며 최근에 CI/CD에 관한 강의를 듣고 있습니다. Jenkins를 활용해 CI/CD 파이프라인을 구축하는 과정에 웹 서버로 Tomcat을 사용하게 되어 이를 구축하게 되었습니다. 처음에는 컨테이너로 구

tech-recipe.tistory.com

 

1. Jenkins - Tomcat 서버 구현 Architecture

 지난 포스팅에서도 말씀드렸지만, CI/CD 학습에 필요한 실습 환경을 구성하기 위해 Tomcat 서버를 구축하게 되었습니다. 제가 듣고 있는 강의에서는 로컬 환경에 Docker를 사용하여 컨테이너 형태로 Jenkins 서버와 Tomcat 서버를 구동하고 웹 애플리케이션을 배포해 보는 정도로 실습을 진행하고 있습니다. 그러나 제가 가진 장비들을 활용하여 Jenkins 서버와 Tomcat 서버를 분리하여 구축한다면 좀 더 의미 있는 실습이 될 것 같아 아래와 같은 구조로 실습 환경을 구성해 보려고 합니다.

[그림 1] CI/CD 학습을 위한 실습 환경 구성도

 사실 위의 [그림 1]과 같은 환경이, 실제 CI/CD 방법론을 택하여 애플리케이션을 운영하는 환경과 유사한지는 잘 모르겠습니다. 아마도 더욱 복잡한 환경이 아닐까 생각합니다. 다만 로컬 환경에서 실습을 진행하는 것보다는, 실제 외부에서 접근할 수 있도록 서비스를 구축해 보는 것이 조금 더 실전적인 방식이 아닐까 하여 위와 같은 환경을 구축해 보려고 합니다. 작업 순서는 아래와 같습니다.

 

  1. ipTIME 공유기 관리 페이지 접속하여 외부 20188번 포트를 내부 VM의 8080번 포트로 포트포워딩 하도록 설정
  2. Tomcat 서버의 tomcat-user.xml 파일에 사용자 정보를 입력하여 Jenkins 서버에서 애플리케이션을 배포할 수 있도록 준비
  3. Jenkins 서버에서 프로젝트를 생성한 후, 생성한 프로젝트의 설정 탭 > 빌드 후 조치 메뉴의 '빌드 후 조치 추가' 드롭 다운 메뉴 클릭하여 'Deploy ear/ear to a container' 선택
  4. WAR/EAR files 필드에 배포할 .WAR 파일에 대한 정보 입력한 후 Containers 필드에 'Add Container' 드롭 다운 메뉴 클릭하여 'Tomcat 9.x Reomote' 선택
  5. Cridentials 필드에 'Add' 버튼 클릭 후 앞선 2번 단계에서 설정한 Tomcat 서버 사용자에 대한 정보를 입력하고 선택한 후, Tomcat URL 필드에 Tomcat 서버의 URL과 ipTime 공유기의 외부 포트 번호인 20188 입력
  6. 프로젝트 빌드를 통해 Jenkins에서 Tomcat 서버로 애플리케이션이 잘 배포되는지 확인

2. 애플리케이션 배포 환경 구성 작업

 

Step 1. ipTIME 공유기 포트포워딩 설정

 이제, 본격적인 구성 작업에 들어가 보도록 하겠습니다. 가장 먼저 ipTIME 공유기의 설정 페이지에 접속합니다.(참고로 본 포스팅에 사용된 공유기 모델명은 ipTIME AX2004BCM입니다.) 일반적으로 ipTIME 공유기의 설정 페이지는 웹 브라우저 주소창에 192.168.0.1을 입력하면 접근할 수 있습니다.

[사진 1] 웹 브라우저 주소창에 192.168.0.1을 입력하면 ipTIME 공유기의 설정 페이지 로그인 화면을 볼 수 있다.
[사진 2] 로그인 후 왼쪽 톱니모양의 관리도구 아이콘을 클릭

 [사진 1]의 로그인 화면에서 로그인을 하고 나면 [사진 2]의 창이 뜨게 됩니다. 처음 확인 해야 할 부분은 [그림 2]의 우측 하단의 내용입니다. 현재 공유기가 제공받은 공인 IP 주소와 공유기의 펌웨어 정보가 나와 있습니다.(그래서 모자이크 처리를 했습니다.) 이후에 언급하겠지만, 공인 IP를 알아야 외부에서 Tomcat 서버로 접근이 가능하기 때문에 따로 메모를 해 두셔야 합니다.


참고 : 저는 ISP로 SK Broadband를 사용합니다. 요즘엔 보통 인터넷을 사용하면 모뎀을 주게 되는데 이 모뎀이 공유기 역할을 하기도 합니다. 제가 제공받은 모뎀은 공인 IP 주소를 받아서 내부에 사설 IP 주소를 제공하는 것이 기본 설정으로 되어 있었습니다. 이렇게 하면 ipTIME 공유기의 포트포워딩 기능을 제대로 사용할 수 없기 때문에 설정을 좀 바꾸어야 합니다. 저는 모뎀이 공인 IP 주소를 바로 ipTIME 공유기의 외부 IP 주소로 전달하도록 설정했습니다. 해당 설정은 ISP 마다 제공하는 모뎀과 방식이 다를 수 있으므로 확인이 필요합니다.


 관리도구 페이지로 이동하여 왼쪽의 고급 설정 > NAT/라우터 관리 > 포트포워드 설정 메뉴로 이동합니다.

[사진 3] 포트포워딩 규칙을 생성

 [사진 3]에서 보는 바와 같이 포트포워딩 규칙을 생성합니다. 빨간 네모를 친 칸에 각각의 값을 넣어 주면 됩니다. 우선 '규칙 이름'은 말 그대로 포트포워딩 규칙의 이름으로 이해할 수 있는 이름을 입력합니다. '내부 IP 주소'는 Tomcat 서버의 IP 주소로 앞선 포스팅에서 VM을 생성하고 부여해준 IP 주소를 말합니다. '외부 포트'는 ipTIME 공유기가 외부에 노출하게 될 포트 번호로 Jenkins 서버에서 해당 포트를 통해 Tomcat 서버에 접근하게 될 것입니다. '내부 포트'는 VM이 노출하고 있는 포트 번호로 Tomcat의 기본 포트 번호인 8080으로 지정해 주겠습니다. 이렇게 하고 오른쪽 아래의 '적용' 버튼을 눌러 규칙을 추가합니다.

 

Step 2. Tomcat 서버 사용자 정보를 입력

 다음으로 Tomcat 서버의 사용자 정보 파일을 편집합니다. /etc/tomcat9 경로에 tomcat-users.xml 파일을 vim 편집기로 열어 아래와 같은 내용을 입력합니다.

sudo vim /etc/tomcat9/tomcat-users.xml

#tomcat-users.xml 파일에 아래 내용을 입력
  <role rolename="manager-script"/>
  <user username="deployer" password="P@ssw0rd" roles="manager-script"/>

[사진 4] /etc/tomcat9/tomcat-user.xml 파일에 사용자 정보 입력

 usernamepassword 값은 이후 단계에서 사용하게 되는데, Jenkins 서버에서 Tomcat 서버에 애플리케이션을 배포하기 위한 권한을 획득하기 위해 사용됩니다. 본 포스팅에는 usernamedeployer로, passwordP@ssw0rd!이후 Tomcat 서버의 서비스를 재시작하여 입력한 사용자 정보가 업데이트되도록 합니다.

sudo systemctl restart tomcat9

 

Step 3. Jenkins 프로젝트에서 배포 대상을 Tomcat 서버로 설정

 다음 단계는 Jenkins 설정으로, 애플리케이션 소스코드를 사용하여 빌드 작업을 실행한 후 이를 배포할 대상을 설정하는 과정입니다. 우선 Jenkins에서 프로젝트를 생성합니다. 생성된 프로젝트 페이지로 이동하면 화면 왼쪽에 '구성' 메뉴가 있습니다. 이를 클릭하고 스크롤을 아래로 드래그하면 '빌드 후 조치' 필드가 나타납니다. 이 필드에 Tomcat 서버에 대한 정보를 입력하여 배포 대상을 설정해 줍니다.

[사진 5] 프로젝트 생성 후 '구성' 메뉴 선택
[사진 6] '빌드 후 조치' 필드에 Tomcat 서버의 정보를 입력

 위와 같이 Tomcat 서버의 설정을 진행해 줍니다. 'Add Contianer' 드롭다운 메뉴에서 Tomcat 9.x Reomte를 선택하고 각 필드를 채워 넣습니다. 앞선 단계에서 설정한 Tomcat 사용자 정보(username : deployer / password: P@ssw0rd!)를 입력해 줍니다. TomcatURL 필드에는 공유기가 제공받은 공인 IP 주소와 포트번호를 입력합니다.("http://공인 IP 주소:포트번호"와  같은 형식으로 실제 환경에 맞춰 입력하면 됩니다.) 설정을 완료하고 왼쪽의 지금 빌드 버튼을 클릭하면 빌드가 진행되고 정상적으로 Tomcat 서버에 .war 파일을 배포하는 것을 볼 수 있습니다.

[사진 7] Jenkins 프로젝트 배포가 성공 된 상태

 본 포스팅에서는 Jenkins 설정에 대해서 상세하게 설명하지 못한 부분이 많습니다. 이에 관한 내용은 따로 포스팅을 통해 설명드리도록 하겠습니다.

 

Step 4. 웹 애플리케이션 작동 상태 확인

 이제 배포를 완료한 웹 애플리케이션이 잘 작동하는지 확인해 볼 차례입니다. 모바일을 사용하여 인터넷 구간을 통해 배포한 애플리케이션에 잘 접근이 되는지 확인해 보겠습니다. 핸드폰의 크롬 브라우저에 http://공인 IP 주소:20188/webapp을 입력하면 아래와 같은 화면을 확인할 수 있습니다.

[사진 8] 인터넷 구간을 통해 웹 애플리케이션 접속 성공

 참고로 저는 ipTIME 공유기에서 제공하는 DDNS 기능을 사용하고 있어 공인 IP 뿐만 아니라 URL을 통해서도 접속이 가능합니다. 위에 보이는 [사진 8]은 URL을 통한 애플리케이션 접속이 성공한 모습입니다.


 지금까지 두 건의 포스팅을 통해 Tomcat 서버를 구축하고 Jenkins로 웹 애플리케이션을 배포, 인터넷 구간을 통한 접속까지 확인해 보았습니다. 기존에 알고 있었던 DDNS나 포트포워딩의 개념을 실제 애플리케이션 배포에 적용해 볼 수 있어서 상당히 재미있는 시간이었습니다. 또한, 아직 배워야 할 것이 많지만 CI/CD의 개념을 조금이나마 이해할 수 있는 실습이었습니다. 이 포스팅을 보시는 분들에게도 도움이 되셨길 바랍니다.

 

그럼 여기서 포스팅을 마치도록 하겠습니다. 감사합니다.

0. 들어가며

 최근에 CI/CD에 관한 강의를 듣고 있습니다. Jenkins를 활용해 CI/CD 파이프라인을 구축하는 과정에 웹 서버로 Tomcat을 사용하게 되어 이를 구축하게 되었습니다. 처음에는 컨테이너로 구성해보려 했으나 Jenkins에서 빌드 후 배포 과정에 Tomcat Server가 구동되고 있는 컨테이너에 접근하지 못하는 문제가 있어 VM을 사용하기로 했습니다.(해당 문제는 차후에 해결책을 찾아보도록 하겠습니다.)


1. Tomcat 서버를 위한 VM 호스팅

 앞서 말씀드린 대로, VM 형식으로 Tomcat 서버를 구축하기로 결정은 했지만 어디에 하느냐가 문제였습니다. 우선 가장 먼저 떠오른 방식은 VMware Workstation이나 Oracle Virtual Box를 활용하는 것이었습니다. 하지만 저는 Apple M1 프로세서를 사용하는 맥북을 사용하고 있어서 약간의 제약사항이 있었습니다. 아무래도 제가 지금까지 경험해 온 환경이 대부분 AMD64 기반이다 보니 Apple M1에 맞추어진 사용 환경이 익숙하지 못하다는 것이 가장 큰 걸림돌이었죠. 어떻게 방법이 없을까 고민하던 차에 갑자기 떠오른 게 NAS였습니다. 제가 사용하고 있는 NAS는 Synology사의 DS1515+인데 VM을 만들 수 있는 기능을 기본적으로 제공하고 있습니다. NAS 자체의 하드웨어 스펙이 그리 넉넉한 건 아니지만 Linux VM 정도는 띄울 수 있는 데다, 사실 쓸데없는 파일들만 쌓이고 있던 참이었는데 이렇게 활용할 수 있는 방법이 생겨서 다행인 것 같습니다.

 

 VM을 생성하는건 그다지 어렵지 않습니다. GUI 환경이 아주 친절하게 되어 있는 데다가, 제가 주로 VMware 제품을 다루다 보니 더욱 그렇지 않나 싶습니다. VM을 생성하는 방법은 따로 포스팅을 통해 안내하도록 하겠습니다. VM에 OS로는 Ubuntu 20.04를 설치했으며 NAS의 사설 IP 네트워크 대역과 같은 곳에 위치하도록 IP 주소를 수동으로 부여하였습니다.

[사진 1] Synology NAS의 기능인 Virtual Machine Manager를 사용하여 VM 생성

 다른 방법으로는 VMware Workstation이나 Oracle Virtual Box를 사용하여 VM을 만들 수 도 있습니다. 해당 포스팅을 보시는 분들이라면 VM 생성 정도는 크게 어렵게 느끼시지 않을 것으로 생각합니다.

 

2. Tomcat 패키지 설치

 VM이 준비되었다면 Tomcat 패키지를 설치해 볼 차례입니다. 여러 방법들이 있지만 가장 간단한 Ubuntu 기본 리포지터리를 통해 패키지를 설치하는 방법을 사용해 보겠습니다.

sudo apt update

 가장 먼저 apt update 명령어를 통해 패키지 정보를 최신으로 업데이트합니다. 앞서 잠깐 언급드렸지만 CI/CD에 관한 강의를 들으며 실습을 위한 환경을 조성하는 것이라 최신 버전의 Tomcat이 필요한 게 아니었습니다. 다운 가능한 Tomcat의 패키지 목록을 검색해서 9 버전이 존재하는지 확인해 보겠습니다.

sudo apt-cache search tomcat

[사진 2] tomcat9와 tomcat9-admin 패키지 확인이 가능

 확인 결과 Tomcat 9 버전 패키지가 검색되었습니다. 이제 패키지를 설치해 보도록 하겠습니다. tomcat9tomcat9-admin 패키지를 설치하겠습니다.

sudo apt install tomcat9 tomcat9-admin

 Tomcat이 작동하기 위해서는 JDK가 반드시 설치되어야 하는데, 패키지 설치를 하게 되면 자동으로 종속성이 있는 패키지를 설치해 줍니다. 따라서 위와 같은 방식으로 설치 시에는 JDK를 따로 설치할 필요는 없습니다. 여기까지 하셨다면 Tomcat 패키지 설치는 끝이 납니다. 사실 매우 간단하죠. 이제 몇 가지 설정작업을 통해 Tomcat 서버 구성을 마무리하도록 하겠습니다.

 

3. Tomcat 서버를 위한 방화벽 설정

 Tomcat 서버는 기본적으로 8080번 포트를 통해 응답하게 되어있습니다. 실제로 8080번 포트로 잘 작동하고 있는지 아래 명령어를 통해 확인해 보도록 하겠습니다.

ss -ltn

[사진 3] ss -ltn 명령어를 통해 8080 포트가 열려 있는것을 확인

 이제 방화벽에서 해당 포트를 통한 통신을 허용해 주어야 합니다. 우선 방화벽 상태를 확인해 보도록 하겠습니다.

sudo ufw status

Status: inactive #방화벽이 비활성화 된 상태를 나타냄
Status: active # 방화벽이 활성화 된 상태이며, 아래에 어떤 방화벽 규칙이 있는지 표시

 위 명령어를 실행해 보면 현재 방화벽의 상태를 알 수 있습니다. Ubuntu를 처음 설치하고 따로 방화벽 설정을 하지 않았다면 Status: inactive로 표시가 됩니다. 먼저 방화벽 규칙을 설정 후 방화벽을 활성화해 보겠습니다.

sudo ufw allow 8080/tcp

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y #'y' 입력 후 Enter

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
8080/tcp                   ALLOW       Anywhere
8080/tcp (v6)              ALLOW       Anywhere (v6)

 먼저 8080번 포트의 tcp 프로토콜 연결에 대해서 허용 규칙을 만들어 줍니다. 그리고 sudo ufw enable 명령어를 입력하면 방화벽이 활성화되면서 SSH 연결이 끊길 수도 있다는 경고 메시지가 등장합니다. 'y'를 입력하고 방화벽을 활성화시켜 줍니다.


주의 : 만약 SSH로 VM에 접속하여 작업 중이라면 방화벽을 활성화 화면 접속이 끊어질 수 있습니다. 따라서 SSH가 사용하는 22번 포트 역시 허용해 주는 규칙을 추가해야 합니다. SSH로 작업하는 경우 아래와 같이 입력합니다.

sudo ufw allow 8080/tcp
sudo ufw allow 22/tcp  #22번 포트를 허용하여 SSH 접속을 유지

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
8080/tcp                   ALLOW       Anywhere
22/tcp                     ALLOW       Anywhere
8080/tcp (v6)              ALLOW       Anywhere (v6)
22/tcp (v6)                ALLOW       Anywhere (v6)

 위와 같이 출력되면 방화벽 설정이 잘 된 것입니다. 이제 마지막으로 Tomcat 서버가 잘 응답을 하는지 확인해 보도록 하겠습니다.

 

4. 브라우저를 통해 localhost:8080으로 접속

 Ubuntu에 기본으로 설치된 Firefox 브라우저를 실행하고 주소창에 http://localhost:8080을 입력하면 아래와 같은 화면을 확인할 수 있습니다.

[사진 4] Tomcat 서버가 잘 작동하는 모습


 이상으로 Ubuntu 20.04에 Tomcat 서버를 구축해 보았습니다. 사실 Tomcat 서버를 설치하는 것은 그다지 어려운 과정은 아니라고 생각합니다. 다음 포스팅에는 이렇게 구축된 Tomcat 서버에 Jenkins를 이용하여 웹 애플리케이션을 배포하기 위한 여러 사전 준비 과정 및 실제 애플리케이션 배포를 진행해 보도록 하겠습니다.

 

 이번 포스팅은 여기서 마치도록 하겠습니다. 감사합니다.

+ Recent posts