개발강의정리/DevOps

[데브옵스를 위한 쿠버네티스 마스터] 3. 쿠버네티스 들어가기

nineDeveloper 2020. 8. 22.
728x90

0 VirtualBox 및 가상 이미지 셋팅

1. 이미지 파일 다운로드

실습 Ubuntu-20.04 이미지: ubuntu-20.04.1-desktop-amd64-dockerzshsudo-20201227.ova 다운로드

2. 환경에 맞게 VirtualBox 다운로드

https://www.virtualbox.org/wiki/Downloads

3. 가상 시스템 가져오기

  1. VirtualBox를 실행하고 파일 - 가상 시스템 가져오기로 다운받은 ubuntu-20.04.1-desktop-amd64-dockerzshsudo-20201227.ova 이미지 셋팅
  2. 셋팅된 가상 이미지 실행
  3. openssh, NOPASSWD 설정

1 docker와 kubeadm 설치

1.1 쿠버네티스 설치 도큐먼트

쿠버네티스 설치하기 위해 다음 사이트에 방문하도록 한다.

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

1.2 도커 및 kubeadm 설치

도커 환경 구성 링크 참조
[Docker] 신규 인스턴스 Docker 환경 구성

다음 스크립트 파일을 작성하고 스크립트를 실행한다

vi install.sh
chmod +x install.sh
./install.sh
# install.sh
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

설치가 완료된 후 다음 명령을 입력하고 TAB 키를 누른다

kubernetes를 관리하는 명령어

  • kubeadm
    • 클러스터를 부트스트랩하는 명령
  • kubelet
    • 클러스터의 모든 시스템에서 실행되는 구성 요소로, 창 및 컨테이너 시작과 같은 작업을 수행
  • kubectl
    • 커맨드 라인 util은 당신의 클러스터와 대화

추가로 필요한 애플리케이션 설치

apt install vim net-tools -y

2 master 노드와 work 노드 생성 (VitualBox)

2.1 노드 복제

시스템을 종료하고 복제를 시작한다.

  • 새 MAC 주소로 생성
  • 호스트 이름이 고유해야 함(master, work1, work2)
  • 스왑 오프 해줘야 함
  • 완전한 복제
  • 현재 머신 상태

호스트 이름 변경하기: 이름 변경 후에 리붓해야 적용 됨

sudo echo master > /etc/hostname # 호스트 이름이 저장돼있는 파일
sudo gedit /etc/hostname

2.2 네트워크 설정

master 노드와 work 노드 간에 통신을 위해 VitualBox 네트워크 설정

  1. VitualBox 설정 클릭

  2. Nat 네트워크 추가

  3. 각 이미지 마다 설정 버튼 클릭해서 네트워크 설정

  4. 각 이미지 마다 Nat 네트워크로 네트워크 설정 변경

설정 완료 후 ip addr 로 ip를 확인한 후 ping 테스트

2.3 HOST NAME 변경

각각 master, work1, work2 로 hostname을 변경한다

sudo vi /etc/hostname

3 클러스터 구성 및 쿠버네티스 테스트

3.1 스왑 기능 비활성화하기

sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

Kubernetes에서 스왑을 비활성화하는 이유

  • Kubernetes 1.8 이후, 노드에서 스왑을 비활성화해야 함(또는 --fail-swap-on을 false로 설정)
  • kubernetes의 아이디어는 인스턴스를 최대한 100%에 가깝게 성능을 발휘하는 것
  • 모든 배포는 CPU/메모리 제한을 고정하는 것이 필요
  • 따라서 스케줄러가 포드를 머신에 보내면 스왑을 사용하지 않는 것이 필요
  • 스왑 발생시 속도가 느려지는 이슈 발생
  • 성능을 위한 것

참고문헌: https://serverfault.com/questions/881517/why-disable-swap-on-kubernetes

3.2 마스터 노드 초기화

