디플로이먼트
https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/
디플로이먼트 작성하기
cat <<EOF > nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3 # 복제본 수
selector:
matchLabels:
app: nginx # 셀렉터
# 파드의 모양
template:
metadata:
labels:
app: nginx # 파드의 레이블
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF
kubectl apply -f nginx-deployment.yaml
디플로이먼트와 함께 레플리카셋과 파드가 잘 생성되는지 확인한다.
$ kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 3/3 3 3 12s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-7fb96c846b 3 3 3 12s
NAME READY STATUS RESTARTS AGE
pod/nginx-7fb96c846b-4whk8 1/1 Running 0 12s
pod/nginx-7fb96c846b-hh7xv 1/1 Running 0 12s
pod/nginx-7fb96c846b-wflp9 1/1 Running 0 12s
레플리카셋의 파드 복원 기능 테스트
파드를 하나 강제로 삭제하고 레플리카셋이 이것을 복구하는 지 확인해보자.
kubectl delete pod nginx-7fb96c846b-4whk8
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-7fb96c846b-hh7xv 1/1 Running 0 101s
nginx-7fb96c846b-p5tnl 1/1 Running 0 7s
nginx-7fb96c846b-wflp9 1/1 Running 0 101s
파드의 스케일 수정하기
kubectl scale deployment nginx --replicas=10 # 확장
kubectl scale deployment nginx --replicas=5 # 축소
연습문제
- jenkins/jenkins 이미지를 사용해 디플로이먼트 deploy-jenkins를 생성하라.
- jenkins 디플로이먼트로 배포되는 앱을 app: jenkins-test로 레이블링하라.디플로이먼트가 잘 생성되었는지 확인한다.
- $ kubectl get pod -w NAME READY STATUS RESTARTS AGE deploy-jenkins-8688796664-75c4n 1/1 Running 0 25s deploy-jenkins-8688796664-klpnr 1/1 Running 0 25s deploy-jenkins-8688796664-ldx7r 1/1 Running 0 25s
- cat <<EOF > jenkins-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: deploy-jenkins spec: replicas: 3 selector: matchLabels: app: jenkins-test # 셀렉터 # 파드 템플릿 template: metadata: labels: app: jenkins-test # 레이블 spec: containers: - name: jenkins image: jenkins/jenkins ports: - containerPort: 8080 EOF kubectl apply -f jenkins-deployment.yaml
- 디플로이먼트로 배포된 파드를 하나 삭제하고 이후 생성되는 파드를 관찰하라.
- kubectl delete pod deploy-jenkins-8688796664-75c4n $ kubectl get pod NAME READY STATUS RESTARTS AGE deploy-jenkins-8688796664-4t6t8 1/1 Running 0 5s deploy-jenkins-8688796664-klpnr 1/1 Running 0 74s deploy-jenkins-8688796664-ldx7r 1/1 Running 0 74s
- scale 명령을 사용해 레플리카 수를 5개로 정의한다.
- kubectl scale deployments deploy-jenkins --replicas=5
secret 저장소를 활용한 mysql 패스워드 설정
CI/CD의 과정에 따라 민감정보를 전달하면 불필요한 사람들에게 정보가 전달될 가능성이 있다. 따라서 배포하는 시점에 비밀정보를 전달할 수 있는 방법에 대해 익혀보자.
mysql 패스워드를 구성할 secret을 생성한다.
- 파일 이름: 키 (passwd)
- 파일 내용: 값 (test1234)
echo -n test1234 > passwd # 패스워드 관련 파일 생성
kubectl create secret generic mysql-pw --from-file=passwd # 앞서 생성한 파일을 사용해 시크릿 저장소를 구성한다.
kubectl get secret mysql-pw -o yaml # 잘 생성되었는지 출력
data의 부분에 passwd가 채워져 있는 모습이다.
apiVersion: v1
kind: Secret
metadata:
creationTimestamp: "2022-09-25T05:51:53Z"
name: mysql-pw
namespace: default
resourceVersion: "6447"
uid: 5223982d-1880-4276-a54a-5de6e02b92a4
type: Opaque
data:
passwd: dGVzdDEyMzQ= # base64 encode
안전하게 보관하기 위해 etcd 데이터베이스를 디스크 암호화를 하는 것을 추천
echo dGVzdDEyMzQ= | base64 -d # test1234
쿠버네티스에서 파드에 시크릿을 환경 변수로 전달하는 방법을 찾으면 됨
https://kubernetes.io/ko/docs/concepts/configuration/secret/#시크릿을-환경-변수-형태로-사용하기
echo -n test1234 > passwd # 패스워드 관련 파일 생성
kubectl create secret generic mysql-pw --from-file=passwd # 앞서 생성한 파일을 사용해 시크릿 저장소를 구성한다.
kubectl get secret mysql-pw -o yaml # 잘 생성되었는지 출력
cat <<EOF > mysql-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql
spec:
containers:
- name: mysql
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD # 컨테이너 개발자가 정한다.
valueFrom:
secretKeyRef:
name: mysql-pw # 시크릿 이름
key: passwd # 키 이름
EOF
kubectl apply -f mysql-pod.yaml
잘 실행되는지 관찰하고
kubectl get pod -w
접속해보자.
mysql 명령어로 127.0.0.1에 있는 mysql 서버로 접속한다. 이때 사용하는 유저는 root고 패스워드를 사용해 인증하겠다. 나올 때 exit 명령을 실행한다.
kubectl exec -it mysql -- mysql -h 127.0.0.1 -u root -p
쿠버네티스 시스템 컴포넌트
쿠버네티스 시스템에 필요한 파드들은 kube-system이라는 네임스페이스에서 동작 중이다. 우리가 사용하는 네임스페이는 default 네임스페이스다.
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-58dbc876ff-g58tn 1/1 Running 2 3d17h
canal-gjbhw 2/2 Running 0 40m
canal-vmxzc 2/2 Running 0 40m
coredns-584f54878-dmj2q 1/1 Running 0 3d17h
coredns-584f54878-ftz24 1/1 Running 0 3d17h
etcd-controlplane 1/1 Running 0 3d17h
kube-apiserver-controlplane 1/1 Running 2 3d17h
kube-controller-manager-controlplane 1/1 Running 3 3d17h
kube-proxy-d454k 1/1 Running 0 3d17h
kube-proxy-vk72j 1/1 Running 0 3d17h
kube-scheduler-controlplane 1/1 Running 3 3d17h
이 파드들은 kubelet에 의해 강제로 올라간 파드로 static pod라고 불린다. /etc/kubernetes/manifests/ 에 가면 다양한 yaml 파일이 있는데 파드에 대한 yaml 파일이다.
$ ls /etc/kubernetes/manifests/
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
스태택 파드는 단순히 파일만 있으면 자동으로 구성되기 때문에 apply는 안해도된다. nginx yaml 파일을 하나 생성해보고 관찰해보자.
cat <<EOF > /etc/kubernetes/manifests/nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-static
namespace: kube-system # 여기에 원하는 네임스페이스를 입력
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF
파드를 확인하면 다음과 같이 올라와 있다.
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-58dbc876ff-g58tn 1/1 Running 2 3d17h
canal-gjbhw 2/2 Running 0 46m
canal-vmxzc 2/2 Running 0 46m
coredns-584f54878-dmj2q 1/1 Running 0 3d17h
coredns-584f54878-ftz24 1/1 Running 0 3d17h
etcd-controlplane 1/1 Running 0 3d17h
kube-apiserver-controlplane 1/1 Running 2 3d17h
kube-controller-manager-controlplane 1/1 Running 3 3d17h
kube-proxy-d454k 1/1 Running 0 3d17h
kube-proxy-vk72j 1/1 Running 0 3d17h
kube-scheduler-controlplane 1/1 Running 3 3d17h
nginx-static-controlplane 1/1 Running 0 26s
서비스
노드 포트 구성하기
gasbugs/http-go:v2.0 이미지를 사용해 디플로이먼트를 구성하고 이것을 외부로 노출시키는 노드포트 서비스를 구성하자.
kubectl delete all --all # 모든 자원 삭제
cat <<EOF > http-go-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: http-go
spec:
replicas: 3
selector:
matchLabels:
app: http-go
template:
metadata:
labels:
app: http-go
spec:
containers:
- name: http-go
image: gasbugs/http-go:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: http-go
spec:
type: NodePort # 노드에 포트를 오픈
selector:
app: http-go
ports:
- protocol: TCP
port: 80 # 서비스할 포트
targetPort: 8080 # 컨테이너 포트
EOF
kubectl apply -f http-go-deploy.yaml
파드와 서비스가 잘 동작하는지 확인한다.
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
http-go-7c5c7bb8fc-76q7n 1/1 Running 0 2s
http-go-7c5c7bb8fc-kfff9 1/1 Running 0 30s
http-go-7c5c7bb8fc-wqfcd 1/1 Running 0 51s
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-go NodePort 10.96.96.209 <none> 80:31918/TCP 37s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d18h
노드 포트를 테스트해보자.
curl 127.0.0.1:31918
클러스터 IP를 테스트해보자. 내부용 IP이기 때문에 파드를 사용해서 요청해야 한다.
kubectl exec http-go-7c5c7bb8fc-76q7n -- curl 10.96.96.209
kubectl exec http-go-7c5c7bb8fc-76q7n -- curl http-go.default # 서비스이름.네임스페이스이름
쿠버네티스 통신 방식 이해
인증서 및 키 위치 확인
쿠버네티스의 컴포넌트는 인증서를 사용해 통신을 수행한다.
$ ls /etc/kubernetes/pki/
apiserver-etcd-client.crt apiserver-kubelet-client.key ca.crt front-proxy-ca.crt front-proxy-client.key
apiserver-etcd-client.key apiserver.crt ca.key front-proxy-ca.key sa.key
apiserver-kubelet-client.crt apiserver.key etcd front-proxy-client.crt sa.pub
$ ls /var/lib/kubelet/pki/
kubelet-client-2022-09-21-12-48-29.pem kubelet-client-current.pem kubelet.crt kubelet.key
$ cat ~/.kube/config # kubectl 명령을 쓰는 유저가 사용하는것
유저 만들기
openssl 명령을 사용하면 개인 키와 공개 키를 구성할 수 있으며 개인 정보를 더해 인증기관 요청을 수행할 수 있다.
openssl genrsa -out gasbugs.key 2048 # 개인키 만들기
openssl req -new -key gasbugs.key -out gasbugs.csr -subj "/CN=gasbugs/O=boanproject" # 공개키를 구성해 CSR(인증서 싸인 요청)을 구성, gasbugs 유저는 boanproject라는 그룹에 속함
# 인증기관은 CSR을 받아서 싸인을 수행한다. 그러면 crt 생성된다.
openssl x509 -req -in gasbugs.csr -CA /etc/kubernetes/pki/ca.crt \\
-CAkey /etc/kubernetes/pki/ca.key \\
-CAcreateserial -out gasbugs.crt -days 365 # 인증서 1년짜리
유저가 잘 생성되었는지 확인
$ ls gas*
gasbugs.crt gasbugs.csr gasbugs.key
kubectl에 crt와 key를 등록하면 사용가능하다.
# 유저를 등록
kubectl config set-credentials gasbugs --client-certificate=gasbugs.crt \\
--client-key=gasbugs.key
# 유저의 정보와 클러스터 정보를 결합해 컨텍스트를 생성 # user@cluster
kubectl config set-context gasbugs@kubernetes --cluster=kubernetes \\
--namespace=office \\
--user=gasbugs
# 현재 사용하는 컨텍스트 변경
kubectl config use-context gasbugs@kubernetes
# 파드 조회
kubectl get pod
오류가 보이면 성공한 것이다. Forbidden은 권한이 없다는 의미로 로그인에는 성공한 것이다.
Error from server (Forbidden): pods is forbidden: User "gasbugs" cannot list resource "pods" in API group "" in the namespace "office"
RBAC를 활용해 권한 부여하기
https://kubernetes.io/docs/reference/access-authn-authz/rbac/
gasbugs에게 파드 조회 권한을 부여하려면 롤과 롤바인딩을 구성해야 한다.
- 롤: 역할에 어떤 권한을 부여할지 정함
- 롤바인딩: 유저를 어떤 롤과 연결하지 정함
관리자 권한으로 돌아와서 다음 명령을 실행한다.
kubectl config use-context kubernetes-admin@kubernetes # 관리자 권한으로 변경
kubectl create ns office # 네임스페이스 생성
cat <<EOF > pod-reader-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: office
name: pod-reader
rules:
- apiGroups: [""] # core 그룹은 ""와 같이 생략 가능
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: office
subjects: # 누구에게?
- kind: User
name: gasbugs
apiGroup: rbac.authorization.k8s.io
roleRef: # 어떤 권한을?
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
EOF
kubectl apply -f pod-reader-rbac.yaml
다시 한 번 gasbugs의 권한으로 get 파드를 실행해보자.
# office 네임스페이스에서는 조회가 잘 된다.
$ kubectl get pod --context=gasbugs@kubernetes
No resources found in office namespace.
# default 네임스페이스는 조회가 안된다.
$ kubectl get pod --context=gasbugs@kubernetes -n default
Error from server (Forbidden): pods is forbidden: User "gasbugs" cannot list resource "pods" in API group "" in the namespace "default"
api 레퍼런스
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24
시큐리티컨텍스트를 활용한 권한 축소
다음과 같이 securityContext 를 설정하면 root 권한이 아니라 일반 유저 권한이 할당된다.
cat <<EOF > security-context-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox:1.28
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
EOF
kubectl apply -f security-context-demo.yaml
쉘로 접근해서 유저 권한을 확인한다.
kubectl exec -it security-context-demo -- sh
권한 축소되어 sh 권한을 취득한다 하더라도 상당히 축소된 기능만을 수행할 수 있다.
$ kubectl exec -it security-context-demo -- sh
/ $ id
uid=1000 gid=3000 groups=2000
/ $ echo 1234 > test.txt
sh: can't create test.txt: Permission denied
/ $ echo 1234 > /data/demo/test.txt
/ $ exit
CIS 벤치마크 점검
trivy와 같은 회사인 아쿠아시큐리티 개발함
cd ~
rm -rf kube-bench
rm -rf /usr/bin/kube-bench
# 릴리즈 파일 다운로드
wget <https://github.com/aquasecurity/kube-bench/releases/download/v0.6.3/kube-bench_0.6.3_linux_amd64.tar.gz>
tar -xf kube-bench_0.6.3_linux_amd64.tar.gz
sudo mv kube-bench /usr/bin/
# 깃헙 프로젝트 다운로드
git clone <https://github.com/aquasecurity/kube-bench>
cd kube-bench
kube-bench --config-dir `pwd`/cfg --config `pwd`/cfg/config.yaml
'Ubuntu' 카테고리의 다른 글
[Ubuntu] 쿠버네티스 설치 및 기초 (3일차) (0) | 2022.09.27 |
---|---|
[Ubuntu] 도커 컨테이너 개발과 저장소 활용 (2일차) (0) | 2022.09.26 |
[Ubuntu] 우분투 가상 머신 접속과 도커 설치 (1일차) (0) | 2022.09.19 |
댓글