pod스펙에서 image: nginx
라고 쓰여있다면, 다음과 같이 image 네이밍 부분을 쪼갤 수 있다.
registry | user account | image/repository | tag | |
---|---|---|---|---|
image | docker.io | library | nginx | latest |
docker에서 image이름 앞에 아무것도 없다면 이는 user account가 명시되지 않아 default값인 library
로 설정된다. 따라서 library/nginx
가 되는 것이다.
여기서 맨 앞부분인 registry부분이 생략되어있으므로 default값인 docker.io
가 되는 것이다. 따라서 docker.io/library/nginx
가 된다. 최종적으로 default tag인 latest
와 합쳐져 docker.io/library/nginx:latest
가 된다.
참고로 docker.io/nginx
라고 쓰면 docker.io
가 registry 이름이되고, nignx
가 이미지 이름이 된다. 즉, user account를 생략하는 것이다. user account에 대해서는 많이들 생략한다.
다른 경우 dnsutils
의 경우는 다음의 image이름을 갖게되는 것이다.
gcr.io/kubernetes-e2e-test-images/dnsutils
kubernetes의 경우 대부분의 application image가 private registry인데, docker의 경우 private registry에서 image를 가져오는 경우 다음과 같이 login을 먼저 해야한다. 가령 private-registry.io/apps/internal-app
을 가져온다고 해보자.
docker login private-registry.io
...
Login Succeeded
docker run private-registry.io/apps/internal-app
해당 이미지를 사용하면 pod의 정의는 다음과 같다.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: private-registry.io/apps/internal-app
그런데 kubernetes에서 어떻게 인증하여 credential을 받을 수 있을까??
이를 위해서 private registry에 접근하기 위한 인증 정보를 담은 secret을 만들어야 한다. 각 registry 호스트가 무엇이냐에 따라 secret의 type이 다른데, docker의 경우는 docker-registry
이다. 따라서, 다음과 같다.
kubectl create secret docker-registry regcred \
--docker-server=private-registry.io \
--docker-username=registry-user \
--docker-password=registry-password \
--docker-email=registry-user@org.com
docker-registry
라는 type을 가진 regcred secret을 만든 것이다. 그리고, 해당 secret에 들어가는 정보가 private registry에 대한 인증 정보인 username, password들이 들어간다.
이제 해당 secret정보를 imagePullSecrets
에 넣어주어야 한다.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: private-registry.io/apps/internal-app
imagePullSecrets:
- name: regcred
docker container는 VM처럼 host os와 완전히 분리되어있지 않다. host os와 커널을 같이 쓰고, 일부 네트워크, 파일 시스템 볼륨들을 공유할 수 있다.
container는 host와 분리된 namespace에서 process를 구동하는데, 기본 USER
자체가 root
이다. 따라서 다음과 같이, container안에서 ps aux
명령어를 실행하면 USER의 PID가 1이다.
ps aux
USER PID ...
root 1 ...
root
user로 실행하게되면 container에 원치 않은 권한들을 줄 수 있고, 이를 통해 host의 일부 기능들을 컨트롤 할 수 있다. 따라서, 다음과 같이 USER
를 dockerfile이나 cli로 넘겨주어 root
권한을 주지 못하도록 하는 것이 보안에 좋다.
docker run --user=1000 ubuntu sleep 3600
다음과 같이 dockerfile에 USER
를 쓸 수도 있다.
FROM ubuntu
USER 1000
그런데 container는 정말 host의 root유저처럼 동작하는 것인가?? root user처럼 root에 있는 파일들을 지울 수 있고, 네트워크 설정들을 바꿀 수 있는가? 그렇지않다. root로 container를 실행시키면, 일부 capability를 제공하지 않은 채로 container를 동작시키는데, 이는 root user의 일부 권한을 부여하지 않은 것이다. 따라서, host의 root user처럼 동작하지 않는 것이다.
만약 필요하다면 docker container를 실행할 때 --cap-add
옵션을 붙이면 된다.
docker run --cap-add MAC_ADMIN ubuntu
이러한 container security 기능을 다음과 같이, kubernetes resource로 제공해줄 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
securityContext:
runAsUser: 1000
containers:
- name: ubuntu
image: ubuntu
command: ["sleep", "3600"]
위와 같이 pod단위로 user option을 제공할 수도 있고, 다음과 같이 각 container마다의 user option과 capability기능을 추가할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- name: ubuntu
image: ubuntu
command: ["sleep", "3600"]
securityContext:
runAsUser: 1000
capabilities:
add: ["MAC_ADMIN"]
다음과 같이 pod와 container 둘 다 securityContext
를 쓸 수도 있다.
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
spec:
securityContext:
runAsUser: 1001
containers:
- image: ubuntu
name: web
command: ["sleep", "5000"]
securityContext:
runAsUser: 1002
- image: ubuntu
name: sidecar
command: ["sleep", "5000"]
web
는 1002이고, sidecar
는 1001 user id를 가지게 된다.