Kubernetes 는 GoLang 으로 만들어진 대표적인 s/w 입니다. Kubernetes  구조와 비슷하게 GoLang 으로 프로젝트를 만들 때 사용되는 일반적인 디렉토리 구조를 설명하겠습니다.

 

제일 먼저 GOPATH 를 지정하고, bin 디렉토리를 PATH에 추가로 지정합니다.

$ GOPATH=/Users/ahnsk/Documents/go_workspace
$ PATH=/Users/ahnsk/Documents/go_workspace/bin:$PATH

 

다음은 go get 으로 govendor 를 설치합니다. govendor 는 dependency module 을 쉽게 다운받고 관리할 수 있습니다.

$ go get -u github.com/kardianos/govendor
$ govendor -version
v1.0.9

 

이제 본인이 생성할 프로젝트를 만들어 보겠습니다. github.com 에 있는 go 프로젝트를 다운로드 받습니다.

$ mkdir -p /Users/ahnsk/Documents/go_workspace/cookiemonster2
$ GOPATH=/Users/ahnsk/Documents/go_workspace/cookiemonster2
$ go get -u github.com/seungkyua/cookiemonster2

GOPATH 는 각 프로젝트마다 자신만의 용도로 사용하기 위해 각각 지정하는 것이 편리합니다.

 

cookiemonster2 라는 프로젝트는 GOPATH 아래의 src 디렉토리에 패키지 경로(github.com/seungkyua/cookiemonster2)로 다운로드 됩니다.

/Users/ahnsk/Documents/go_workspace/cookiemonster2/src/
github.com/seungkyua/cookiemonster2

 

프로젝트 디렉토리로 이동해서 보면 다음과 같습니다.

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    └── ...

 

일반적으로 entrypoint 가 되는 go 파일은 cmd 디렉토리 아래에 위치하고 나머지 go 파일들은 pkg 디렉토리에 패키지 구조로 위치합니다.

vendor 디렉토리는 dependency module 을 다운받은 곳이므로 이 디렉토리는 삭제를 하고, 처음부터 새롭게 구성해 보겠습니다.

$ rm -rf vendor

 

govendor init 으로 vendor 디렉토리를 생성합니다.  새롭게 생성된 vendor 디렉토리에 vendor.json 파일이 보이는데 이것은 향후 dependency module 을 다운 받을 때 활용됩니다.

$ govendor init

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    └── vendor.json

 

vendor 디렉토리 밑으로 디펜던시 module 을 다운로드 받습니다.

$ govendor get github.com/seungkyua/cookiemonster2

$ tree -L 2 .
.
├── Dockerfile.cookiemonster
├── LICENSE
├── Makefile
├── README.md
├── cmd
│   ├── cluster_client.go
│   ├── cluster_client2.go
│   └── server.go
├── config
│   └── config.yaml
├── manifest
│   ├── cookiemonster-cm-config.yaml
│   ├── cookiemonster-deployment.yaml
│   ├── cookiemonster-rbac.yaml
│   └── cookiemonster-service.yaml
├── pkg
│   ├── domain
│   └── handler
└── vendor
    ├── appengine
    ├── appengine_internal
    ├── github.com
    ├── golang.org
    ├── google.golang.org
    ├── gopkg.in
    ├── k8s.io
    ├── sigs.k8s.io
    └── vendor.json

 

vendor 디렉토리에 dependency module 의 특정버전까지 다운 받을 수 있으니 관리가 편리해 집니다. 

현재 버전에서 labstack 의 echo v4 모듈에 버그가 있어 v3 로 다시 다운받기 위해 해당 디렉토리를 지우고 다시 다운 받을 수 있습니다. @v3 는 v3  이상의 최신 버전에 해당하는 git 브랜치나 태그를 다운받으라는 의미입니다.

$ rm -rf vendor/github.com/labstack/echo

$ govendor get github.com/labstack/echo@v3

 