Master 노드를 초기화를 가장 먼저 수행 (사용할 포드 네트워크 대역을 설정)

kubeadm init

마스터 노드 초기화 후 나오는 명령어들을 활용해 마스터 노드와 워커 노드에서 각각 실행한다

Kubeadm init 또는 join 명령을 실행할 때 중복된 실행으로 문제가 생기는 경우 kubeadm reset 명령을 통해서 초기화한다

kubeadm reset

클러스터를 사용 초기 세팅(마스터 노드에서만 할 것!)

다음을 일반 사용자 계정으로 실행 (콘솔에 출력된 메시지를 복붙)

# 유저를 위한 설정(마스터 노드)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 워커노드에 참여를 위해 실행하는 명령
kubeadm join 10.0.2.15:6443 --token 4t5o8a.3ixwu5vwctisgrjg \
    --discovery-token-ca-cert-hash sha256:76673ddd883b226639254ac79e48b336dc09854de6eb2e553f5be934c7975949

3.3 네트워크 애플리케이션 설치

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

마스터 노드에서만 다음 명령어 실행 (Pod Network 추가)

  • 이것을 잘해야 노드 추가 명령어가 잘 실행됨
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

3.4 슬레이브 노드 추가

  • 앞서 설치한 대로 쿠버네티스 설치
  • init 명령어 전까지만 수행(init 명령어 실행X)
  • 이후 각 노드에서 관리자 권한으로 워커 노드를 참가 시킴 (콘솔에 출력된 메시지를 복붙)
# 워커노드에 참여를 위해 실행하는 명령
kubeadm join 192.168.232.128:6443 --token 4t5o8a.3ixwu5vwctisgrjg \
    --discovery-token-ca-cert-hash sha256:76673ddd883b226639254ac79e48b336dc09854de6eb2e553f5be934c7975949

3.5 최종 확인

마지막으로 kubectl get nodes 명령으로 모두 ready가 됐는지 확인한다

kubectl get nodes
NAME     STATUS   ROLES    AGE     VERSION
master   Ready    master   4h39m   v1.18.8
work1    Ready    <none>   4h32m   v1.18.8
work2    Ready    <none>   4h32m   v1.18.8

애플리케이션 생성과 확인

  1. nginx master node 및 work node 에 설치
$ kubectl run nginx --image=nginx
pod/nginx created
  1. 설치된 Application 확인
$ kubectl get pod 
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          11s
  1. nginx 8080 으로 port forwarding 하여 실행
$ kubctl port-forward nginx 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

4 GCP에 쿠버네티스 설치 및 실행

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=LoadBalance

5 쿠버네티스에서 실행할 Go 언어 컨테이너 작성

main.go 코드 작성

package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
    "os"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    hostname, err := os.Hostname()
    if err == nil {
        fmt.Fprint(w, "Welcome! " + hostname +"\n")
    } else {
        fmt.Fprint(w, "Welcome! ERROR\n")
    }
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)

    log.Fatal(http.ListenAndServe(":8080", router))
}

golang 설치 및 앱 작성 후 실행

$ apt install golang
$ go get github.com/julienschmidt/httprouter
$ go build main.go
$ main
$ curl 127.0.0.1:8080

Dockerfile

FROM golang:1.11
WORKDIR /usr/src/app
COPY main  /usr/src/app
CMD ["/usr/src/app/main"]

도커 빌드 및 푸시

$ sudo docker build -t freelife1191/http-go .
$ sudo docker login
$ sudo docker push freelife1191/http-go
$ sudo docker run -d -p 8080:8080 --rm http-go
$ curl 127.0.0.1:8080

쿠버네티스로 배포 및 실행

kubectl create deploy http-go --image=freelife1191/http-go

계층구조(deploy - rs - pod)로 실행이 됨

$ kubectl get deploy
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
http-go   1/1     1            1           43m

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
http-go-88b7cdcb5   1         1         1       43m

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
http-go-88b7cdcb5-8rgpb   1/1     Running   0          115s

