0 VirtualBox 및 가상 이미지 셋팅
1. 이미지 파일 다운로드
실습 Ubuntu-20.04 이미지: ubuntu-20.04.1-desktop-amd64-dockerzshsudo-20201227.ova 다운로드
- https://drive.google.com/file/d/1MPL1VUEUkEil6_4X4s-Ed-ubca0W08Jq/view?usp=sharing
- ID/PW: sever1/1111
- 관리자 전환: sudo -i
2. 환경에 맞게 VirtualBox 다운로드
https://www.virtualbox.org/wiki/Downloads
3. 가상 시스템 가져오기
- VirtualBox를 실행하고 파일 - 가상 시스템 가져오기로 다운받은 ubuntu-20.04.1-desktop-amd64-dockerzshsudo-20201227.ova 이미지 셋팅
- 셋팅된 가상 이미지 실행
- 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 네트워크 설정
-
VitualBox 설정 클릭
-
Nat 네트워크 추가
-
각 이미지 마다 설정 버튼 클릭해서 네트워크 설정
-
각 이미지 마다 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
애플리케이션 생성과 확인
- nginx master node 및 work node 에 설치
$ kubectl run nginx --image=nginx
pod/nginx created
- 설치된 Application 확인
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 11s
- 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
'개발강의정리 > DevOps' 카테고리의 다른 글
[데브옵스를 위한 쿠버네티스 마스터] 연습문제: GKE에서 인그레스를 활용한 로드밸런싱 프로세스 확인 (0) | 2020.08.22 |
---|---|
[데브옵스를 위한 쿠버네티스 마스터] 4. 쿠버네티스 핵심 개념 (0) | 2020.08.22 |
[데브옵스를 위한 쿠버네티스 마스터] 2. 쿠버네티스 소개 (0) | 2020.08.18 |
[데브옵스를 위한 쿠버네티스 마스터] 1. Docker 요약 정리 (0) | 2020.08.17 |
[도커(Docker)의 이해] 4. 이미지 빌드 환경 만들기 (0) | 2019.10.07 |
댓글