여기서 govendor 의 버그로 echo 는 다운받았지만 하위 디렉토리인 echo/middleware 는 다운이 안되었으므로 추가로 vendor.json 을 수정하여 다운로드 받습니다.

$ vi vendor/vendor.json
{
   "checksumSHA1": "ynPXfBgVKquHSKkdFWk3oqSYf+g=",
   "path": "github.com/labstack/echo",
   "revision": "38772c686c76b501f94bd6cd5b77f5842e93b559",
   "revisionTime": "2019-01-28T14:12:53Z",
   "version": "v3.3.10",
   "versionExact": "v3.3.10"
},
{
   "checksumSHA1": "Rp/k+BJKpaeB9vyjEPFBW4LeFP8=",
   "path": "github.com/labstack/echo/middleware",
   "revision": "38772c686c76b501f94bd6cd5b77f5842e93b559",
   "revisionTime": "2019-01-28T14:12:53Z",
   "version": "v3.3.10",
   "versionExact": "v3.3.10"
}

$ govendor fetch github.com/labstack/echo/middleware

 

 

 

 

 

 

 

 

 

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요


Kubespray 와 같이 많은 role 을 가진 ansible playbook 에서는 선언된 변수와 실제 할당된 값을 살펴보는 것이 쉽지 않습니다. ansible 에서는 이러한 변수들에 대한 값, 특히 hostvar 값을 볼 수 가 있습니다.

일단 먼저 inventory 파일인 hosts.ini 로 어떤 host 와 group 이 지정되었는지 확인할 수 있습니다.

$ vi inventory/k1-seungkyua/hosts.ini
[all]
k1-master01 ip=192.168.30.13
k1-master02 ip=192.168.30.14
k1-master03 ip=192.168.30.15
k1-node01 ip=192.168.30.12
k1-node02 ip=192.168.30.17
k1-node03 ip=192.168.30.18
k1-node04 ip=192.168.30.21
k1-node05 ip=192.168.30.20

[etcd]
k1-master01
k1-master02
k1-master03

[kube-master]
k1-master01
k1-master02
k1-master03

[kube-node]
k1-node01
k1-node02
k1-node03
k1-node04
k1-node05

[k8s-cluster:children]
kube-master
kube-node

다양한 그룹이 있음을 볼 수 있는데 맨 마지막의 k8s-cluster 그룹은 하위로 kube-master 와 kube-node 를 가지고 있으므로, k8s-cluster 그룹이 모든 노드를 포함한다는 것을 알 수 있습니다.

이제 ansible 명령어로 하나의 host 노드 "k1-master01" 에 대해 적용된 변수를 볼 수 있습니다.
 
$ ansible -i inventory/k1-seungkyua/hosts.ini -m debug -a "var=hostvars['k1-master01']" k8s-cluster

이에 대한 결과는 다음과 같습니다.

