PV/PVC 는
1. 정적 매핑
- 개발자와 스토리지 담당자가 대화를 통해 필요한 볼륨을 정의
- 스토리지 담당자는 볼륨을 미리 준비한다. 생성된 볼륨은 pool에 담긴다.
- 개발자는 스토리지 담당자로 부터 접속을 위한 정보(파일시스템 -> NFS, iSCSI..., IP, Access[ReadWriteMany/ReadWriteOnce])를 전달받고 해당 정보를 PVC에 정의한 다음 해당 PVC를 Pod에 작성하여 배포시 지정된 볼륨을 사용한다.
RWO 이면 한 Pod에 한 PV만 연결
RWM 이면 여러 Pod에 한 PV를 연결
-> 정적 매핑은 볼륨의 정확한 정보를 미리 알고 있어야 한다.
2. 동적 매핑
* k8s에서의 계정관리
1. ServiceAccount: 시스템 사용자, 특정 포드, 오브젝트를 사용할 수 있는 권리
2. UserAccount : 전체 클러스터를 대상으로한 사용자, k8s 내에서 별도로 사용자를 생성하는 것이 아니라, 3rd party에서 제공하는 인증서버와 연계해서 사용해야 한다.(들어오기전에 사용자 인증서버를 거치어서 들어오는 계정)
프로비저너는 회사내에서 포드에 볼륨을 제공할 수 있는 스토리지별로 작성한다.
동적과 정적 매핑의 가장 큰 차이점은 정적 매핑은 필요한 볼륨정보를 사전에 담당자와 미리 회의를 통해 결정해야하고 정확한 주소 등을 기록할 수 있어야 한다.
하지만 개발자가 볼륨이 필요할 때마다 담당자에게 연락해서 해당 볼륨을 제공받는 것은 서로에게 불필요한/불편한 작업이 될 것이다. 따라서, 개발자는 볼륨이 필요할 때마다 담당자와의 소통 필요없이 즉시 볼륨을 제공받을 수 있는 것이 필요한데 이것은 동적 PVC에서 제공한다.
---
이제 Pod 안에는 StorageClass가 존재하고 StorageClass는 어떤 Provisioner를 사용할지가 결정되어 잇다. 우리의 Provisioner 코드는 NFS(211.183.3.99/k8s)에게 가게된다. 그렇게 만들어진 PV가 PVC의 요청에 따라서 Pod로 가게 된다.
pv를 사용할 수 있는 포드 배포하기
동적 프로비저너를 사용해서 배포하는 것이 보다 편리할 수 있다.
Pod(PVC -> Storage Class -> Provisioner) ---> NFS(Storage/디렉토리)
SA: 쿠버네티스 내에서 시스템(노드 등등의 오브젝트와 특정 명령을 사용할 수 있는 일종의 계정)
RBAC(Role Based Access Control)
Role(네임스페이스에 속한 오브젝트에 대한 사용가능 명령?)
--- deploy, pod, svc, pvc ... ---
둘을 연결해주는 것이 RoleBinding(Role과 SA를 연결)
SA
ClusterRole(네임스페이스에 속하지 않은 오브젝트에 대한 명령)
--- node, namespace, persistent volume(PV) ... ---
둘을 연결해주는 것이 ClusterRoleBinding(Role과 SA를 연결)
SA
AutoScaling(중요)
-> 클라우드에서는 인스턴스, Pod 와 같은 서비스 실행 주체에대하여 대부분 autoscaling을 제공한다. 특히 퍼블릭 클라우드에서는 이를 편리하게 구성할 수 있도록 서비스를 제공하고 있다.
인스턴스에서는 이런식으로 배포가 된다.
1. Base 이미지를 가지고 인스턴스를 만든다.
2. 인스턴스에는 AmazonLinux가 있고 여기에 httpd, App을 얹었다면 이 두가지가 포함된 인스턴스를 newImage로 만든다.
3. 이렇게 만들어진 이미지는 aws의 AMI 혹은 Docker hub에 담아놓는다. 우리는 newImage를 가지고 새로운 인스턴스 두개를 배포했다. 이것들은 group으로 관리되기 때문에 cpu/ram의 평균값을 알 수 있다. 평균값이 80% 이상이 되면 이미지를 가지고 새로운 인스턴스를 만들라고 한다. 그리고 같은 group안에 포함되게 된다.
k8s에서는 pod를 기준으로 측정한다.
필요한것
1. autoscale의 대상이 될 Pod에서 사용할 수 있는 리소스를 지정한다.
-> 만약 리소스를 지정하지 않는다면 포드는 물리 자원에 대한 제한이 없이 사용할 수 있다.
autoscaler는 포드별 물리자원의 사용량을 확인하고 지정된 % 이상을 사용하게 되면 자동으로 동일한 포드를 늘려나가게 된다. 이때 최소포드 개수와 최대 포드 개수를 지정할 수 있다.
일반적으로 최소 포드 개수는 Deployment에서 지정된 replica 값과 동일하게 설정한다.
min : 3 -> max : 10 (10대의 서버에 각각 한대씩 포드를 배포하게 되므로 실제로는 10대의 서버가 동작하게 된다. 한 서버가 10개의 포드를 가지고 있는것이 아니다.
우리 실습에서는 ingress와 연계하여 사용하면 좋다. 외부 접속자가 http://www.test.com으로 로 접속시 처음 LB(ingress-nginx)를 만나고 LB안의 controller에 만나게 된다.
이 controller에 접속한 사용자가 어디로 접속했는가에 따라서 다른 도메인별 포드로 접속하게 만들어준다.
접속하는 포드가 기능별로 사용량이 늘어남에 따라서 포드의 갯수를 증가시키어 주기도 한다.
---
우리의 CI/CD는 kvm + k8s + ansible + (CI/CD 1. github + jenkins 2. gitlab)구조로 사용할 것이다.
실재로 사용하는 서비스는 Vagrant(IaC)이다. Vagrant는 yaml파일로 kvm과 같은 하이퍼바이저에게 작업지시를 보내게 된다.
Discover Vagrant Boxes - Vagrant Cloud (vagrantup.com)
Vagrant Cloud by HashiCorp
Vagrant Cloud by HashiCorp
app.vagrantup.com
이미지는 위의 사이트에서 받아오면 된다.
그리고 provision에 있는 bootstrap.sh을 인스턴스 내부에서 실행하라는 의미이다.
vagrant는 자기가 작업한 내용을 libvirt(kvm)에게 전달해야 한다. 이게 전달되면 hypervisor가 인스턴스를 만들게 된다.
인스턴스 배포를 vagrant로 하게되면 한꺼번에 생성/삭제가 되기 때문에 IaC 입장에서 굉장히 편해진다.
인스턴스가 배포되면 자신만의 vResource가 배포되고 그 위에 OS가 배포된다. 그리고 우리는 이 위에 k8s를 설치하자는 것이다. 그리고 overlay를 위한 Add-on(calico, flunel, weaver net)들을 깔면 노드들간의 소통이 가능해진다.
클러스터를 구성하고 나면 pod를 배포해야 한다. 각 노드 위에 pod를 배치해주어야 한다. pod가 배치된 상태에서 우리는 클러스터 상태를 관리하고 싶어진다. 이를 위해 위쪽은 WeaveNet으로 연결해주고 아래쪽은 서버자체관리하는 네트워크를 연결해준다.
연결된 네트워크에서 노드가 너무 많아지면 Ansible을 이용해서 관리해주어야 한다. 반드시 Ansible이 아니더라고 Terraform을 이용해서 관리해줄 수도 있다.
---
우리의 CI/CD는 kvm + k8s + ansible + (CI/CD 1. github + jenkins 2. gitlab)구조로 사용할 것이다.
실재로 사용하는 서비스는 Vagrant(IaC)이다. Vagrant는 yaml파일로 kvm과 같은 하이퍼바이저에게 작업지시를 보내게 된다.
ci/cd 를 이용한 k8s 관리
ci/cd 가 나온이유는 결국 개발자와 인프라 관리자 사이의 불협화음을 줄이기 위한 것이다. 나중에는 TA에게 요구해서 처리하기도 한다.
위와 같은 불필요함, 비효율성을 주이기 위해 CI/CD가 필요하다.
CI/CD의 Pipeline을 이용하면 코드 빌드에서 부터 배포까지 개발자는 인프라담당자의 간섭없이 진행할 수 있다.
jenkins
pipeline
Pipeline Syntax
When Jenkins Pipeline was first created, Groovy was selected as the foundation. Jenkins has long shipped with an embedded Groovy engine to provide advanced scripting capabilities for admins and users alike. Additionally, the implementors of Jenkins Pipelin
www.jenkins.io
pipeline 작성은
pipeline {
/* insert Declarative Pipeline here */
}
내에 섹션을 구분하여 작성한다.
- agent : runtime 불러오기, 누구를 이용하여 아래의 작업을 진행할 것인가?
- post : 작업진행된 결과에 따라 출력할, 실행할 요소(시작전 또는 실행 이후 가능)
1) 특정 스테이지나 파이프라인이 시작되기 전 또는 이후에 실행할 컨디션 블럭
1.1) always : 실행 이후 무조건 실행되는 step (결과 코드와 상관없이)
1.2) failure : 실패하면 실행
1.3) success : 성공하면 실행
1.4) unstable : testfail, code violation 등일 때 실행
1.5) aborted : 실행 중간에 강제로 종료되었을 때
- stages : 작업을 올려두는 곳. stage 내에 여러개의 stage를 사용
1) 하나 이상의 stage에 대한 모음을 정의
2) 파이프라인 내에서 한번만 사용할 수 있다
3) stages 내에서 여러개의 stage를 사용할 수 있다.
- steps : stage 내에서 실제로 작업할 내용을 순서대로 작성
1. stages 내에 있는 stage('작업 이름')을 이용하여 각 작업을 구분한다.
2. 각 stage 블록 내에서 여러번의 작업을 순서대로 작성한다.
* 큰 흐름은 이 순서대로 작성된다.
agent
- agent : runtime 불러오기 누구를 이용하여 아래의 작업을 진행할까?
1. any : 모든 agent에서 불러와서 실행해 본다.
2. none : 여기에서는 내가 정확히 지정하지 않지만 각각의 stage에서 지정해서 쓰겠다.
3. label :
4. node :
5. docker :
이렇게 작성해주어서 해도 되고 yaml 파일을 작성해서 실행시키어도 된다.
---
post의 예시
---
이외의 것들
input : stage 내에서 실행할때 사용자로부터 입력을 받는다.
stage 내에 위치하고 작업이 진행될 때, 사용자로부터 입력값을 받을 수 있다. 입력된 내용은 사용자가 지정한 변수에 담겨 이를 step 내에 적용한 뒤 실행할 수 있다.
1) message : 실행될 때 팝업으로 뜨는 메시지
"이름을 입력하세요"
2) ok : 다음 실행으로 넘어갈 때 화면에 보이는 버튼에 어떤 글자를 뜨게 할 것이냐? "next"와 같은 버튼을 뜨게 하여 다음 단계로 넘어가게 만들어주기
3) parametes : 사용자로부터 입력받은 값을 input에 넣기
- string : 입력창에 받는 데이터의 형을 문자열로 받겠다
- name : 입력되는 문자열을 저장하는 변수명
- defaultValue : 입력값이 없다면 변수에 담기는 기본 값
- description : 주석
pipeline {
agent any
stages {
stage('test1'){
steps{
echo "HELLO ALL1"
}
}
stage('test2'){
steps{
echo "HELLO ALL2"
}
}
}
}
단순하게 만들어서 실행해보자
실행해보니 별거 없다. HELLO ALL1, HELLO ALL2 가 뜬것을 볼 수 있다.
pipeline {
agent any
stages {
stage('test1'){
steps{
echo "HELLO ALL1"
}
}
stage('test2'){
input {
message "What is your name?"
ok "finished"
parameters {
string(name: 'NAME', defaultValue: 'GILDONG', description:'type your name')
}
}
steps{
echo "HELLO ${NAME}"
}
}
}
}
이번에는 마우스포인터를 올려놓으니 입력창이 뜬것을 볼 수 있다.
내 이름이 출력된 부분을 확인할 수 있다.
---
pipeline {
agent any
stages {
stage('test1'){
steps {
echo "HELLO ALL1"
}
}
stage('test2'){
input {
message "What is your name?"
ok "Next"
parameters {
string(name: 'NAME', defaultValue: 'GILDONG', description: 'type your name')
}
}
steps {
echo "HELLO ${NAME}"
}
}
stage('test3'){
input {
message "Docker image tag name"
ok "finished"
parameters {
string(name: 'TAG', defaultValue: 'none', description: 'type docker image tag')
}
}
steps {
sh '''
sudo rm -rf /var/lib/jenkins/workspace/testjenkinsfile/cicdtest
git clone https://github.com/beomtaek78/cicdtest.git
cd cicdtest
sudo docker build -t brian24/webtest:${TAG} .
sudo docker push brian24/webtest:${TAG}
sudo sed -i 's@image: nginx@image: brian24/webtest:'"${TAG}"'@g' nginx.yaml
sudo kubectl apply -f nginx.yaml
'''
}
}
}
post {
always {
echo "작업완료 - 성공실패여부 모름"
}
}
}
위의 코드는 사용자로부터 태그 버전을 입력받아 업로드 하는 과정을 담았다.
무중단 상태에서 업데이트 = 롤링업데이트 전략
Recreate : 기존 pod를 완전 삭제 & 새로 만들기 -> 서비스의 Downtime이 발생 = Downtime 만큼 가용성이 떨어짐
RollingUpdate(기본값) : 기존것을 죽여가면서 새로운 것을 하나씩 만들억가는 방식
Deployment 안에 replicas를 3으로 해놓고 이 안에 컨테이너들은 nginx로 배포한 상태이다.
우리가 나중에 jenkins로 input image tag 값을 받았다. 그럼 tag를 붙이 새로운 이미지가 만들어지고 이게 docker hub로 올라간다. 그리고 docker hub로 부터 이미지를 끌고 오고 Deployment에서 새로운 이미지를 끌고 올 것이다.
그럼 nginx가 아닌 새로운 이름의 이미지로 Pod가 변경될 것이다. 이걸 rolling update라고 부른다.
```
k get deploy
k describe deploy deploy-nginx
```
보면 위와같이 StrategyType이 RollingUpdate 인 것을 볼 수 있다.
그리고 RollingUpdate의 전략도 보인다.
max unavailable : 롤링업데이트 중 동시에 삭제할 수 있는 포드의 최대 수
max surge : 생성할 수 있는 최대 포드의 수
이때의 25%는 전체 포드 갯수중에서 25%라는 의미이다.
노드의 성능 및 리소스를 고려하여 수정해야하는 부분이다. 그럼에도 기본값은 모두 25%이다.
GCP
개발을 해보자
VM에서 GCP에 들어와보자
GCP는 프로젝트 단위로 작업을 진행한다. 그리고 이때 GCP의 프로젝트 id는 타 프로젝트와 독립적이다.
왼쪽 3줄을 클랙해서 대시보드로 들어가고
이 안에서 새 프로젝트를 생성하자
가급적 프로젝트 이름과 프로젝트 ID를 동일하게 설정해놓자
대시보드의 프로젝트 설정으로 이동을 클릭하자
종료가 보인다. 이걸로 프로젝트를 죽일수도 있다.
GCP도 AWS와 동일하게 Region이 있고 이 안에 zone들이 들어가 있다. 실재 데이터센터는 zone으로 구성되어 있다. 이때 zone은 물리적 DC이고 Region은 zone의 집합이자 논리적 zone의 연결이다. Region 내의 모든 zone은 ISP를 통한 네트워크가 이중화 되어 있다.
이때 zone 내부에서는 과금되지 않는다 사설구간이니 ISP를 거치지 않으므로 추가비용 발생 없다.
하지만 조금만 외부로 나와 다른 zone으로 가는 IP들은 무조건 과금이 된다.
이제 같은 zone 내부에서 통신은 가능하지만 다른 zone과의 통신은 사설 ip를 사용해서 어려운 부분이 존재한다.
1. 하나의 zone 내부에서 각 작업공간 분리? Vlan 이용
- vlan을 사용해서 패킷을 보내더라도 패킷을 한번더 감싸는 기술이 필요해진다.
vlan은 다른 zone 이더라도 같은 번호를 사용할 수 있다. 그래서 다른 zone의 vlan이라고 하더라도 논리적으로 같은 그룹이 되도록 만들어줘야 한다. 그래서 이 vlan들을 같은 그룹으로 묶어 주자.
이때의 그룹 번호는 클라우드 내에서 unique한 번호가 된다. 각 프로젝트별 unique한 번호인 것이다.
이 번호가 패킷의 앞쪽에 붙어 L3에서도 유지되도록 해야한다.
각 그룹별로 1개의 프로젝트가 할당될것이고 클라우드 내에서 unique한 번호가 할당될 것이다. 이는 곧 하나의 테넌트 번호와 같다. 우린 이 번호를 보고 VxLAN 번호라고 부른다. 데이터센터내에서 각 프로젝트별로 unique한 VxLAN을 할당받게 되면 각각의 프로젝트를 구분하고 이 번호를 통해 서버들을 하나의 작업공간으로 만들어 줄 수 있다.
그리고 이 들이 인터넷을 가로질러 연결하기 위해서는 Tunneling 기술이 필요해진다.(GRE tunnel, VxLAN)
gcp 내에서 새로운 프로젝트를 만들어보자.
이렇게 만들어지면 대시보드로 가보자
`google cloud platform sdk` 라고 검색해보자 이걸 이용하면 ubuntu의 CLI 환경에서 개발할 수 있다.
https://cloud.google.com/sdk/docs/install
Cloud SDK - 라이브러리 및 명령줄 도구 | Google Cloud
Cloud SDK는 Google Cloud에서의 개발을 위한 도구 모음으로 gcloud, gsutil, bq 명령줄 도구, 클라이언트 라이브러리, 로컬 에뮬레이터가 포함되어 있습니다.
cloud.google.com
위의 사이트에서 가서 debian 버전을 사용하자
```
sudo apt-get install apt-transport-https ca-certificates gnupg
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
sudo apt-get update && sudo apt-get install google-cloud-cli
```
모두 완료되었다면
```
gcloud init
```
하면 url이 뜰것이고 그 링크를 따라가면 google cloud sdk 로그인에 대한 정보가 나오게 된다.
그러면서 project id가 나오게 된다. 우리가 만든 프로젝트를 선택해주자
gcloud config list project
하면 나오는 project id를 PROJECT_ID 에 등록해놓자
```
gcloud config list project --format "value(core.project)"
```
해서 자신의 프로젝트 이름이 잘 나오면 된다. 참고로 gcloud sdk는 가급적 mobaXterm같은 외부 소프트웨어 말고 컴퓨터 자체에서 실행시키어주어야 잘 작동한다.
'Development(Web, Server, Cloud) > 22) LINUX - Cloud' 카테고리의 다른 글
클라우드 69일차(aws-정리중, ansible, ????) (0) | 2022.05.02 |
---|---|
클라우드 68일차 (0) | 2022.04.29 |
클라우드 66일차(k8s-labeling, ansible, jenkins) (0) | 2022.04.27 |
클라우드 65일차(정리중, autoscale, jenkins) (0) | 2022.04.26 |
클라우드 64일차 (MSA, 다이나믹 pvc, 동적 pv, 정리중) (0) | 2022.04.25 |