expose 명령어로 외부에 노출하여 서비스

LoadBalancer 로 실행하면 외부에서 접근할 수 있는 EXTERNAL IP를 받아옴

kubectl expose deployment http-go --port=8080 --target-port=8080 --type=LoadBalancer

외부에 노출한 서비스 확인

kubectl get svc

Watch 모드 옵션을 주어 실행하면 계속 확인하다가 변경사항이 있는 라인을 다시 출력해줌

kubectl get svc -w

EXTERNAL-IP 생성된 IP를 확인하고 웹에서 테스트 34.64.84.62:8080

NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
http-go      LoadBalancer   10.36.15.185   34.64.84.62   8080:31245/TCP   7m50s
kubernetes   ClusterIP      10.36.0.1      <none>        443/TCP          90m

잘못 만들었을때 삭제

deploy 삭제시 레플리카셋, POD 모두 삭제됨

kubectl delete deploy http-go

서비스 삭제

kubectl delete svc http-go-svc

포드(pod)란

  • 쿠버네티스는 kubectl get container와 같이 컨테이너를 취급하지 않는다!
  • 대신 여러 위치에 배치된 컨테이너 개념인 컨테이너 그룹을 포드(Pod)라는 개념을 사용

포드의 특징

  • 포드는 하나 이상의 밀접하게 관련된 컨테이너로 구성된 그룹
  • 동일한 리눅스 네임스페이스와 동일한 워커 노드에서 항상 함께 실행
  • 각 포드는 애플리케이션을 실행하는 자체 IP, 호스트 이름, 프로세스 등이 있는 별도의 논리적 시스템

포드 나열하기

kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
http-go-88b7cdcb5-8rgpb   1/1     Running   0          115s

웹 애플리케이션 만들어보기

  • 실행 중인 포드는 클러스터의 가상 네트워크에 포함돼 있음
  • 어떻게 액세스 할 수 있을까?
  • 외부에서 액세스하려면 서비스 객체를 통해 IP를 노출하는 것이 필요
  • LoadBalancer라는 서비스를 작성하면 외부 로드 밸런서가 생성
  • 로드 밸런서의 공인 IP를 통해 포드에 연결 가능
    (하지만 로컬 쿠버네티스에서는 동작하지 않으며 externalDNS가 필요함,
    이 기능은 GKE, EKS 같은 클라우드에서 사용 가능(구글, AWS 계정 필요))
$ kubectl expose deployment http-go --type=LoadBalancer --name http-go-svc --port=8080 - -target-port=8080
service/http-go-svc exposed
$ kubectl get services
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
http-go      LoadBalancer   10.36.15.185   34.64.84.62   8080:31245/TCP   7m50s
kubernetes   ClusterIP      10.36.0.1      <none>        443/TCP          90m

디플로이먼트, 포드, 서비스가 동작하는 방식 이해

  • 사실 실제로 포드도 직접 만들지 않음
  • kubectl create deploy 명령을 실행하면 디플로이먼트가 생성
  • 디플로이먼트가 실제 포드 객체를 생성
  • 해당 디플로이먼트가 관리하는 포드의 포트 8080을 노출하라고 명령 필요

디플로이먼트의 역할

  • 디플로이먼트는 레플리카셋을 생성
  • 레플리카셋은 수를 지정하여 알려주면 그 수만큼 포드를 유지
  • 어떤 이유로든 포드가 사라지면 레플리카셋은 누락된 포드를 대체할 새로운 포드를 생성
$ kubectl get deployment
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
http-go   1/1     1            1           43m

서비스의 역할

  • 포드는 일시적이므로 언제든지 사라질 가능성 존재
  • 포드가 다시 시작되는 경우에는 언제든 IP와 ID 변경됨
  • 서비스는 변화하는 포드 IP 주소의 문제를 해결하고 단일 IP 및 포트 쌍에서 여러 개의 포드 노출
  • 서비스가 생성되면 정적 IP를 얻게 되고 서비스의 수명 내에서는 변하지 않음
  • 클라이언트는 포드에 직접 연결하는 대신 IP 주소를 통해 서비스에 연결
  • 서비스는 포드 중 하나로 연결을 포워딩