k1-node01 | SUCCESS => {
    "hostvars['k1-master01']": {
        "admin_token": "QVFBTmRVVlh5UmZoTlJBQTMyZTh6Qk5uajV1VElrMDJEbWFwWmc9PQ==",
        "ansible_all_ipv4_addresses": [
            "192.168.230.13",
            "192.168.30.13",
            "172.16.31.64",
            "172.17.0.1",
            "10.233.0.1",
            "10.233.0.3",
            "10.233.55.72",
            "10.233.18.191"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::3ea8:2aff:fe1c:cfd4",
            "fe80::5eb9:1ff:fe8c:67dc",
            "fe80::42:98ff:fec4:7ad1",
            "fe80::ecee:eeff:feee:eeee",
            "fe80::ecee:eeff:feee:eeee"
        ],
        "ansible_apparmor": {
            "status": "enabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "05/06/2015",
        "ansible_bios_version": "P89",
        "ansible_cali1845c564081": {
            "active": true,
            "device": "cali1845c564081",
            "features": {
                "busy_poll": "off [fixed]",
                "fcoe_mtu": "off [fixed]",
                "generic_receive_offload": "on",
                "generic_segmentation_offload": "on",
                "highdma": "on",
                "hw_tc_offload": "off [fixed]",
                "l2_fwd_offload": "off [fixed]",
                "large_receive_offload": "off [fixed]",
                "loopback": "off [fixed]",
                "netns_local": "off [fixed]",
                "ntuple_filters": "off [fixed]",
                "receive_hashing": "off [fixed]",
                "rx_all": "off [fixed]",
                "rx_checksumming": "on",
                "rx_fcs": "off [fixed]",
                "rx_vlan_filter": "off [fixed]",
                "rx_vlan_offload": "on",
                "rx_vlan_stag_filter": "off [fixed]",
                "rx_vlan_stag_hw_parse": "on",
                "scatter_gather": "on",
                "tcp_segmentation_offload": "on",
                "tx_checksum_fcoe_crc": "off [fixed]",
                "tx_checksum_ip_generic": "on",
                "tx_checksum_ipv4": "off [fixed]",
                "tx_checksum_ipv6": "off [fixed]",
                "tx_checksum_sctp": "off [fixed]",
                "tx_checksumming": "on",
                "tx_fcoe_segmentation": "off [fixed]",
                "tx_gre_segmentation": "on",
                "tx_gso_robust": "off [fixed]",
                "tx_ipip_segmentation": "on",
                "tx_lockless": "on [fixed]",
                "tx_nocache_copy": "off",
                "tx_scatter_gather": "on",
                "tx_scatter_gather_fraglist": "on",
                "tx_sit_segmentation": "on",
                "tx_tcp6_segmentation": "on",
                "tx_tcp_ecn_segmentation": "on",
                "tx_tcp_segmentation": "on",
                "tx_udp_tnl_segmentation": "on",
                "tx_vlan_offload": "on",
                "tx_vlan_stag_hw_insert": "on",
                "udp_fragmentation_offload": "on",
                "vlan_challenged": "off [fixed]"
            },
            "hw_timestamp_filters": [],
            "ipv6": [
                {
                    "address": "fe80::ecee:eeff:feee:eeee",
                    "prefix": "64",
                    "scope": "link"
                }
            ],
            "macaddress": "ee:ee:ee:ee:ee:ee",
            "mtu": 1500,
            "promisc": false,
            "speed": 10000,
            "timestamping": [
                "rx_software",
                "software"
            ],
            "type": "ether"
        },
        "ansible_uptime_seconds": 46351496,
        "ansible_user_dir": "/root",
        "ansible_user_gecos": "root",
        "ansible_user_gid": 0,
        "ansible_user_id": "root",
        "ansible_user_shell": "/bin/bash",
        "ansible_user_uid": 0,
        "ansible_userspace_architecture": "x86_64",
        "ansible_userspace_bits": "64",
        "ansible_verbosity": 0,
        "ansible_version": {
            "full": "2.7.7",
            "major": 2,
            "minor": 7,
            "revision": 7,
            "string": "2.7.7"
        },
        "ansible_virtualization_role": "host",
        "ansible_virtualization_type": "kvm",
        "calico_ip_auto_method": "can-reach=8.8.8.8",
        "ceph_version": "mimic",
        "dashboard_enabled": true,
        "docker_insecure_registries": [
            "tacorepo:5000"
        ],
        "gather_subset": [
            "all"
        ],
        "global_as_num": "65000",
        "group_names": [
            "etcd",
            "k8s-cluster",
            "kube-master"
        ],
        "groups": {
            "all": [
                "k1-master01",
                "k1-master02",
                "k1-master03",
                "k1-node01",
                "k1-node02",
                "k1-node03",
                "k1-node04",
                "k1-node05"
            ],
            "etcd": [
                "k1-master01",
                "k1-master02",
                "k1-master03"
            ],
            "k8s-cluster": [
                "k1-node01",
                "k1-node02",
                "k1-node03",
                "k1-node04",
                "k1-node05",
                "k1-master01",
                "k1-master02",
                "k1-master03"
            ],
            "kube-master": [
                "k1-master01",
                "k1-master02",
                "k1-master03"
            ],
            "kube-node": [
                "k1-node01",
                "k1-node02",
                "k1-node03",
                "k1-node04",
                "k1-node05"
            ],
            "ungrouped": []
        },
        "helm_enabled": true,
        "ingress_nginx_enabled": true,
        "ingress_nginx_host_network": true,
        "ingress_nginx_node_count": 1,
        "ingress_nginx_nodeselector": {
            "node-role.kubernetes.io/ingress": "true"
        },
        "inventory_dir": "/home/seungkyua/deploy/my-kubespray/inventory/k1-seungkyua",
        "inventory_file": "/home/seungkyua/deploy/my-kubespray/inventory/k1-seungkyua/hosts.ini",
        "inventory_hostname": "k1-master01",
        "inventory_hostname_short": "k1-master01",
        "ip": "192.168.30.13",
        "ipip_mode": "Never",
        "kubeadm_enabled": true,
        "kubeconfig_localhost": true,
        "kubectl_localhost": true,
        "local_volume_provisioner_enabled": true,
        "module_setup": true,
        "monitors": "192.168.30.23:6789,192.168.30.24:6789,192.168.30.25:6789",
        "nat_outgoing": true,
        "omit": "__omit_place_holder__4491a572b322dda2550f5ce4d8005946f456f738",
        "override_system_hostname": false,
        "peer_with_router": true,
        "peers": [
            {
                "as": "65000",
                "router_id": "192.168.30.1"
            }
        ],
        "playbook_dir": "/home/seungkyua/deploy/my-kubespray",
        "pool_name": "kubes",
        "populate_inventory_to_hosts_file": false,
        "storageclass_name": "rbd",
        "user_id": "kube",
        "user_secret_namespace": "openstack",
        "user_token": "QVFDdC9CcFlpZ0o3TVJBQTV2eStjbDM5RXNLcFkzQyt0WEVHckE9PQ=="
    }
}




Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요


https://github.com/seungkyua/my-kubespray

my-kubespray

You can easily add your custom logic without modifying kubespray.

The my-kubespray has serveral parameters to override and can deploy ceph rbd provisioner into namespace.

Prerequisites

  • All servers must have the same user, and the user must set root permissions to NOPASSWD in sudo.

  • In the deployment node (or master 1 node), you need to enable ssh access to all other servers (including localhost) without a password to the corresponding account.

  • Register all cluster servers in the /etc/hosts file.

  • Time synchronization between servers with ntp.

  • Enable network restart with systemctl restart network.service .

  • Disable firewall such as selinux or ufw.

  • swapoff.

  • Install python 2.7.x in ansible runner node.

Quick Start

To deploy the cluster you can use :

# Download kubespray and my-kubespray
$ git clone https://github.com/kubernetes-sigs/kubespray.git
$ git clone https://github.com/seungkyua/my-kubespray.git

# Change directory into my-kubespray
$ cd my-kubespray

# Install dependencies from ``requirements.txt``
$ sudo pip install -r ../kubespray/requirements.txt

# Copy ``inventory/k2-seungkyua`` as ``inventory/mycluster``
$ cp -rfp inventory/k2-seungkyua inventory/mycluster

# Update Ansible inventory file
$ vi inventory/mycluster/hosts.ini
[all]
k2-master01 ip=192.168.30.151
k2-master02 ip=192.168.30.152
k2-master03 ip=192.168.30.153
k2-ctrl01 ip=192.168.30.154
k2-ctrl02 ip=192.168.30.155
k2-ctrl03 ip=192.168.30.156
k2-cn01 ip=192.168.30.157

[etcd]
k2-master01
k2-master02
k2-master03

[kube-master]
k2-master01
k2-master02
k2-master03

[kube-node]
k2-ctrl01
k2-ctrl02
k2-ctrl03
k2-cn01

[k8s-cluster:children]
kube-node
kube-master

# Review and change parameters under ``inventory/mycluster/group_vars/k8s-cluster.yml``
$ cat inventory/mycluster/group_vars/k8s-cluster.yml
populate_inventory_to_hosts_file: false
override_system_hostname: false
helm_enabled: true
etcd_memory_limit: 8192M
kubeconfig_localhost: true
kubectl_localhost: true
ipip_mode: Never
calico_ip_auto_method: "can-reach=8.8.8.8"
kubeadm_enabled: true
docker_insecure_registries:
- seungkyua:5000
dashboard_enabled: true
local_volume_provisioner_enabled: true
ingress_nginx_enabled: true
ingress_nginx_host_network: true
ingress_nginx_nodeselector:
node-role.kubernetes.io/ingress: true
ceph_version: mimic
storageclass_name: rbd
monitors: 192.168.30.23:6789,192.168.30.24:6789,192.168.30.25:6789
admin_token: QBTEBmRVVlh5UmZoTlJBQTMyZTh6Qk5uajV1VElrMDJEbWFwWmc9WA==
user_secret_namespace: default
pool_name: kubes
user_id: kube
user_token: QEFESG9CcFlpZ0o3TVJBQTV2eStjbDM5RXNLcFkzQyt0WEVHckE9WA==

# Run Ansible Playbook to deploy kubernetes cluster
$ ansible-playbook -b -f 30 -i inventory/mycluster/hosts.ini ../kubespray/cluster.yml

# Run Ansible Playbook to deploy ceph rbd provisioner
$ ansible-playbook -b -f 30 -i inventory/mycluster/hosts.ini storage.yml

Miscellaneous

After installation, you can find the artifacts which are kubectl and admin.conf in inventory/mycluster/artifacts directorin on deploy node(ansible runner).

$ ls -al inventory/mycluster/artifacts
total 173620
drwxr-x--- 2 seungkyua seungkyua     4096 Feb 22 05:25 .
drwxrwxr-x 4 seungkyua seungkyua     4096 Feb 22 02:38 ..
-rw-r----- 1 seungkyua seungkyua     5449 Feb 22 05:25 admin.conf
-rwxr-xr-x 1 seungkyua seungkyua 177766296 Feb 22 05:25 kubectl
-rwxr-xr-x 1 seungkyua seungkyua       65 Feb 22 05:25 kubectl.sh

If desired, copy admin.conf to ~/.kube/config and kubectl to /usr/local/bin/kubectl

$ mkdir -p ~/.kube
$ cp inventory/mycluster/artifacts/admin.conf ~/.kube/config
$ sudo cp inventory/mycluster/artifacts/kubectl /usr/local/bin/kubectl



Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요

변수의 key 값을 가져오기 위해서는 regex_replace 함수를 사용하여 substring 을 할 수 도 있지만 set_fact 를 이용할 수 도 있습니다.

아래 내용은 set_fact 를 활용한 내용입니다.

예제는 ingress controller 가 실행될 node label 을 세팅하기 위한 방법입니다.
node label 은 다음과 같은 명령어로 세팅할 수 있습니다.
$ kubectl label --overwrite node k2-ctrl01 node-role.kubernetes.io/ingress=true


먼저 변수를 세팅하는 defaults/main.yml 파일은 다음과 같습니다.
ingress_nginx_nodeselector:
  node-role.kubernetes.io/ingress: "true"
ingress_nginx_node_count: 1

ingress_nginx_nodeselector 의 dict 값은 node-role.kubernetes.io/ingress: "true" 인데 node-role.kubernetes.io 는 key 값으로 이 값이 변경될 수 있으므로 key 를 사용하기에는 어렵습니다.

key 값을 유동적으로 활용하기 위해서는 set_fact 를 활용합니다.
- name: Set ingress nginx node role
  set_fact:
    ingress_nginx_node_role:
      key: "{{ item.key }}"
      value: "{{ item.value }}"
  with_dict: "{{ ingress_nginx_nodeselector }}"
  when:
    - inventory_hostname == groups['kube-master'][0]

위 태스크가 실행되면 ingress_nginx_node_role 변수에 {"key" : "node-role.kubernetes.io/ingress", "value" : "true"} 라고 저장됩니다.
그럼 이제 쉽게 ingress_nginx_node_role.key 로 해당 값을 가져올 수 있습니다.

- name: Set ingress nginx node list
  set_fact:
    ingress_nginx_node_list:
      - "{{ groups['kube-node'][item|int] }}"
  with_sequence: start=0 end={{ (ingress_nginx_node_count-1)|int }}
  when:
    - inventory_hostname == groups['kube-master'][0]

- name: NGINX Ingress Controller | Set node label
  shell: |
    {{ bin_dir }}/kubectl label --overwrite node {{ item }} {{ ingress_nginx_node_role.key }}={{ ingress_nginx_node_role.value }}
  loop: "{{ ingress_nginx_node_list }}"
  when:
    - inventory_hostname == groups['kube-master'][0]

label 을 세팅하기 전에 node 를 선택해야 하기 때문에 node 를 선택하는 "Set ingress nginx node list" 태스크를 먼저 수행했고 "NGINX Ingress Controller | Set node label" 태스크가 node label 을 지정하는 명령어 입니다.



 




Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요

Kubernetes Node 가 NotReady 인 경우 해결을 위해서 제일 먼저 해당 노드의 syslog 를 확인 하는 것이 좋다.


## Node 의 syslog 확인 (ubuntu 인 경우)
# vi /etc/log/syslog

Feb 20 12:14:49 k1-node01 kubelet[31100]: E0220 12:14:49.401890   31100 raw.go:146] Failed to watch directory "/sys/fs/cgroup/devices/system.slice": inotify_add_watch /sys/fs/cgroup/devices/system.slice/run-ref5f878051f440b98dfd9bd843a01b58.scope: no space left on device
Feb 20 12:14:49 k1-node01 kubelet[31100]: F0220 12:14:49.401909   31100 kubelet.go:1369] Failed to start cAdvisor inotify_add_watch /sys/fs/cgroup/devices/system.slice/run-ref5f878051f440b98dfd9bd843a01b58.scope: no space left on device
Feb 20 12:14:49 k1-node01 kubelet[31100]: E0220 12:14:49.640153   31100 kubelet.go:2266] node "k1-node01" not found
Feb 20 12:14:49 k1-node01 systemd[1]: kubelet.service: Main process exited, code=exited, status=255/n/a
Feb 20 12:14:49 k1-node01 systemd[1]: kubelet.service: Unit entered failed state.
Feb 20 12:14:49 k1-node01 systemd[1]: kubelet.service: Failed with result 'exit-code'.


