[CKAD] Kubernetes Certificate Application Developer(CKAD) with Tests 학습노트(3/)
Container Image Build using Docker
컨테이너를 서비스하려면 컨테이너 이미지를 결국 만들어야 한다. 컨테이너 이미지를 만든다는 것은 무엇일까? 기존의 서버 기반 구조에서 웹 서비스를 예로 들어 생각해보면, 베이스 이미지파일을 만드는 것과 동일한 작업이라고 생각하면 된다. flask(python)를 이용한 웹 서비스를 위한 서버를 준비한다고 생각해보자.
- OS를 설치하고
- 기본적인 업데이트를 수행하고
- 디벤던시가 있는 패키지에 대한 repo와 설치(apt or yum or dnf)를 수행하고
- python(pip)과 flask, 필요 라이브러리를 설치하고
- 소스 코드를 git에서 내려받아 서비스 경로(ex. /opt)에 카피하고
- 서비스로 flask를 등록하여 서버 리셋시 자동으로 웹 서비스가 수행되게 한다.
이런 베이스 이미지가 있으면, 해당 이미지를 실행하여 워크로드를 수행할 수 있고, 이미지를 복사하여 스케일링을 진행할 수 있다.
위 과정을 컨테이너 이미지로 만드는 과정을 dockerfile로 작성하면 아래와 같다.
FROM ubuntu # OS를 설치하는데신 베이스 OS 컨테이너 이미지를 가져오고RUN apt-get update # 업데이트를 수행하고RUN apt-get install python # python을 설치하고RUN pip install flask # flash를 설치하고RUN pip install flask-mysql # 라이브러리를 설치하고COPY . /opt/source-code # 소스 파일을 필요 경로에 복사한 후ENTRYPOINT FLASK_APP=/opt/source-code/app.py flask run # 해당 소스 파일을 flask로 실행한다
Authentication & Authorization
쿠버네티스 클러스터, 즉, ApiServer에 대한 Authentication & Authorizaiton을 어떻게 구성할 것인가?
Authentication
쿠버네티스는 기본적으로 ldap과 같은 외부 소스에 사용자 인증을 의존한다.
아이디비밀번호를 이용한 인증
1
api서버 실행시 유저 정보를 csv로 던지기
--basic-auth-file옵션을 넣고 kube-apiserver를 실행하면 해당 파일의 인증 정보를 사용할 수 있다.
$ kube-apiserver --basic-auth-file=user-defailts.csv ...
csv로 생성된 인증파일 구조는 아래와 같은 형태를 가진다.
password123,username1,user1,group1
curl을 이용시 유저 정보 던지기
curl로 api 호출시 -u 옵션에 유저:비밀번호를 던지면 된다.
curl -v -k https://apiserver-masternode:6443/api/v1/pods -u "username:passwordofuser"
토큰을 이용한 인증
api서버 실행시 유저 정보를 csv로 던지기
--basic-auth-file옵션을 넣고 kube-apiserver를 실행하면 해당 파일의 인증 정보를 사용할 수 있다.
$ kube-apiserver --basic-auth-file=user-defailts.csv ...
csv로 생성된 인증파일 구조는 아래와 같은 형태를 가진다.
<tokenvalue>,username1,user1,group1
curl을 이용시 유저 토큰 던지기
curl로 api 호출시 --header 옵션에 토큰값을 추가하여 던지면 된다.
curl -v -k https://apiserver-masternode:6443/api/v1/pods --header "Authorization: Bearer <tokenvalue>"
당연히 파일에 모든 인정 정보가 적히므로 권장되는 방법은 아니다.
KubeConfig
kubectl로 명령을 날릴 때는 kubeapiserver를 통해 요청을 날리게 된다. masternode에서 kubectl을 수행할 때는 인증이 되어 있지만 그렇지 않은 masternode가 아닌 곳에서 kubectl로 kubeapiserver에 요청을 날리려면 어떻게 해야할까? 다음과 같이 apiserver 엔드포인트와 인증서들을 옵션으로 던져주면 된다.
kubectl get pods--sever <kubeapisevrerdomain>:6443--client-key admin.key # 클라키(개인키)--client-certificate admin.crt # 클라 인증서(공개키)--certificate-authority ca.crt # 서버 인증서(공개키)
매번 치는게 까라로우니 하나의 KubeConfig로 넣어서 관리한다면 다음과 같은 옵션을 줄 수 있는데,
kubectl get pods --kubeconfig config
--kubeconfig config는 $HOME/.kube/config 아래에 있는 파일 경로이다. 즉, $HOME/.kube/config에 옵션 정보를 담아두면 한번에 적용할 수 있다.
kubeconfig파일의 구성은 clusters, contexts, uesrs 세 부분으로 이루어져있다.
- clusters: 클러스터 정보. 개발/운영 등
- users: 유저 정보. 관리자, 개발자 등
- context : cluster + user. 관리자@운영, 개발자@개발 등
위의 예제의 정보들은 각각의 영역으로 들어가게 된다.
- 클러스터 영역 : MyKubeCluster --sever kubeapisevrerdomain:6443
- 유저 영역 : MyKubeAdmin --client-key admin.key # 클라키(개인키) --client-certificate admin.crt # 클라 인증서(공개키) --certificate-authority ca.crt # 서버 인증서(공개키)
- 컨텍스트 영역 : MyKubeAdmin@MyKubeCluster
마스터노드에서 kubectl로 명령을 입력할 때 인증정보를 넣지 않아도 되는 것은 해당 정모들이 이미 입력되어 있기 때문임을 알 수 있는데 다음 명령으로 현재 config 내용을 확인할 수 있다.
$ kubectl config viewapiVersion: v1kind: Configcurrent-context: MyKubeAdmin@KubeCluster # 복수의 컨텍스트가 있을 때 기본 컨텍스트 설정 가능clusters:- cluster:certificate-authority-data: ca.crt# or certificate-authority-daya: <base64로 변환된 crt파일내용 전체를 밀어넣으면 동일하게 동작>server: <kubeapisevrerdomain>:6443name: MyKubeClustercontexts:- context:cluster: MyKubeClusteruser: MyKubeAdminnamespace: defaultname: MyKubeAdmin@MyKubeClusterpreferences: {}users:- name: MyKubeAdminuser:client-certificate: admin.crtclient-key-data: admin.key
config내에 정의된 context 중 다른 context를 이용하고 싶다면 아래 명령을 수행하면 된다.
kubectl config use-context MyKubeAdmin@KubeCluster
API Groups
kubectl utility여러 그룹으로 나누어져있다. deployment를 get하는 api를 살펴보면 다음과 같다. /apis/apps /v1 /deployments /get
- apigroup - resource - verb
Authorization
Node : ABAC : RBAC : Webhook : AlwaysAllow : 기본모드. 모두 허용 AlwaysDeny : 모두 거부
kube-apiserver --authorization-mode=AlwaysAllow # 옵션이 없으면 기본적으로 모두 허용--authorization-mode=Node,RBAC,Webhook # 이렇게 여러 개를 적을 수 도 있음. 실행할 때 작성한 순서대로 체크함.
RBAC
Role Base Access Control.
role and rolebinding
쿠버네티스는 롤과 롤바인딩을 이용하여 RBAC을 구현한다.
특정 에이피아이그룹의 리소스에 대해 수행할 수 있는 권한을 롤로 생성하고, 생성한 롤을 유저에게 바인딩시켜 롤별 권한을 설정한다.
롤과 롤바인딩은 네임스페이스
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: developerrules:- apiGroups: [""]resources: ["pods"]verbs: ["list", "get", "create", "update", "delete"]resourceNames: ["podname"] # 특정 pod에 대한 권한을 주고 싶으면 여기를 추가하자.- apiGroups: [""]resources: ["ConfigMap"]verbs: ["create"]
rolebinding
apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: devuser-developer-bindingsubjects:- kind: Username: dev-userapiGroup: rbac.authorization.k8s.ioroleRef:kind: Rolename: developerapiGroup: rbac.authorization.k8s.io
taroguru@taroguruui-MacBookAir yamls % k describe role developerName: developerLabels: <none>Annotations: <none>PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----ConfigMap [] [] [create]pods [] [] [get list watch create update delete]taroguru@taroguruui-MacBookAir yamls % k describe rolebinding devuser-developer-bindingName: devuser-developer-bindingLabels: <none>Annotations: <none>Role:Kind: RoleName: developerSubjects:Kind Name Namespace---- ---- ---------User dev-user
check access resource
다음 명령을 통하여 액션을 확인할 수 있다. k auth can-i 명령 리소스 k auth can-i 명령 리소스 --as user
실행하면 다음과 같다.
taroguru@taroguruui-MacBookAir yamls % k auth can-i create deploymentsyestaroguru@taroguruui-MacBookAir yamls % k auth can-i delete nodesWarning: resource 'nodes' is not namespace scopedyestaroguru@taroguruui-MacBookAir yamls % k auth can-i delete nodes --as dev-userWarning: resource 'nodes' is not namespace scopedno
Cluster Roles
namespace로 pod와 같은 리소스를 분류하여 관리할 수 있다. 하지만 node나 pv같은 자원은 어떨까? cluster scope의 리소스에 대해서 관리할 필요가 있다.
clusterrole
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: cluster-administratorrules:- apiGroups: [""]resources: ["nodes"]verbs: ["list", "get", "create", "delete"]
clusterrolebinding
apiVersion: rbac.authorizaiton.k8s.io/v1kind: ClusterRoleBindingmetadata:name: cluster-admin-role-bindingsubjects:- kind: Username: cluster-adminapiGroup: rbac.authorization.k8s.ioroleRef:kind: ClusterRolename: cluser-administratorapiGroup: rbac.authorization.k8s.io
Admission Controller
rolebaseaccesscontrol은 리소스 단위의 동작(verb)만 권한을 제어할 수 있다. 하지만 세세한 권한(로컬 이미지만 사용 or 루트 유저로 pod 수행 등)을 제어하려면 어떻게 해야 할까? 이때 Admission controller를 사용한다. Admission Controller는 Authentication & Authorization이후에 사용된다. 1.27에서 기본 플러그인은 다음과 같다.
CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, LimitRanger, MutatingAdmissionWebhook, NamespaceLifecycle, PersistentVolumeClaimResize, PodSecurity, Priority, ResourceQuota, RuntimeClass, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionPolicy, ValidatingAdmissionWebhook
mutating and validating admission webhook
admission webhook은 두 가지 종류의 작업을 한다. 첫 번째는 validating이다. 예를 들어 k get pod --namespace blue를 던졌을 때 NamespaceExists가 blue라는 네임스페이스가 있는지 없는지에 대한 validating을 수행하고 그 결과를 던져준다. 두 번째는 mutating이다. 요청한 내용을 변경한다는 것인데, 예를 들어 pvc 생성이 들어왔을 때 storageclass가 없으면 defaultstorageclass로 구성되도록 요청을 변경할 수 있다. securitycontext로 작성할 수 있으며, 기본 유저 정보 등을 채울 수 있다. 작업 순서는 mutating and validating 순서로 진행된다.
API Versions
API and API Groups
APIVersion 분류
기본적으로 다음과 같은 버전을 가진다.
- /v1alpha1 : 알파버전. 기본적으로 활성화되지 않는다.
- apiVersion에 명백하게 alpha1이라고 기입하여야 함.
- 지금쓰고 있지만 또 사라질 수 있는 그런 느낌
- /v1beat1 : 베타버전
- /v1 : GA / stable version
API Deprecation
당연히 deprecation되기도 한다. api deprecation policy을 알아야하는데,
Rule #1 : API elements는 API Group의 버전이 증가할 때만 삭제할 수 있다
Rule #2 : API 오브젝트들은 API 버전사이를 라운드트립할 수 있어야 한다. 예를 들어, 객체를 v1로 작성한 다음 v2로 다시 읽고 v1로 변환할 수 있으며, 그 결과 생성되는 v1 리소스는 원본과 동일합니다. v2의 표현은 v1과 다를 수 있지만 시스템은 양방향으로 변환하는 방법을 알고 있습니다. 또한 v2에 추가된 새 필드는 v1과 왕복할 수 있어야 하므로 v1에 동등한 필드를 추가하거나 주석으로 표현해야 할 수도 있습니다.
Rule #3: 특정 트랙의 API 버전은 안정성이 떨어지는 API 버전을 위해 더 이상 사용되지 않을 수 있습니다.
- GA API 버전은 베타 및 알파 API 버전을 대체할 수 있습니다.
- 베타 API 버전은 이전 베타 및 알파 API 버전을 대체할 수 있지만 GA API 버전을 대체할 수는 없습니다.
- v2alpha, v2beta가 v1(ga or stable)을 대체할 수 없음
- 알파 API 버전은 이전 알파 API 버전을 대체할 수 있지만 GA 또는 베타 API 버전을 대체할 수는 없습니다.
규칙 #4a: API 수명은 API 안정성 수준에 따라 결정됩니다.
규칙 #4b: 특정 그룹의 '기본' API 버전과 '저장소 버전'은 새 버전과 이전 버전을 모두 지원하는 릴리스가 만들어질 때까지 진행되지 않을 수 있습니다.
버전 선택은 kube-apiserver의 --runtime-config=api/version을 통해서 설정할 수 있다.
Custom Resource Definition
pod, deployment같이 미리 정의된 리소스가 아닌 커스텀 리소스에 대한 정의를 할 수 있다. 그야말로 무엇이나 정의할 수 있다. 예를 들어 FlightTicket이라는 리소스를 정의한다고 하자. create, get delete 명령으로 해당 리소스를 관리할 수 있다. 이를 위해서
- CRD - Custom Resource Definition을 정의해야 한다. 아래와 같은 yaml을 통하여 crd를 정의할 수 있다.
apiVersion: apiextensions.k8s.io/v1kind: CustomResourceDefinitionmetadata:name: flighttickets.flights.comspec:scope: Namespacedgroup: flights.comnames:kind: FlightTicketsingular: flightticketplural: flightticketsshortNames:- ftversions:- name: v1served: truestorage: trueschema:openAPIV3Schema:type: objectproperties:spec:type: objectproperties:spec:type: objectproperties:from:type: stringto:type: stringnumber:type: integerminimum: 1maximum: 10
위 yaml로 flightticket이라는 crd를 정의할 수 있다.
Custom Controllers
Custom Definition Resource를 정의한 후 생성한 create/get/delete 오퍼레이션은 단순히 etcd에 데이터를 갱신하기만 한다. Custom Controller는 crd로 정의한 커스텀 리소스에 대한 실제 동작을 구현한 declarative API이다.
Operator Framework
일단 패스
Deployment Strategy
- Recreate : 한번에 다 내리고 올림. 일시 다운됨.
- Roling Update : 기본 배포 전략
- Blue/Green : Old(Blue)를 두고 New(Green)을 배포. Green이 정상 동작이면 Green으로 서비스 시작. istio같은 서비스 메시에서 적당함
- service의 selector를 조정하여 배포 가능
- Canary : 전체 워크로드 중 일부 워크로드만 올려서 정상 동작하는지 확인하고 정상 동작하면 나머지 전체를 돌려서 배포 예를 들어 old:new=4:1의 비율로 카나리 배포로 새로운 배포를 수행한다고 하면,
- 사전 상태 : serivce, deployment(old)가 생성되어 있고 selector가 동일
- 사전 상태 : deployment의 replicas는 4인 상태
- deployment(new)를 하나 생성. selector를 동일하게 맞춤
- 동일 셀렉터로 잡히는 워크로드(pod)가 4:1의 비율로 돌고있으므로 4:1의 비율로 배포됨
- 정상 동작하는지 테스트
- deployment(new)의 replicas를 4개로 올리고 deployment(old)의 replicas를 0으로 줄임(삭제)
- 종료
Helm
helm은 kubernetes상에서 돌아가는 워크로드에 대한 패키지매니저다. 예를 들어 워드프레스를 서비스 하려고하면, 웹서버, php, mysql 등 다양한 구성 요소들을 설치하고 설정해야 하는데 helm을 이용하면 패키지매니저의 사용자 경험을 이용하여 이런 기능을 사용할 수 있다.
helm install wordpresshelm upgrade wordpresshelm roleback wordpress...
helm concept
wordpress를 기준으로 생각해보자. 웹 프론트를 위한 pod, 공간을 위한 pv와 pvc, 이를 배포할 프론트 service, 관리자 비밀번호 등 다양한 정보들이 필요하다. helm chart는 이런 정보를 관리하기 위한 구조를 가진다. 이를 위해 기본적인 yaml의 틀을 template으로, 각 서비스에 필요한 값들은 values.yaml로 관리된다. 긜고 이런 정보들이 chart.yaml로 관리된다.
주요 명령
다음과 같은 주요 명령을 가진다.
helm install RELEASE-NAME CAHRT-NAME