목차
- 컨피그맵 볼륨을 사용해 컨피그맵 항목을 파일로 노출
- 컨피그맵 생성
- 볼륨 안에 있는 컨피그맵 항목 사용
- Nginx 서버가 마운트한 설정 파일을 사용하는지 확인
- 마운트된 컨피그맵 볼륨 내용 살펴보기
- 볼륨에 특정 컨피그맵 항목 노출
- 디렉터리를 마운트할 때 디렉터리의 기존 파일을 숨기는 것 이해
- 디렉터리 안에 다른 파일을 숨기지 않고 개별 컨피그맵 항목을 파일로 마운트
- 컨피그맵 볼륨 안에 있는 파일 권한 설정
- 애플리케이션 재시작 없이 애플리케이션 설정 업데이트
- 컨피그맵 편집
- 설정을 다시 로드하기 위해 Nginx에 신호 전달
- 파일이 한꺼번에 업데이트되는 원리
- 주의사항
- 컨테이너 불변성을 우회해도 될까?
컨피그맵 볼륨을 사용해 컨피그맵 항목을 파일로 노출
환경변수 또는 명령줄 인자로 설정 옵션을 전달하는 것은 일반적으로 짧은 변숫값에 대해 서 사용됩니다. 앞에서 본 것처럼 컨피그맵은 모든 설정 파일을 포함할 수 있습니다. 이 파일들을 컨테이너에 노출시키려면, 6장에서 언급한 특수 볼륨 유형 중 하나인 컨피그맵 볼륨을 사용할 수 있습니다.
컨피그맵 볼륨은 파일로 컨피그맵의 각 항목을 노출합니다. 컨테이너에서 실행 중인 프로세스는 이 파일 내용을 읽어 각 항목의 값을 얻을 수 있습니다. 이는 대부분 대형 설정 파일들을 컨테이너에 전달하기 위한 방법이지만, 짧은 단일 값 을 전달할 때도 문제없습니다.
컨피그맵 생성
fortuneloop.sh 스크립트를 수정하는 대신 다른 예를 시도해봅시다. fortune 파드의 웹 서 버 컨테이너 안에서 실행되는 Nginx 웹 서버의 환경 설정을 위해 설정 파일을 사용할 것 입니다. Nginx 서버가 클라이언트로 응답을 압축해서 보내려고 한다고 가정해봅시다. 압축을 사용하도록 설정하려면 Nginx 설정 파일에 다음 예제와 같은 내용이 포함돼야 합니다.
server {
listen 80;
server_name www.kubia-example.com;
gzip on; > 일반 텍스트와 XML 파일에 대해 gzip 압축 활성화
gzip_types text/plain application/xml;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
이제 kubectl delete configmap fortune-config 명령으로 기존 fortune-config 컨피그맵을 삭제하고 Nginx 설정 파일을 포함하는 새로운 컨피그맵으로 교체할 수 있습니다. 로컬 디스크에 저장된 파일을 이용해 컨피그맵을 생성해봅시다.
configmap-files라는 새 디렉터리를 생성하고 앞 예제 Nginx 설정 파일을 configmap -files/my-nginx-config.conf 파일로 저장합니다. 컨피그맵에 sleep-interval 항목도 포 함시키려면, 동일한 디렉터리에 sleep-interval이라는 일반 텍스트 파일을 생성하고 25를 저장합니다. 이제 디렉터리 안에 있는 모든 파일을 이용해 컨피그맵을 생성해봅시다.
$ kubectl create configmap fortune-config --from-file=configmap-files
configmap "fortune-config" create
다음 예제는 이 컨피그맵의 YAML 정의를 보여줍니다.
$ kubectl get configmap fortune-config -o yaml
apiVersion: v1
data:
my-nginx-config.conf: | Nginx 설정 파일 내용을 담고 있는 항목
server {
listen 80;
server_name www.kubia-example.com;
gzip on;
gzip_types text/plain application/xml;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
sleep-interval: | sleep-interval 항목
25
kind: ConfigMap
...
두 항목 가운데 첫 번째 줄에서 콜론 뒤 파이프라인(|) 문자는 여러 줄의 문자열이 이어진다는 것을 나타냅니다. 컨피그맵은 두 항목을 포함하며 각 키는 해당 항목을 생성한 파일 이름으로 돼 있습니다. 이제 이 컨피그맵을 파드의 두 컨테이너에서 사용합니다.
볼륨 안에 있는 컨피그맵 항목 사용
컨피그맵의 내용을 가진 볼륨을 생성하는 것은, 컨피그맵 이름으로 참조하는 볼륨을 만들 고 이 볼륨을 컨테이너에 마운트하는 만큼 간단합니다. 이미 볼륨을 생성하고 마운트하는 방 법을 배웠으니 컨피그맵 항목에서 생성된 파일로 볼륨을 초기화하는 방법만 배우면 됩니다.
Nginx는 /etc/nginx/nginx.conf 파일의 설정을 읽습니다. Nginx 이미지는 기본 설정 옵션을 가진 파일을 이미 포함하며, 이 파일이 가진 기본 옵션을 모두 무시하고 싶지는 않다. 다행히 기본 설정 파일은 /etc/nginx/conf.d/ 디렉터리 안에 있는 모든 .conf 파일을 포함하기 때문에 원하는 설정 파일을 해당 디렉터리에 추가하면 됩니다. 그림 7.9에서 달성 하고자 하는 것을 보여줍니다. 파드 정의는 다음 예제에서 볼 수 있습니다(관련 없는 부분은 생략됐지만, 코드 아카이브에서 전체 파일을 찾을 수 있습니다).
apiVersion: v1
kind: Pod
metadata:
name: fortune-configmap-volume
spec:
containers:
- image: nginx:alpine
name: web-server
volumeMounts:
...
- name: config
mountPath: /etc/nginx/conf.d > 컨피그맵 볼륨을 마운트하는 위치
readOnly: true
…
volumes:
...
- name: config
configMap: > 이 볼륨은 fortune-config 컨피그맵을 참조합니다.
name: fortune-config
…
이 파드 정의에는 fortune-config 컨피그맵을 참조하는 볼륨이 포함돼 있습니다. 해당 볼륨을 Nginx에서 사용할 수 있도록/etc/nginx/conf.d 디렉터리로 마운트합니다.
Nginx 서버가 마운트한 설정 파일을 사용하는지 확인
이제 웹 서버는 응답을 압축해서 보내주도록 설정돼 있어야 합니다. 이를 검증하려면 local host:8080 파드의 80번 포트로 전달하도록 연결하고, 다음 예제처럼 curl 명령을 이용해 서버 응답을 확인할 수 있습니다.
$ kubectl port-forward fortune-configmap-volume 8080:80&
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080>80
$ curl -H "Accept-Encoding: gzip" -I localhost:8080
HTTP/1.1 200 OK
tale &
Server: nginx/1.11.1
Date: Thu, 18 Aug 2016 11:52:57 GMT
Content-Type: text/html
Last-Modified: Thu, 18 Aug 2016 11:52:55 GMT
Connection: keep-alive
ETag: W/"57b5a197-37"
Content-Encoding: gzip > 응답이 압축됐음을 나타냄 응답이 압축됐음을 나타냄
마운트된 컨피그맵 볼륨 내용 살펴보기
응답을 통해 원하는 것을 달성했음을 확인할 수 있습니다. 이제/etc/nginx/conf.d 디렉터리에 무엇이 있는지 살펴봅시다.
$ kubectl exec fortune-configmap-volume -c web-server Is /etc/nginx/conf.d
my-nginx-config.conf
sleep-interval
컨피그맵의 두 항목이 모두 디렉터리에 파일로 추가돼 있습니다. sleep-interval 항목은 fortuneloop 컨테이너에서 사용되고 여기에서는 사용되지 않지만, 같이 포함돼 있습니다. 서로 다른 두 개의 컨피그맵을 작성해 하나는 fortuneloop 컨테이너에 사용하고, 나머지 하 나는 web-server 컨테이너에 사용하도록 할 수 있습니다. 그러나 여러 컨피그맵을 동일한 파 드의 컨테이너들을 구성하는 데 사용하는 것은 무언가 잘못된 느낌입니다. 결국 동일한 파드 에 있는 컨테이너들은 컨테이너가 서로 밀접한 관계를 가지고 있어 하나의 유닛으로 설정 돼야 함을 의미합니다.
볼륨에 특정 컨피그맵 항목 노출
다행히 컨피그맵 볼륨을 컨피그맵 항목의 일부만으로 채울 수 있습니다(여기에서는 my-nginx- config.conf 항목만). sleep-interval 항목은 볼륨이 아닌 환경변수로 전달해 fortuneloop 컨테이너에 영향을 주지 않습니다.
컨피그맵 볼륨 안에 파일로 노출될 항목을 정의하려면, 예제 7.16에 표시된 대로 볼륨의 items 속성을 사용합니다.
volumes:
- name: config
configMap:
name: fortune-config
items: > 볼륨에 포함할 항목을 조회해 선택
- key: my-nginx-config.conf > 해당 키 아래에 항목 포함
path: gzip.conf > 항목 값이 지정된 파일에 저장
개별 항목을 지정할 때 항목 키와 함께 각 개별 항목의 파일 이름을 설정하는 것이 필 요합니다. 이전 예제를 이용해 파드를 실행하면 /etc/nginx/conf.d 디렉터리는 gzip.conf 파일만 포함하고, 그 밖에 다른 것은 포함하지 않아 멋지고 깨끗하게 유지됩니다.
디렉터리를 마운트할 때 디렉터리의 기존 파일을 숨기는 것 이해
이 시점에서 논의해야 할 중요한 사항이 있습니다. 이 예제와 이전 예제에서 볼륨을 디렉터리 에 마운트했다. 이는 컨테이너 이미지 자체에 있던 /etc/nginx/conf.d 디렉터리 안에 저 장된 파일을 숨겼음을 의미합니다.
이는 일반적으로 리눅스에서 파일시스템을 비어 있지 않은 디렉터리에 마운트할 때 발 생합니다. 해당 디렉터리는 마운트한 파일시스템에 있는 파일만 포함하고, 원래 있던 파일은 해당 파일시스템이 마운트돼 있는 동안 접근할 수 없게 됩니다.
이번 경우에는 부작용이 크지 않지만, 일반적으로 중요한 파일을 포함하는 /etc 디렉 터리에 볼륨을 마운트한다고 상상해봅시다. /etc 디렉터리에 있어야 하는 모든 원본 파일이 더 이상 존재하지 않기 때문에 전체 컨테이너가 손상될 수 있습니다. 만약 /etc 디렉터리와 같 은 곳에 파일을 추가하는 것이 필요하다면, 이 방법을 사용할 수 없습니다.
디렉터리 안에 다른 파일을 숨기지 않고 개별 컨피그맵 항목을 파일로 마운트
컨피그맵의 항목을 개별 파일로 기존 디렉터리 안에 있는 모든 파일을 숨기지 않고 추가하 는 방법을 궁금해할 것입니다. 전체 볼륨을 마운트하는 대신 volumeMount에 subPath 속성으 로 파일이나 디렉터리 하나를 볼륨에 마운트할 수 있습니다. 그림으로 설명하는 것이 더 쉬울 것입니다.
myconfig.conf 파일을 포함하는 컨피그맵 볼륨을 갖고 있고, 이 파일을 /etc 디렉터 리에 someconfig.conf 파일로 추가하려고 합니다. subpath 속성으로 디렉터리에 있는 다른 파일에 영향을 주지 않고 마운트할 수 있습니다. 관련 있는 파드 정의는 예제 7.17에서 볼 수 있습니다.
spec:
containers:
- image: some/image
volumeMounts:
- name: myvolume
mountPath: /etc/someconfig.conf > 디렉터리가 아닌 파일을 마운트
subpath: myconfig.conf > 전체 볼륨을 마운트하는 대신 myconfig.conf 항목만 마운트
subpath 속성은 모든 종류의 볼륨을 마운트할 때 사용할 수 있습니다. 전체 볼륨을 마운트하는 대신에 일부만을 마운트할 수 있습니다. 하지만 개별 파일을 마운트하는 이 방법은 파일 업데이트와 관련해 상대적으로 큰 결함을 가지고 있습니다. 이어지는 절에서 이를 알아볼 것이 다. 그 전에 먼저 파일 권한에 대해 짧게 이야기하며 컨피그맵 볼륨 초기 상태에 관해 이야 기하는 것으로 이 절을 마무리해봅시다.
컨피그맵 볼륨 안에 있는 파일 권한 설정
기본적으로 컨피그맵 볼륨의 모든 파일 권한은 644(-rw-r-r--)로 설정됩니다. 다음 예제와 같이 볼륨 정의 안에 있는 defaultMode 속성을 설정해 변경할 수 있습니다.
volumes:
- name: config
configMap:
name: fortune-config
defaultMode: "6600" > 모든 파일 권한을 -rw-rw-----로 설정
컨피그맵은 중요하지 않은 설정 데이터에만 사용해야 하지만 이전 예제처럼 파일을 소유한 사용자와 그룹만 파일을 읽고 쓸 수 있도록 만들 수 있습니다.
애플리케이션 재시작 없이 애플리케이션 설정 업데이트
환경변수 또는 명령줄 인수를 설정 소스로 사용할 때의 단점은 프로세스가 실행되고 있는 동안에 업데이트할 수 없다는 것입니다. 컨피그맵을 사용해 볼륨으로 노출하면 파드를 다시 만들거나 컨테이너를 다시 시작할 필요 없이 설정을 업데이트할 수 있습니다.
컨피그맵을 업데이트하면, 이를 참조하는 모든 볼륨의 파일이 업데이트됩니다. 그런 다 음 변경됐음을 감지하고 다시 로드하는 것은 프로세스에 달려 있습니다. 그러나 쿠버네티스는 파일 업데이트 후 컨테이너에 신호를 보내는 것을 지원할 가능성이 높다. 하지만 컨피그맵을 업데이트한 후에 파일이 업데이트되기까지 오랜 시간이 걸릴 수 있습니다(최대 1분까지 걸릴 수 있습니다).
컨피그맵 편집
컨피그맵을 변경하고 파드 안에서 실행 중인 프로세스가 컨피그맵 볼륨에 노출된 파일을 다시 로드하는 방법을 살펴봅시다. 이전 Nginx 설정 파일을 편집해 파드 재시작 없이 Nginx 가 새 설정을 사용하도록 만들자. kubectl edit 명령으로 fortune-config 컨피그맵을 편집해 gzip 압축을 해제해봅시다.
$ kubectl edit configmap fortune-config
편집기가 열리면 gzip on을 gzip off로 변경하고 파일을 저장한 다음 편집기를 닫습니다. 컨피그맵이 업데이트되면 곧 볼륨의 실제 파일도 업데이트됩니다. 파일 내용을 kubectl exec 명령으로 출력해 확인해볼 수 있습니다.
$ kubectl exec fortune-configmap-volume -c web-server
└> cat /etc/nginx/conf.d/my-nginx-config.conf
업데이트된 내용이 보이지 않으면 기다렸다가 다시 시도해봅시다. 파일이 업데이트되려면 시간이 걸립니다. 결국에는 변경된 설정 파일을 볼 수 있지만, Nginx에는 아무런 영향이 없는 것을 알게 될 것입니다. Nginx는 파일의 변경을 감시하지 않으며 자동으로 다시 로드 하지 않기 때문입니다.
설정을 다시 로드하기 위해 Nginx에 신호 전달
Nginx는 설정 파일을 다시 로드하라는 다음 명령을 실행하기 전까지 응답을 계속 압축합니다.
$ kubectl exec fortune-configmap-volume -c web-server-- nginx -s reload
이제 curl 명령어를 이용해 서버에 다시 접속하면, 더 이상 응답이 압축되지 않는 것을 볼 수 있습니다(더 이상 Content-Encoding: gzip 헤더를 포함하지 않습니다). 이렇게 컨테이너를 재시작하거나 파드를 재생성하지 않고도 애플리케이션의 설정을 효과적으로 변경할 수 있습니다.
파일이 한꺼번에 업데이트되는 원리
쿠버네티스가 컨피그맵 볼륨에 있는 모든 파일을 업데이트하기 전에 애플리케이션이 설정 파일의 변경 사항을 자체적으로 감지하고 다시 로드할 경우에 어떻게 되는지 궁금해할 수 있습니다. 다행히도 모든 파일이 한 번에 동시에 업데이트되기 때문에 이런 일이 발생할 수 없습니다. 쿠버네티스는 심볼릭 링크를 사용해 이를 수행합니다. 만약에 마운트된 컨피그맵 볼륨의 모든 파일을 조회하면 다음 예제와 같은 내용을 보게 될 것입니다.
$ kubectl exec -it fortune-configmap-volume -c web-server -- 1s -1A /etc/nginx/conf.d
total 4
drwxr-xr-x ... 12:15 ..4984_09_04_12_15_06.865837643
Irwxrwxrwx... 12:15 ..data->..4984_09_04_12_15_06.865837643ex Lasdud
1rwxrwxrwx ... 12:15 my-nginx-config.conf -> ..data/my-nginx-config.conf
1rwxrwxrwx ... 12:15 sleep-interval -> ..data/sleep-interval
보는 것처럼 마운트된 컨피그맵 볼륨 안의 파일은 .. data 디렉터리의 파일을 가리키는 심볼릭 링크입니다...data 디렉터리 또한..4984_09_04_something 디렉터리를 가리키는 심 볼릭 링크다. 컨피그맵이 업데이트되면 쿠버네티스는 이와 같은 새 디렉터리를 생성하고, 모든 파일을 여기에 쓴 다음..data 심볼릭 링크가 새 디렉터리를 가리키도록 해, 모든 파일을 한 번에 효과적으로 변경합니다.
주의사항
한 가지 주의 사항은 컨피그맵 볼륨 업데이트와 관련이 있습니다. 만약 전체 볼륨 대신 단일 파일을 컨테이너에 마운트한 경우 파일이 업데이트되지 않습니다.
만일 개별 파일을 추가하고 원본 컨피그맵을 업데이트할 때 파일을 업데이트해야 하는 경우 한 가지 해결 방법은 전체 볼륨을 다른 디렉터리에 마운트한 다음 해당 파일을 가리 키는 심볼릭 링크를 생성하는 것입니다. 컨테이너 이미지에서 심볼릭 링크를 만들거나, 컨테 이너를 시작할 때 심볼릭 링크를 만들 수 있습니다.
컨테이너 불변성을 우회해도 될까?
컨테이너의 가장 중요한 기능은 불변성(immutability)입니다. 즉, 동일한 이미지에서 생성된 여러 실행 컨테이너 간에 차이가 없는지 확인할 수 있습니다. 그렇다면 컨테이너를 실행하는 데 사용되는 컨피그맵을 수정해 이 불변성을 우회하는 것이 잘못된 것일까요?
애플리케이션이 설정을 다시 읽는 기능을 지원하지 않는 경우에 심각한 문제가 발생합니다. 이로 인해 서로 다른 설정을 가진 인스턴스가 실행되는 결과를 초래합니다. 컨피그맵을 변경한 이후 생성된 파드는 새로운 설정을 사용하지만 예전 파드는 계속해서 예전 설정을 사용합니다. 그리고 이것은 새로운 파드에만 국한되는 문제가 아닙니다. 파드 컨테이너가 어떠 한 이유로든 다시 시작되면 새로운 프로세스는 새로운 설정을 보게 됩니다. 따라서 애플리케이션이 설정을 자동으로 다시 읽는 기능을 가지고 있지 않다면, 이미 존재하는 컨피그맵을 (파드가 사용되는 동안) 수정하는 것은 좋은 방법이 아닙니다.
애플리케이션이 다시 읽기(reloading)를 지원한다면, 컨피그맵을 수정하는 것은 그리 큰 문제는 아니다. 하지만 컨피그맵 볼륨의 파일이 실행 중인 모든 인스턴스에 걸쳐 동기적으 로 업데이트되지 않기 때문에, 개별 파드의 파일이 최대 1분 동안 동기화되지 않은 상태로 있을 수 있음을 알고 있어야 합니다.
이제 쿠버네티스 내용이 중간 정도 진행되었는데 난이도가 많이 어려워졌습니다. 때문에 궁금하신 점은 댓글을 달아주시면 답변해드리도록 하겠습니다. 끝까지 봐주셔서 감사합니다. :)
'Container > Kubernetes' 카테고리의 다른 글
[Kubernetes] Downward API와 메타데이터(1) (0) | 2023.05.27 |
---|---|
[Kubernetes Secrets] 쿠버네티스 시크릿(Secret)이란? (0) | 2023.04.17 |
[Kubernetes Configmap] 컨피그맵이란? (1) (0) | 2023.04.16 |
[Kubernetes] 2. 도커 컨테이너 환경 변수 설정 (0) | 2023.04.16 |
[Kubernetes] 1. 도커 컨테이너 명령줄(command line) 인자 설정법 (2) | 2023.04.16 |