위와 같이 inotify_add_watch 에서 no space left on device 로 에러가 날 경우에 sysctl 로 값을 늘려줘야 한다.

## fs.inotify.max_user_watches 값을 늘려줌
# vi /etc/sysctl.d/99-sysctl.conf

net.ipv4.ip_forward=1
net.ipv4.ip_local_reserved_ports=30000-32767
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-arptables=1
net.bridge.bridge-nf-call-ip6tables=1
fs.inotify.max_user_watches=1048576


해당 값을 적용하고 나서 kubelet 이 activating 상태이거나 failed 상태인 경우가 많으므로 아래와 같이 kubelet 을 재 시작해 준다.

## sysctl 로 적용 및 kubelet 재실행

# sysctl -p
# sudo systemctl restart kubelet 






Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요

kubernetes 에서 ceph rbd provisioner 활용 방법입니다.


1. 먼저 rbd provisioner 가 사용할 rbac 권한 yaml 파일을 만듭니다.
# vi rbd-rbac.yaml
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rbd-provisioner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["kube-dns","coredns"]
    verbs: ["list", "get"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rbd-provisioner
subjects:
  - kind: ServiceAccount
    name: rbd-provisioner
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: rbd-provisioner
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rbd-provisioner
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbd-provisioner
  namespace: kube-system
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rbd-provisioner
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rbd-provisioner
subjects:
- kind: ServiceAccount
  name: rbd-provisioner
  namespace: kube-system 

# kubectl create -f rbd-rbac.yaml 



2. kube-system 네임스페이스로 admin secret 과 user secret 을 생성한다.
# ceph auth get client.admin 2>&1 |grep "key = " |awk '{print  $3'} |xargs echo -n > /tmp/secret.admin
# kubectl create secret generic ceph-secret-admin --type=kubernetes.io/rbd --from-file=/tmp/secret.admin --namespace=kube-system

# ceph auth get-key client.kube > /tmp/secret.user
# kubectl create secret generic ceph-secret-user --type=kubernetes.io/rbd --from-file=/tmp/secret.user --namespace=kube-system 




3. rbd provisioner 가 사용할 storage class yaml 파일을 만듭니다.
pool 이름과 userId 를  정확히 입력해야 합니다.

# vi rbd-storageclass.yaml

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: "rbd"
  annotations:
    storageclass.beta.kubernetes.io/is-default-class: "true"
provisioner: ceph.com/rbd
reclaimPolicy: Delete
parameters:
  monitors: "192.168.30.23:6789,192.168.30.24:6789,192.168.30.25:6789"
  adminId: "admin"
  adminSecretName: "ceph-secret-admin"
  adminSecretNamespace: "kube-system"
  pool: "kubes"
  userId: "kube"
  userSecretName: "ceph-secret-user"
  userSecretNamespace: "kube-system"
  imageFormat: "2"
  imageFeatures: "layering" 


# kubectl create -f rbd-storageclass.yaml 



4. rbd provisioner 를 deployment 타입 yaml 로 생성합니다.
# vi deployment-rbd-provisioner.yaml

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rbd-provisioner
  namespace: kube-system
  labels:
    app: rbd-provisioner
    version: v2.1.1-k8s1.11
spec:
  replicas: 2
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: rbd-provisioner
      version: v2.1.1-k8s1.11
  template:
    metadata:
      labels:
        app: rbd-provisioner
        version: v2.1.1-k8s1.11
    spec:
      priorityClassName: system-cluster-critical
      serviceAccount: rbd-provisioner
      containers:
        - name: rbd-provisioner
          image: quay.io/external_storage/rbd-provisioner:v2.1.1-k8s1.11
          imagePullPolicy: IfNotPresent
          env:
            - name: PROVISIONER_NAME
              value: ceph.com/rbd
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          command:
            - "/usr/local/bin/rbd-provisioner"
          args:
            - "-id=${POD_NAME}" 


# kubectl create -f deployment-rbd-provisioner.yaml 




5. 이제 default 네임스페이스에 테스트를 해 보겠습니다.
먼저 default 네임스페이스에 user secret 을 생성합니다. (rbd provisioner 를 사용하고자 하는 네임스페이스에는 user secret 을 만들어 줘야 합니다.)
# ceph auth get-key client.kube > /tmp/secret.user
# kubectl create secret generic ceph-secret-user --type=kubernetes.io/rbd --from-file=/tmp/secret.user --namespace=default


6. 테스트용 pod 생성.

# vi rbd-test.yaml

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-test
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: rbd
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: Pod
metadata:
  name: rbd-test
  namespace: default
spec:
  containers:
  - name: pod-test
    image: gcr.io/google_containers/busybox:1.24
    command:
    - "/bin/sh"
    args:
    - "-c"
    - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
    - name: pvc
      mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
  - name: pvc
    persistentVolumeClaim:
      claimName: rbd-test 



# kubectl create -f rbd-test.yaml 





Posted by Kubernetes Korea co-leader seungkyua@gmail.com

댓글을 달아 주세요