kubernetes 에서 ceph rbd provisioner 활용 방법입니다.
kubernetes 에서 ceph rbd provisioner 활용 방법입니다.
처음에는 대충 볼려고 했는데 내용이 좋아서 끝까지 집중해서 봤네요. 전체 요약해 봤습니다.
AWS re:Invent 2018 - Keynote with Werner Vogels
ASW 유형별 Databases 종류
고객들이 serverless 로 가려고 하는가?
Firecracker (New): serverless computing을 위한 안전하고 빠른 microVMs
이번에는 docker 이미지 최적화에 대해서 설명하겠습니다.
이미지 최적화를 위해서는 다음의 3가지를 잘 활용하면 됩니다.
1. 레이어를 줄이기 위해서 다중 RUN 명령어는 하나의 RUN 명령어로 구성
2. 파일 복사와 라이브러리 Install 은 순서가 중요
3. 컴파일과 같은 작업은 Multistep build 를 이용
alpine linux 로 nginx 를 실행시기 위한 방법으로 다음과 같은 docker 이미지를 만들 수 있습니다.
먼저, nginx.conf 파일을 로컬 컴퓨터에 생성합니다.
$ vi nginx.conf
user www;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
access_log /var/log/nginx/access.log;
keepalive_timeout 3000;
server {
listen 80;
root /www;
index index.html index.htm;
server_name localhost;
client_max_body_size 32m;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}
}
}
다음은 간단한 index.html 입니다.
$ vi index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5</title>
</head>
<body>
Server is online
</body>
</html>
이 두 파일을 활용한 Dockerfile 은 다음과 같습니다.
$ vi Dockerfile
FROM alpine:3.8
RUN apk update
RUN apk add --no-cache nginx
RUN adduser -D -g 'www' www
RUN mkdir /www
RUN chown -R www:www /var/lib/nginx
RUN chown -R www:www /www
COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /www/index.html
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
docker 이미지를 빌드하고 실행시키면 index.html 결과를 얻을 수 있습니다.
$ sudo docker build -t seungkyua/nginx-alpine .
$ docker run -d -p 30080:80 --name nginx-alpine seungkyua/nginx-alpine
$ curl http://localhost:30080
여기서 첫번째 이미지 최적화 포인트가 보입니다.
앞의 Dockerfile 에서 하나의 RUN 은 하나의 이미지 레이어가 되므로 이것을 하나로 다음과 같이 줄일 수 있습니다.
RUN apk update && \
apk add --no-cache nginx && \
adduser -D -g 'www' www && \
mkdir /www && \
chown -R www:www /var/lib/nginx && \
chown -R www:www /www
이번에는 nodejs docker 이미지를 만들어 보겠습니다.
$ package.json
{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"private": true,
"author": "Seungkyu Ahn <seungkyua@gmail.com>",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.16.1"
}
}
$ vi server.js
'use strict';
const express = require('express');
const PORT = 8080;
const HOST = '0.0.0.0';
const app = express();
app.get('/', (req, res) => {
res.send('Hello world\n');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
$ vi Dockerfile
FROM node:8
RUN mkdir -p /app
COPY package*.json /app/
WORKDIR /app
COPY . /app
RUN npm install --only=production
EXPOSE 8080
CMD [ "npm", "start" ]
위의 Dockerfile 의 경우 현재 디렉토리 소스를 COPY 한 후에 npm install 을 수행합니다.
docker 이미지는 변경된 레이어만 build 되지만 연관된 하위 레이어까지 build 됩니다.
여기서는 현재 디렉토리 소스가 변경되면 npm install 을 매번 다시 수행합니다.
그러므로 일단 package 설치를 먼저하고 COPY 를 나중에 하면 package 설치 내용이 변경되지 않는다면 npm install 은 캐시를 바로 사용하여 설치하지 않습니다.
RUN npm install --only=production
COPY . /app
마지막으로, 컴파일 하는 소스의 docker 이미지를 살펴보겠습니다.
$ vi hello.c
#include <stdio.h>
int main () {
printf ("Hello, world!\n");
return 0;
}
$ vi Dockerfile
FROM alpine:3.8
RUN apk update && \
apk add --update alpine-sdk
RUN mkdir -p /app
COPY . /tmp
WORKDIR /tmp
RUN gcc hello.c -o hello
ENTRYPOINT ["/tmp/hello"]
위의 경우에 c 컴파일을 하기 위해 c 컴파일로가 들어있는 sdk 패키지를 설치하고 바이너리 파일로 컴파일을 하므로 이미지 사이즈가 커집니다.
여기서 build 단계를 활용하면 sdk 패키지는 제외하고 최종 바이너리 파일만 docker 이미지에 넣을 수 있습니다.
$ vi Dockerfile
FROM alpine:3.8 AS build
RUN apk update && \
apk add --update alpine-sdk
RUN mkdir -p /app
COPY . /tmp
WORKDIR /tmp
RUN gcc hello.c -o hello
FROM alpine:3.8
COPY --from=build /tmp/hello /app/hello
ENTRYPOINT ["/app/hello"]
아래 이미지 사이즈는 build 스텝을 활용하지 않은 파일 사이즈와 활용한 사이즈의 차이입니다.
seungkyua/c-hello-world 176MB
seungkyua/c-hello-world 4.42MB
docker 이미지가 어떻게 구성되는지 이해하기 위해서는 Copy-on-write 정책을 이해해야 합니다.
아래와 같은 Dockerfile 이 있고 이를 이미지로 만들었을 때 이미지가 차지하는 스토리지 구성은 다음과 같습니다.
(아래 Dockerfile 은 sample 파일로 make tool 까지 있다고 가정합니다.)
FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py
이미지 출처: https://docs.docker.com/v17.09/engine/userguide/storagedriver/images/container-layers.jpg
가장 아래 레이어 d3a1f33e8a5a 는 ubuntu:15.04 이미지 입니다.
그 다음 바로 위의 c22013c84729 는 현재 디렉토리의 이하의 모든 소스를 /app 디렉토리 아래 복사한 이미지 레이어입니다. (COPY . /app 명령에 의한)
d74508fb6632 는 RUN make /app 가 실행된 이미지 레이어이고, 마지막으로 91e54dfb1179 는 CMD python /app/app.py 이미지 레이어입니다.
Dockerfile 에서 하나의 명령어는 하나의 이미지 레이어 이며, 여기까지 이미지는 Read Only 이미지로 컨테이너가 실행되어도 바꿀 수 없습니다.
위의 Dockerfile 로 만든 이미지로 컨테이너가 실행되면 제일 상단의 Container Layer 로 Thin Read/Write 스토리지가 생기며, 여기에만 데이터 쓰기가 가능합니다.
같은 이미지로 컨테이너 인스턴스를 여러 개 실행시켜도 이미지는 공유하며 Container Layer 만 각 인스턴스별로 생겨 자신의 쓰기 스토리지가 생기는 구조이며, 기본적으로 컨테이너가 실행되면서 생긴 스토리지는 실행된 컨테이너가 삭제될 때 같이 삭제됩니다.
위의 Dockerfile 에서 두번째 라인이 현재 디렉토리를 /app 아래로 복사는 명령어에서 현재 디렉토리에 있는 파일이 변경되었다고 가정해 봅시다.
다시 이미지를 만들 경우 맨아래 d74508fb6632 이미지 레이어는 링크로 그대로 활용되고, c22013c84729 이미지 레이어를 먼저 복사하고(copy), 수정된 파일들을 /app 디렉토리 아래로 복사하는(write) 부분이 일어나며 그 이후의 이미지 레이어들은 계속 실행됩니다.
Dockerfile 을 작성할 때 기본 예약 명령어는 다음과 같습니다.
FROM nginx:alpine
nginx 이미지의 alpine 태그를 Base 이미지로 사용합니다.
RUN mkdir -p /app
mkdir -p /app 명령을 실행합니다. shell 명령어를 쓸 때 사용합니다.
ADD source.tar /app/
source.tar 를 /app 디렉토리 아래에 풉니다.
ADD http://ahnseungkyu.com/release /data/
인터넷의 http://ahnseungkyu.com/release 파일을 /data 디렉토리 아래에 다운받습니다.
COPY . /app
현재 디렉토리의 모든 파일과 하위 디렉토리를 /app 디렉토리 아래로 복사합니다.
COPY ./conf /app/conf
conf 디렉토리 아래의 모든 파일과 하위 디렉토리를 /app/conf 디렉토리 아래로 복사합니다.
COPY ./*.js /app/
현재 디렉토리으 모든 js 파일을 /app 디렉토리 아래로 복사합니다.
추가로 Dockerfile 을 작성할 때 가장 기본이 되는 CMD 와 ENTRYPOINT 의 차이에 대해서 알아보겠습니다.
Dockerifle 에서는 기본적으로 최소 하나의 CMD 혹은 ENTRYPOINT 가 있어야 하며, 둘 다 있을 수 도 있습니다.
즉, docker 를 실행할 때 CMD 로 호출하거나 ENTRYPOINT 로 호출 할 수 있습니다.
아래 alpine ping Dockerfile 을 예로 살펴보겠습니다.
From alpine:latest
RUN apk update && apk add --update iputils \
&& rm -rf /var/cache/apk/*
CMD ["ping", "-c", "3", "8.8.8.8"]
여기서는 CMD 를 사용하여 ping -c 3 8.8.8.8 명령어를 실행했습니다.
docker 이미지를 만들고 실행해보면 결과가 잘 나옵니다.
$ sudo docker build -t seungkyua/alpine-sample .
$ sudo docker run --name alipine-sample --rm -it seungkyua/alpine-sample
이것을 ENTRYPOINT 사용으로 바꾸면 다음과 같습니다.
From alpine:latest
RUN apk update && apk add --update iputils \
&& rm -rf /var/cache/apk/*
ENTRYPOINT ["ping", "-c", "3", "8.8.8.8"]
똑같이 결과가 나타납니다.
그럼 이 둘의 차이는 무엇일까요? 그건 둘 다 사용했을 때 알 수 있습니다. 다음과 같이 바꿔보겠습니다.
From alpine:latest
RUN apk update && apk add --update iputils \
&& rm -rf /var/cache/apk/*
ENTRYPOINT ["ping"]
CMD ["-c", "3", "8.8.8.8"]
결과가 똑같습니다. 하지만 여기서 아래와 같이 docker 를 실행할 때 8.8.8.8 을 맨 뒤에 추가하면 결과가 달라집니다.
$ sudo docker run --name alipine-sample --rm -it seungkyua/alpine-sample 8.8.8.8
마지막의 CMD 부분이 argument 로 처리 되는데 8.8.8.8 이라는 argument 가 override 되어 -c 3 8.8.8.8 부분이 8.8.8.8 로 되어 버립니다.
결과적으로 ENTRYPOINT 와 CMD 를 함께 쓰는 경우는 CMD argument 를 override 하고 싶을 때 사용할 수 있기 때문에 가능하면 둘 다 사용하는 방법을 추천드립니다.
PID namespace 외에 Network namespace 를 알아보겠습니다.
처음 글을 시작한 의도는 docker 를 잘 활용하자는 의미였는데 하다보니 아직 그 내용은 들어가 보지도 못했네요.
개발자나 운영자들은 잘 인식하지 못하지만 linux 의 Network 는 모두 namespace 구조하에 움직이고 있습니다.
기본적으로 host 기반으로 사용하는 network 의 namespace 는 1 입니다. 그리고 docker 가 실행되면 docker process 에 대해서 내부적인 network 를 사용합니다.
network namespace 와 network namespace 간의 연결은 virtual ethernet (veth) 를 사용하여 연결합니다. 즉, veth pair 를 만들어서 하나는 docker 내부에 다른 하나는 host 로 하여 서로 네트워크로 연결하고 host 에 있는 veth 는 host 의 bridge 로 연결하면 docker 내부에서 host 의 bridge 로 연결이 됩니다.
docker 컨테이너 (eth0) <-> host veth <-> host bridge (docker0) <-> host network (ens2f0)
먼저, host veth 의 리스트를 보겠습니다.
$ sudo ip addr show
15479: vethf5fa5c1@if15478: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 32:83:61:96:55:4a brd ff:ff:ff:ff:ff:ff link-netnsid 1
15481: veth4667f7d@if15480: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 56:39:6e:41:3d:50 brd ff:ff:ff:ff:ff:ff link-netnsid 0
15483: vethd61c546@if15482: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether b2:4a:88:71:d0:03 brd ff:ff:ff:ff:ff:ff link-netnsid 2
15489: vethbe5dd5b@if15488: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP
link/ether fe:85:37:ac:ea:76 brd ff:ff:ff:ff:ff:ff link-netnsid 4
15493: veth66998b7@if15492: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 42:5f:03:92:45:9d brd ff:ff:ff:ff:ff:ff link-netnsid 5
총 5개가 보이는데 이중 하나는 docker gateway bridge 로 연결되고 나머지 4개는 1:1 로 각각 docker 내부의 eth0 와 연결되어 있습니다.
이를 좀 쉽게 찾기 위해서 veth.sh 파일을 만들었습니다.
#!/bin/bash
VETHS=`ifconfig -a | grep veth | sed 's/ .*//g'`
DOCKERS=$(docker ps -a | grep Up | awk '{print $1}')
for VETH in $VETHS
do
PEER_IFINDEX=`ethtool -S $VETH 2>/dev/null | grep peer_ifindex | sed 's/ *peer_ifindex: *//g'`
for DOCKER in $DOCKERS
do
PEER_IF=`docker exec $DOCKER ip link list 2>/dev/null | grep "^$PEER_IFINDEX:" | awk '{print $2}' | sed 's/:.*//g'`
if [ -z "$PEER_IF" ]; then
continue
else
printf "%-10s is paired with %-10s on %-20s\n" $VETH $PEER_IF $DOCKER
break
fi
done
done
위 파일을 실행하면 아래와 같이 나옵니다.
veth4667f7d: is paired with eth0@if15481 on b75a945f84fa
veth66998b7: is paired with eth0@if15493 on 67246d3e1c68
vethd61c546: is paired with eth0@if15483 on 87faa6bacbba
vethf5fa5c1: is paired with eth0@if15479 on 0b4bc5ba78f9
마지막에 보이는 것은 docker id 입니다.
host 의 docker0 bridge 가 어떻게 연결되어 있는 지는 brctl 로 알 수 있습니다.
$ sudo yum install -y bridge-utils
$ sudo brctl show
docker0 bridge 가 어떻게 host 의 외부 네트워크로 나가는 지는 iptables 와 routing 을 보면 알 수 있습니다.
$ sudo iptables -t nat -S
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
source 가 docker 내부 ip 대역이고 host 입장에서 패킷이 나가는 인터페이스가 docker0 가 아니면 jump 를 하고 host의 ip 로 변경해서 (masquerade) 나가라고 되어 있습니다.
$ netstat -rn
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.30.1 0.0.0.0 UG 0 0 0 ens2f0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker_gwbridge
그리고 위와 같이 외부로 나갈 때는 default gateway 로 외부로 나가게 됩니다.
컨테이너가 linux 의 cgroup 과 namespace 를 활용하여 동작하는 것은 이제 보편적으로 알려진 내용입니다. cgroup 은 자원의 활용에 사용하고 namespace 는 자원의 isolation 에 사용합니다.
이 중에서 namespace 의 종류는 다음과 같습니다.
ipc : 프로세스간 양방향 통신
mnt : 파일 시스템
net : 네트워크
pid : 프로세스 id
user : 사용자 계정
uts : Unix time sharing
위의 namespace를 기본으로 docker 의 프로세스 구조를 보면 다음과 같습니다.
먼저, pstree 명령어를 설치합니다. 어떤 패키지인지 모르면 아래 명령어로 패키지명을 찾을 수 있습니다.
$ sudo yum whatprovides pstree
psmisc-22.20-15.el7.x86_64 : Utilities for managing processes on your system
Repo : base
Matched from:
Filename : /usr/bin/pstree
$ sudo yum install -y psmisc
이제 pstree 로 docker 의 패키지를 봅니다.
$ pstree -lSps $(pidof dockerd)
() 안에 들어간 번호는 프로세스 id 입니다. dockerd 프로세스는 15472 이고 이후의 프로세스 명이 잘려서 보이니 ps 로 프로세스 명을 보면 다음과 같습니다.
$ ps -ef | grep 15489
15489 는 docker-containerd 입니다.
$ ps -ef | grep 15675
15675 는 docker-container-shim 입니다.
$ ps -ef | grep 15711
그리고 실제 컨테이너로 띄고 있는 minio 프로세스는 15711 입니다.
위의 내용을 보면 docker 프로세스는 다음과 같은 구조로 되어 있습니다.
dockerd (15472, docker 데몬) -> docker-containerd (15489, docker cotainerd) -> docker-container-shim (15675) -> minio (15711, 실행중인 docker 컨테이너)
docker-containerd 는 docker runtime 과 관련 있습니다. 컨테이너 실행은 runc 와 containerd 를 따릅니다. runc 는 Open Container Initiative(OCI) 에 의해 정의된 컨테이너를 실행시키는 부분으로 namespace 와 보안에 관한 표준입니다. containerd 는 runc 를 기반으로 컨테이너 이미지 관리, 스토리지, 실행 등의 기능을 확장한 것으로 CNCF 에 기부된 프로젝트 입니다.
docker-container-shim 은 docker 에서 자체적으로 추가한 것으로, 실행되는 컨테이너와 containerd 사이에서 컨테이너를 연결하여 containerd 가 문제가 생기더라도 실행되는 컨테이너에는 여향을 주지 않기 위해서 만들었습니다. 그런데 사실 이게 왜 더 필요한지는 모르겠습니다. 괜히 관리 레이어만 하나 더 추가된 부분으로 보이긴 합니다.
PID namespace 를 docker 에서 어떻게 적용되는지 보겠습니다.
앞에서 minio 컨테이너는 host 에서 보면 프로세스 id 가 15711 이고 그 부모 프로세스는 15675 인 docker-container-shim 인 것을 확인했습니다.
이제 minio 컨테이너를 아래와 같이 확인 합니다.
$ sudo docker (container) ls | grep minio
0b4bc5ba78f9 minio/minio "minio server /export" 18 months ago Up 4 hours 0.0.0.0:9000->9000/tcp minio
그리고, minio 컨테이너 안으로 들어가 보겠습니다.
$ sudo docker (container) exec -it 0b4bc5ba78f9 sh
프로세스를 조회해보면 다음과 같이 1번 프로세스로 minio 서버를 띄운 것이 보이고 (컨테이너 밖의 host 에서는 15711) 그 위의 부모 프로세스는 보이지 않습니다.
Kubernetes 는 여러 컨테이너를 관리할 수 있습니다. 그 이유는 kubernetes kubelet 과 컨테이너 데몬이 정해진 spec 에 따라 gRPC 통신을 하기 때문입니다. Kubernetes 는 여러 컨테이너를 적용할 수 있는데 rkt, docker, CRI-O 등이 있습니다. 이중에서 가장 많이 사용하는 Docker 에 대해서 설명하고자 합니다.
앞서 kubespray 사용에 대해서 설명이 있는데, 여기를 보면 Production Level 로 사용 가능한 CentOS, RedHat, Ubuntu에 맞게 docker 를 쉽게 설치할 수 있습니다. 여기서는 Docker 를 이미 설치한 후에 어떻게 Docker 를 잘 활용할 수 있는지에 대해서 설명합니다.
대부분의 Linux 는 이제 systemd 를 활용하고 있습니다. 그렇기 때문에 docker 데몬 실행은 systemd 에 설치된 docker.service 를 보면 됩니다. 디렉토리는 둘 중에 하나를 찾아보면 됩니다.
/etc/systemd/system/multi-user.target.wants/docker.service
/etc/systemd/system/docker.service
제 환경은 CentOS 로 이렇게 정의가 되어 있습니다.
MountFlags=shared
EnvironmentFile=-/etc/sysconfig/docker
ExecStart=/usr/bin/dockerd $DOCKER_OPTS
ExecReload=/bin/kill -s HUP $MAINPID
dockerd 의 환경 파일로 /etc/sysconfig/docker 를 읽게 되어 있고 해당 파일은 아래 옵션으로 정의되어 있습니다.
DOCKER_OPTS="--storage-driver=overlay2 --insecure-registry docker-registry:5000 --insecure-registry oreo:5000"
이 경우 systemctl restart docker.service 를 하면 dockerd 가 restart 되는데 문제는 이미 실행되고 있는 docker 컨테이너가 영향을 받아 stop 으로 빠집니다. (kubernetes 의 deployment, daemonset, statefulset 혹은 docker 의 --restart=always 가 아닌 경우) 그러므로, docker 옵션만 reload 해야 기존의 실행되고 있는 컨테이너가 영향을 받지 않습니다.
docker option reload 는 SIGHUP 을 보내면 됩니다.
$ sudo kill -SIGHUP $(pidof dockerd)
하지만, 지금의 세팅으로는 다시 올라오지 않습니다.
dockerd 로그를 보면 다음과 같습니다. 로그는 다음 명령어로 볼 수 있습니다.
$ sudo journalctl --no-pager -u docker.service
kube-deploy dockerd[16391]: time="2018-10-27T18:36:17.767207453+09:00" level=info msg="Got signal to reload configuration, reloading from: /etc/docker/daemon.json"
kube-deploy dockerd[16391]: time="2018-10-27T18:36:17.767283042+09:00" level=error msg="open /etc/docker/daemon.json: no such file or directory"
디폴트로 dockerd 옵션은 /etc/docker/daemon.json 파일을 읽기 때문에 옵션 reload 가 안되는 문제가 있습니다.
이를 해결하기 위해서 다음과 같이 변경해 보겠습니다.
docker.service 에 정의된 EnvironmentFile 의 변수를 daemon.json 으로 옮기겠습니다.
/etc/systemd/system/multi-user.target.wants/docker.service
EnvironmentFile=-
$ sudo mkdir -p /etc/docker
$ sudo vi /etc/docker/daemon.json
{
"storage-driver": "overlay2",
"insecure-registries": ["docker-registry:5000", "oreo:5000"]
}
docker.service 를 바꿨으니 어쩔 수 없이 한 번의 docker restart 는 해야 합니다.
$ sudo systemctl daemon-reload
$ systemctl restart docker.service
이제 현재의 dockerd option 이 어떤지 보겠습니다.
$ sudo docker system info
Storage Driver: overlay2
Insecure Registries:
docker-registry:5000
oreo:5000
127.0.0.0/8
Insecure Registries 의 oreo:5000 을 제거하고 싶다면 다음과 같이 daemon.json 에서 변경하면 됩니다.
{
"storage-driver": "overlay2",
"insecure-registries": ["docker-registry:5000"]
}
그리고 SIGHUP 을 보내서 option reload 를 하면 새로운 옵션이 적용됩니다.
$ sudo kill -SIGHUP $(pidof dockerd)
dockerd 옵션에 oreo:5000 이 Insecure Registries 에서 빠져 있는 것을 볼 수 있습니다.
$ sudo docker system info
Storage Driver: overlay2
Insecure Registries:
docker-registry:5000
127.0.0.0/8
일반적으로 RBAC 으로 Kubernetes Dashboard 를 설치하면 service account 의 token 을 가지고 접속해야 합니다.
admin clusterrole 을 가진 secret 을 찾아서 해당 token 으로 접속합니다.
$ kubectl -n kube-system describe secret clusterrole-aggregation-controller-token-fmnfg
Name: clusterrole-aggregation-controller-token-fmnfg
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name=clusterrole-aggregation-controller
kubernetes.io/service-account.uid=ccbaf065-8f01-11e8-80c8-3ca82a1ccfd4
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 11 bytes
token: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
매번 이런 token 방식이 귀찮으면 아래와 같이 dashboard service account 에 admin clusterrole 을 지정하고 로그인 화면에서는 skip 을 클릭하여 넘어가면 됩니다.
$ kubectl get serviceaccount -n kube-system | grep kubernetes-dashboard
kubernetes-dashboard 1 8d
$ kubectl create clusterrolebinding kubernetes-dashboard-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:kubernetes-dashboard
Kubernetes dashboard 를 Ingress Controller 와 연결할 때 SSL 을 적용하고 싶으면 다음과 같이 Ingress 를 생성하면 된다.
Kubernetes dashboard ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/secure-backends: "true"
ingress.kubernetes.io/ssl-passthrough: "true"
nginx.org/ssl-backend: "kubernetes-dashboard"
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "100M"
name: kubernetes-dashboard
namespace: kube-system
spec:
tls:
- secretName: kubernetes-dashboard-certs
rules:
- host: dashboard.k8s.stage
http:
paths:
- path: /
backend:
serviceName: kubernetes-dashboard
servicePort: 443