Rolling Updates and Rollbacks
Rollout Command
rollout 상태 확인
kubectl rollout status deployment/[deployment-name]
rollout 이력 조회
kubectl rollout history deployment/[deployment-name]
Deployment Strategy
- Recreate Strategy
이미 존재하는 인스턴스가 5개라면 5개의 구버전 인스턴스를 모두 중단 및 제거하고 새버전 인스턴스를 5개 생성하는 방식으로, 구버전 인스턴스가 모두 제거되고 새버전 인스턴스가 모두 생성되는 사이에 서비스 중단이 발생한다.
- Rolling Strategy(default)
구버전 인스턴스를 하나씩 중단하면서 새버전 인스턴스를 하나씩 실행시키는 방식으로, 한번에 구버전 인스턴스를 모두 중단시키지 않는다. 때문에 구버전과 새버전 인스턴스가 동시에 존재할 수 있다. 이 경우에는 서비스가 중단되지 않는다. 배포시 전략을 지정하지 않으면 기본적으로 롤링 전략을 수행한다.
Upgrade
- Deployment 업그레이드뿐만 아니라 사용한 도커 컨테이너 버전, ReplicaSet 등을 모두 포함
- Deployment 수정시 YAML 파일을 수정한 후 `apply -f `커맨드를 통해 적용할 수 있다.
- 컨테이너 이미지 변경시 `set image` 커맨드를 사용할 수 있다. 하지만 이 방식의 경우 manifest 파일의 구성이 달라질 수 있어, 하나의 manifest 파일을 통해 지속적으로 관리할 예정이라면 유의하는 것이 좋다.
kubectl apply -f deployment-definition.yaml
kubectl set image deployment/[deployment-name] [container-name]=[image-name]
# example
kubectl set image deploy/deployment-definition.yaml nginx-container=nginx:1.9.1
Rollout undo(Rollback)
- `--to-revision` 옵션이 없으면 가장 직전의 버전으로 돌아가고, 옵션이 있으면 특정 버전으로 돌아갈 수 있다.
kubectl rollout history deployment/[deployment-name]
kubectl rollout undo deployment/[deployment-name]
# specify revision
kubectl rollout undo deployment/[deployment-name] --to-revision=[version]
- 쿠버네티스는 롤아웃시 변경 사항을 취소하고 싶으면 이전 리비전으로 돌아갈 수 있도록 지원해준다.
#deployment-definition.yaml
...
spec:
containers:
- name: [container-name1]
image: [edit here!]
...
Configure Application
Command and Args
도커 이미지는 각 이미지마다 실행하는 기본 커맨드가 존재한다. 쿠버네티스에서는 YAML 파일에 command에 String array 형태로 커맨드(인자도 전달할 경우 구분해서 배열의 요소 형태로 전달 - EX. ['command', 'args1'])를 작성할 수 있다. 이렇게 command를 작성할 경우 도커 이미지의 기본 실행 커맨드를 덮어쓴다.
Docker | Kubernetes |
ENTRYPOINT | command |
CMD | args |
Ex)
in Docker file
FROM alpine:latest
COPY "executable_file" /
ENTRYPOINT [ "./executable_file" ]
in Kubernetes
spec:
containers:
- name: container_name
image: image_name
args: ["arg1", "arg2", "arg3"]
# 아래와 같이 array 형태로 작성시 ' 또는 "로 감싸주지 않아도 된다.
# args:
# - arg1
# - arg2
환경 변수 구성하기
`spec.containers[*].env` 사용(key:value 형태)
env:
- name:
value:
ConfigMap을 사용하는 경우
ConfigMap의 전체 데이터를 이용하는 경우(`envFrom.configMapRef` 사용)
envFrom:
- configMapRef:
name: [configmap-name]
ConfigMap의 특정 키 값만 이용하는 경우(`env[*].valueFrom.configMapKeyRef` 사용)
env:
- name:
valueFrom:
configMapKeyRef:
name: [configmap-name]
key: [key-name]
볼륨으로 사용하는 경우(`volumes[*].configMap` 사용)
volumes:
- name: [volume-name ex) app-config-volume]
configMap:
name: [configmap-name]
Secret을 사용하는 경우
Secret의 전체 데이터를 이용하는 경우(`envFrom[*].secretRef` 사용)
envFrom:
- secretRef:
name: [secret-name]
Secret의 특정 키 값만 이용하는 경우(`env[*].valueFrom.secretKeyRef` 사용)
env:
- name:
valueFrom:
secretKeyRef:
name: [secret-name]
key: [key-name]
볼륨으로 사용하는 경우(`volumes[*].secret` 사용)
volumes:
- name: [volume-name ex) app-config-volume]
secret:
name: [secret-name]
ConfigMap 구성하기
Imperative(명령형)
여러 쌍의 데이터를 정의할 때는 `--from-[source-type]=[key]=[value]` 추가
- source-type: `literal`, `file` 등
Cf. 줄바꿈: 리눅스 쉘에서는 `\`를 통해 명령어를 줄바꿈 후 이어서 작성할 수 있게 해준다. 이어지는 명령어는 반드시 `\` 바로 뒤에 이어서 작성해주어야 한다.
kubectl create configmap \
# literal value
app-config --from-literal=[key]=[value]
# file
app-config --from-file=[file-path]
Declarative(선언형)
apiVersion: v1
kind: ConfigMap
metadata:
data:
[key1]: [value1]
[key2]: [value2]
...
`spec` 대신 `data` 필드 존재
Cf. ConfigMap 조회
kubectl describe configmaps
kubectl get configmaps
Secrets 구성하기
Secret은 인코딩된 상태로 저장된다는 점을 제외하고는 ConfigMap가 유사하다. (Pod에 적용하는 방법은 환경 변수 구성하기 참고)
Imperative
kubectl create secret generic \
# literal
[secret-name] --from-literal=[key1]=[value1]
# file
[secret-name] --from-file=[file-path]
Declarative
파일 구성 양식(ConfigMap과 흡사하나, 데이터의 값을 인코딩해서 작성)
apiVersion: v1
kind: Secret
metadata:
name: [secret-name]
data:
[key1]:[value1]
[key2]:[value2]
...
데이터 값 인코딩 방법(뒤에` | base64`가 붙어야 함) - 출력된 값을 복사해서 작성할 것
Cf. `-n` 옵션은 없어도 됨
echo -n '[text]' | base64
Cf. 디코딩 방법
echo -n '[encoding-value]' | base64 --decode
# or
kubectl create -f
Cf. Secret 주의 사항
- 인코딩될 뿐, 암호화되지 않는다. 때문에 GitHub 등에 코드와 함께 올리지 않아야 한다.
- ETCD 내부의 Secret 역시 암호화되지 않는다. 따라서 암호화 설정을 별도로 해야 한다.
- 이를 위해 반드시 EncryptionConfiguration 라는 오브젝트를 생성해야 한다.
- 참고) https://cwal.tistory.com/47
- Secret을 한번 생성하면 같은 NameSpace에 Pod/Deployment를 생성할 수 있는 사람 역시 해당 Secret에 접근할 수 있게 된다.
- 이를 위해 역할 기반 액세스 제어(RBAC)를 구성하는 것을 고려해야 한다. (최소한의 권한 설정)
- 서드파티 암호 공급자를 고려해야한다.
- AWS, Azure, CGP, Vault 등의 공급자를 통해 Secret이 Etcd가 아닌 외부 비밀 공급자에 저장되고 공급자가 보안의 대부분을 처리하도록 하는 것이 좋다.
Demo: Encrypting Secret Data at Rest
- Single Node Kubenetes 환경을 전제로 실습한 내용이다.
- etcd-client 설치(없는 경우에 한함) - etcdctl 커맨드의 실행 여부로 확인 가능
apt-get install etcd-client
- EncryptionConfiguration 오브젝트 생성
- `resources[*].providers[*]` 하위의 전체 provider들은 명시한 key를 기반으로 decrypt 하는데 사용된다. 그 중 최상단에 provider는 암호화(encrypt)에 사용된다.
- `resources[*].providers[*].identity`: decryption된 데이터를 plain text로 읽기 위해선 항상 존재해야한다. 다만 첫 번째 공급자로 둘 경우 암호화되지 않으니 주의할 것(`resources[*].providers[*]`를 구성하지 않으면 identity가 기본값이다.)
apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: # 이 암호화 방식을 사용할 리소스 배열 - secrets - configmaps providers: - identity: {} - aesgcm: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA==
- api-server 파드에 EncryptionConfiguration 관련 설정 추가 작성(api-server는 Static Pod로 파일 내용 수정시 auto restart)
- `crictl pods`: crictl을 통해 파드들의 상태 확인 가능(api-server가 재동작되는 등의 상황에 kubectl을 통해 확인할 수 없을 때 사용 가능)
- EncryptionConfiguration 설정을 완료하면 이전에 생선된 Secret들의 내용은 암호화되지 않은 채 존재하기 때문에 모든 Secret을 파일을 통해 같은 내용으로 업데이트 해주는 과정이 필요하다. (이전에 생성한 Secret이 있는 경우에 한함)
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
Multi-Container
EX) Sidecar Pattern: 로깅 작업 등을 위해 기존의 애플리케이션을 호스트하는 컨테이너에 부가적인 컨테이너를 붙이는 디자인 형태
- 기존 파드에 컨테이너 추가(이 때 edit 이나 단순 replace 로는 수정할 수 없다.(동작 중인 파드에 컨테이너를 추가 또는 제거할 수 없음) 따라서 replace --force 를 통해 파드 삭제 후 재생성하는 과정이 필요하다.
- 두 컨테이너가 같은 볼륨을 공유하도록 할 경우(로그 등의 데이터를 위해)
1. 볼륨 정의(해당 볼륨을 공유하는 컨테이너마다 볼륨명을 일치시켜 명시해야 한다.)
spec:
...
volumes:
- emptyDir: {} # volume init
name: volume-log # example
2. 각 컨테이너에 볼륨 마운트(`mountPath`는 각 컨테이너의 어떤 경로에 해당 볼륨을 마운트할지를 명시하는 것으로 다를 수 있다.)
spec:
containers:
- name: container1
image: container1-img
volumeMounts:
- name: volume-log
mountPath: /log # example
- name: container2-img
volumeMounts:
- name: volume-log
mountPath: /log/event-simulator # example
Volume 종류
- `emptyDir`: 파드가 노드에 할당될 때 처음 생성되어 실행되는 동안에만 존재한다. 해당 노드에서 파드가 제거되면 데이터는 모두 사라진다.
volumes:
- name:
emptyDir: [}
- `hostPath`: 호스트 노드의 파일 시스템에 직접 마운트한다. 파드의 제거 유무와 상관없이 유지된다. 보안상의 문제로 가능하면 사용하지 않는 것이 권고된다. (필요한 파일 또는 디렉토리로 범위를 지정하고 ReadOnly로 마운트 하는 것이 권고된다.)
유형
volumes:
- name:
hostPath:
path: #option
type:
값 | 행동 |
빈 문자열 (기본값)은 이전 버전과의 호환성을 위한 것으로, hostPath 볼륨은 마운트 하기 전에 아무런 검사도 수행되지 않는다. | |
DirectoryOrCreate | 만약 주어진 경로에 아무것도 없다면, 필요에 따라 Kubelet이 가지고 있는 동일한 그룹과 소유권, 권한을 0755로 설정한 빈 디렉터리를 생성한다. |
Directory | 주어진 경로에 디렉터리가 있어야 함 |
FileOrCreate | 만약 주어진 경로에 아무것도 없다면, 필요에 따라 Kubelet이 가지고 있는 동일한 그룹과 소유권, 권한을 0644로 설정한 빈 파일을 생성한다. |
File | 주어진 경로에 파일이 있어야 함 |
Socket | 주어진 경로에 UNIX 소캣이 있어야 함 |
CharDevice | 주어진 경로에 문자 디바이스가 있어야 함 |
BlockDevice | 주어진 경로에 블록 디바이스가 있어야 함 |
Cf. 참고(`emptyDir`, `hostPath` 등 Volume 관련)
[k8s] 6. Volume - emptyDir, hostPath, PV/PVC
[k8s] Volume - (emptyDir, hostPath, PV/PVC)
InitContainer
Pod가 처음 생성될 때 실행되며, 애플리케이션을 호스팅하는 실제 컨테이너가 실행되기 전에 프로세스가 완료되어야 한다.
여러 개의 InitContainer를 정의할 수 있으며, 한 번에 하나씩 실행된다. 하나의 InitContainer라도 완료되지 않으면 완료될 때까지 파드를 새로 시작한다.
`spec.initContainers[*]` 필드 하위에 존재(하위 필드들은 `spec.containers[*]`와 유사)
apiVersion:
kind:
metadata:
name:
spec:
containers:
initContainers:
- name:
image:
ports:
- containerPort:
'Kubernetes' 카테고리의 다른 글
k8s) Security - 1. Kubernetes의 Authentication, TLS 구조 (0) | 2024.03.10 |
---|---|
k8s) Cluster Maintenance (0) | 2023.11.17 |
k8s) Scheduling - 5. Scheduler (1) | 2023.11.17 |
k8s) Scheduling - 4. DaemonSet & Static Pod (1) | 2023.11.17 |
k8s) Scheduling - 3. Requirements & Limits (1) | 2023.11.17 |