애플리케이션의 수평 스케일링

  • 쿠버네티스를 사용해 얻을 수 있는 큰 이점 중 하나는 간단하게 컨테이너의 확장이 가능하다는 점
  • 포드의 개수를 늘리는 것도 쉽게 가능
  • 포드는 디플로이먼트가 관리
$ kubectl scale deploy http-go --replicas=3
deployment.extensions/http-go scaled

$ kubectl get deploy
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
http-go   1/3     3            1           70m

$ kubectl get deploy -w
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
http-go   1/3     3            1           70m
http-go   2/3     3            2           70m
http-go   3/3     3            3           70m

직접 앱에 접근하기

  • curl 명령어로 요청
  • external IP를 할당 받지 못했기 때문에 포드의 힘을 빌려 요청
$ kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
http-go      LoadBalancer   10.36.15.185   34.64.84.62   8080:31245/TCP   19m
kubernetes   ClusterIP      10.36.0.1      <none>        443/TCP          101m
$ kubectl exec http-go-88b7cdcb5-8rgpb -- curl -s [http://10.36.15.185:8080](http://10.36.15.185:8080)  
Welcome! http-go-88b7cdcb5-bs4xc  
$ kubectl exec http-go-88b7cdcb5-8rgpb -- curl -s [http://10.36.15.185:8080](http://10.36.15.185:8080)  
Welcome! http-go-88b7cdcb5-nhk8c  
$ kubectl exec http-go-88b7cdcb5-8rgpb -- curl -s [http://10.36.15.185:8080](http://10.36.15.185:8080)  
Welcome! http-go-88b7cdcb5-bs4xc

앱의 위치 확인

-o wide 옵션을 사용해서 IP와 NODE등 확장된 정보를 확인할 수 있다

$ kubectl get pod -o wide  
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES  
http-go-88b7cdcb5-8rgpb 1/1 Running 0 31m 10.32.1.6 gke-cluster-1-default-pool-474a6f77-0m6g  
http-go-88b7cdcb5-bs4xc 1/1 Running 0 3m2s 10.32.2.10 gke-cluster-1-default-pool-474a6f77-pd8d  
http-go-88b7cdcb5-nhk8c 1/1 Running 0 3m2s 10.32.0.5 gke-cluster-1-default-pool-474a6f77-m1p9

포드의 자세한 내용 살펴보기

  • 예정된 노드, 시작된 시간, 실행 중인 이미지 등 유용한 정보 포함
$ kubectl describe pod http-go-88b7cdcb5-8rgpb  

쿠버네티스를 활용해서 Jenkins 서비스하기

  • kubectl delete all --all 를 실행해서 모든 서비스를 지우고 시작한다

jenkins 이미지 배포

$ kubectl create deploy jenkins --image=jenkins

jeknkins 실행

$ kubectl expose deploy jenkins --type=LoadBalancer --name jenkins-svc --port=8080 --target-port=8080

LoadBalancer IP 확인

$ kubectl get svc -w  
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE  
jenkins-svc LoadBalancer 10.36.13.223 8080:30005/TCP 29s  
kubernetes ClusterIP 10.36.0.1 443/TCP 8m19s  
jenkins-svc LoadBalancer 10.36.13.223 34.64.84.62 8080:30005/TCP 42s

pod 확인

$ kubectl get pod

jenkins password 확인

$ kubectl exec jenkins-866b579869-fb4qh -- cat /var/jenkins\_home/secrets/initialAdminPassword  
663031dac5ab4af4a00f475b533ea396

logs 로 password 확인

$ kubectl logs jenkins-866b579869-fb4qh  
728x90

댓글

💲 추천 글