CentOS 7.6上のMicrok8s環境でEFKスタック(Elasticsearch,Fluentd,Kibana)を利用してコンテナログを取得・可視化【1】

首題の通り。シングルノード構成。
fluentd周りで大変苦労した。

f:id:sota0113:20190529220252p:plain

このブログポストで紹介する内容は以下。

====ここから====
ステップ⓪コンポーネント紹介
ステップ①dockerを導入する
ステップ②microk8sをCentOSに導入する
ステップ③dockerイメージを取得してmicrok8sのプライベートイメージリポジトリにプッシュする
ステップ④microk8sでビルドしたイメージを動かす。
====ここまで====

※以下は次回のブログポストを参照
ステップ⑤elasticsearchをデプロイする
ステップ⑥kibanaをデプロイする
ステップ⑦fluentdをデプロイする


ステップ⓪コンポーネント紹介

まず登場する各コンポーネントの簡単な説明。

CentOS
OS。バージョン7.6を使用。
(ちなみにインスタンスのCPUは1コアでメモリは4GB。これでも動くんですね。)

・Microk8s
軽量なKubernetes実行環境。バージョンv1.14.1を使用。

・fluentd
データ収集・転送コンポーネント。Elasticsearchにログを転送する役を担う。
今回はhelmで導入し、DaemonSetとして稼動させる。dockerイメージ名とタグ:gcr.io/fluentd-elasticsearch/fluentd:v2.5.2
(Microk8sに組み込まれたfluentdも利用可能だが、今回そちらは利用せず、別途導入する。helmで導入したのは、試行錯誤の結果、helmでの導入が唯一うまくいったためです。。)

・Elasticserach
分散型RESTful検索/分析エンジン。Kibanaからのログ検索の役割を担う。
Podとして稼動させる。dockerイメージ名とタグ:docker.elastic.co/elasticsearch/elasticsearch:6.5.4

Kibana
可視化ツール。今回はElasticsearchがfluentdから収集したログを可視化する役割を担う。
Podとして稼動させる。dockreイメージ名とタグ:docker.elastic.co/kibana/kibana:6.5.4

helm
kubernetes構成ツール。fluentdのために利用。
クライアント、サーバーともにバージョンは2.14.0。
(手動でデプロイメント作っても良いと思いますが、私はうまくいかず、上述の通り試行錯誤の結果、helmでの導入が唯一うまくいきました)

docker
docker imageの管理のために利用。バージョンは1.13.1


ステップ①dockerを導入する

イメージ管理のためにdockerを導入。

[nakanishi@elastic01 ~]$ sudo yum install docker
Loaded plugins: copr, fastestmirror
…
Complete!

dockerプロセスを開始。

[nakanishi@elastic01 ~]$
[nakanishi@elastic01 ~]$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: http://docs.docker.com
[nakanishi@elastic01 ~]$ sudo systemctl start docker
[nakanishi@elastic01 ~]$
[nakanishi@elastic01 ~]$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2019-05-24 03:33:54 CDT; 17s ago
     Docs: http://docs.docker.com
….
[nakanishi@elastic01 ~]$

nakanishiユーザーでdockerコマンドを利用しようとしたらpermission deniedだった。
https://qiita.com/tubone/items/9c1b3d807197b7162fd9
Centos7ではユーザーをdockerrootグループに追加して、/var/run/docker.sockのグループをrootからdockcerrootに変更することが必要なようだ。

[akanishi@elastic01 ~]$ sudo usermod -aG dockerroot ${USER}
[nakanishi@elastic01 ~]$ groups ${USER}
nakanishi : nakanishi wheel dockerroot
[nakanishi@elastic01 ~]$
[nakanishi@elastic01 ~]$ sudo chown root:dockerroot /var/run/docker.sock
[nakanishi@elastic01 ~]$ ls -l /var/run/docker.sock
srw-rw----. 1 root dockerroot 0 May 24 03:33 /var/run/docker.sock
[nakanishi@elastic01 ~]$

これでdockerコマンドを利用できるはずだったが、まだpermission denied。
一度シェルを終了し、再度ログインしたところ、無事dockerコマンドが利用できた。


また、以下を参照。
https://qiita.com/ir-shin1/items/37d606144566387996eb
“ただ、/var/run/docker.sock は起動のたびに作成されるファイル(ソケット)だからどこかでグループを定義してやる必要がある。”
↑なるほど。
以下の通りdockerを構成。

[nakanishi@elastic01 ~]$ sudo cp /etc/sysconfig/docker /etc/sysconfig/docker.org
[nakanishi@elastic01 ~]$ sudo vi /etc/sysconfig/docker
[nakanishi@elastic01 ~]$ sudo diff /etc/sysconfig/docker /etc/sysconfig/docker.org
4c4
< OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false -G dockerroot'
---
> OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false'
[nakanishi@elastic01 ~]$
起動時にdockerrootグループで起動するように構成した。

dockerプロセスを再起動。

[nakanishi@elastic01 ~]$ sudo systemctl restart docker
[nakanishi@elastic01 ~]$ systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2019-05-24 03:45:05 CDT; 6s ago
     Docs: http://docs.docker.com
[nakanishi@elastic01 ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[nakanishi@elastic01 ~]$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
[nakanishi@elastic01 ~]$

ステップ②microk8sをCentOSに導入する


microk8sをCentOS7に導入する。
参考:https://computingforgeeks.com/install-snapd-snap-applications-centos-7/

[nakanishi@elastic01 ~]$ sudo yum install -y epel-release
[sudo] password for nakanishi:
[nakanishi@elastic01 ~]$ sudo yum install -y yum-plugin-copr
[sudo] password for nakanishi:
......()
Complete!
[nakanishi@elastic01 ~]$ sudo yum copr enable ngompa/snapcore-el7
......()
Do you want to continue? [y/N]: y
copr done
[nakanishi@elastic01 ~]$ sudo yum -y install snapd
Loaded plugins: copr, fastestmirror
......()
Complete!
[nakanishi@elastic01 ~]$ sudo systemctl enable --now snapd.socket
Created symlink from /etc/systemd/system/sockets.target.wants/snapd.socket to /usr/lib/systemd/system/snapd.socket.
[nakanishi@elastic01 ~]$ sudo ln -s /var/lib/snapd/snap /snap
[nakanishi@elastic01 ~]$ which snap
/usr/bin/snap    //snapコマンドを確認。
sudo snap install microk8s --classic
2019-05-24T03:18:25-05:00 INFO Waiting for restart...
Warning: /var/lib/snapd/snap/bin was not found in your $PATH. If you've not restarted your session
         since you installed snapd, try doing that. Please see https://forum.snapcraft.io/t/9469
         for more details.

microk8s v1.14.1 from Canonical✓ installed
[nakanishi@elastic01 ~]$

これで導入自体は完了。
この状態だと必要なパスが通っておらずmicrok8sを操作するコマンド群microk8s.*コマンドが見つからないので、“/var/lib/snapd/snap/bin”のパスを通す。

[nakanishi@elastic01 ~]$ export PATH=$PATH:/var/lib/snapd/snap/bin

これでmicrok8sの操作コマンドのパスを通すことができた。

[nakanishi@elastic01 ~]$  microk8s.config
2019/05/24 03:23:09.833961 cmd_run.go:367: restoring default SELinux context of /home/nakanishi/snap
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxxxx...(SSL証明書をbase64で難読化した値)
    server: https://XX.XXX.XXX.XX:XXXXX
    name: microk8s-cluster
contexts:
- context:
    cluster: microk8s-cluster
    user: admin
  name: microk8s
current-context: microk8s
kind: Config
preferences: {}
users:
- name: admin
  user:
    username: admin
    password: xxxxxxxxxxxxxxxxxxx
[nakanishi@elastic01 ~]$

以下のステータス確認コマンドを実行すると、microk8sには色々とアドオンがあることがうかがえる。(fluentdも)

[nakanishi@elastic01 ~]$ microk8s.status
microk8s is running
addons:
ingress: disabled
dns: disabled
metrics-server: disabled
prometheus: disabled
istio: disabled
jaeger: disabled
fluentd: disabled
gpu: disabled
storage: disabled
dashboard: disabled
registry: disabled
[nakanishi@elastic01 ~]$

DNSを有効化させる。

[nakanishi@elastic03 curl]$ microk8s.enable dns
Enabling DNS
Applying manifest
service/kube-dns created
serviceaccount/kube-dns created
configmap/kube-dns created
deployment.extensions/kube-dns created
Restarting kubelet
[sudo] password for nakanishi:
DNS is enabled
[nakanishi@elastic03 curl]$

kubectlコマンド相当のコマンドはmicrok8s.kubectlであるようだ。

[nakanishi@elastic01 ~]$ microk8s.kubectl config current-context
microk8s

kubectlコマンドを実行できるように、エイリアス設定。

[nakanishi@elastic01 ~]$ sudo snap alias microk8s.kubectl kubectl
[sudo] password for nakanishi:
Added:
  - microk8s.kubectl as kubectl
[nakanishi@elastic01 ~]$

ステップ③dockerイメージを取得してmicrok8sのプライベートイメージリポジトリにプッシュする

fluentdがログを収集するサンプルアプリのdocker imageを作成して、プッシュする。

#ディレクトリを作成して移動

[nakanishi@elastic03 ~]$ mkdir -p k8s/testapp/sample-app
[nakanishi@elastic03 ~]$ cd ~/k8s/testapp/sample-app
[nakanishi@elastic03 sample-app]$


#Dockerimageの作成
Dockerfile

[nakanishi@elastic03 sample-app]$ cat Dockerfile
FROM node:10.11.0-alpine

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY index.js ./

EXPOSE 3000

CMD [ "node", "index.js" ]
[nakanishi@elastic03 sample-app]$

#Dockerfileで利用するpackage.jsonとcat package-lock.json、index.jsファイルを作成。

[nakanishi@elastic03 sample-app]$ vim package.json
[nakanishi@elastic03 sample-app]$ cat package.json
{
  "dependencies": {
    "simple-node-logger": "^18.12.21"
  }
}
[nakanishi@elastic03 sample-app]$ vim package.json
[nakanishi@elastic03 sample-app]$ cat package-lock.json
{
  "requires": true,
  "lockfileVersion": 1,
  "dependencies": {
    "event-lite": {
      "version": "0.1.2",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/event-lite/-/event-lite-0.1.2.tgz",
      "integrity": "sha1-g4o+D93e+MyQ8SgAbI5VpOTkwRs="
    },
    "fluent-logger": {
      "version": "3.2.3",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/fluent-logger/-/fluent-logger-3.2.3.tgz",
      "integrity": "sha1-PjG0fWPz6f/ueSnR9n5XorrlZIY=",
      "requires": {
        "msgpack-lite": "*"
      }
    },
    "ieee754": {
      "version": "1.1.12",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/ieee754/-/ieee754-1.1.12.tgz",
      "integrity": "sha1-UL8k5bnIu5ivSWTJQc2wkY2ntgs="
    },
    "int64-buffer": {
      "version": "0.1.10",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/int64-buffer/-/int64-buffer-0.1.10.tgz",
      "integrity": "sha1-J3siiofZWtd30HwTgyAiQGpHNCM="
    },
    "isarray": {
      "version": "1.0.0",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/isarray/-/isarray-1.0.0.tgz",
      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
    },
    "lodash": {
      "version": "4.17.11",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/lodash/-/lodash-4.17.11.tgz",
      "integrity": "sha1-s56mIp72B+zYniyN8SU2iRysm40="
    },
    "moment": {
      "version": "2.23.0",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/moment/-/moment-2.23.0.tgz",
      "integrity": "sha1-dZ6kkayX1UusWtd2mW4qWMwbwiU="
    },
    "msgpack-lite": {
      "version": "0.1.26",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/msgpack-lite/-/msgpack-lite-0.1.26.tgz",
      "integrity": "sha1-3TxQsm8FnyXn7e42REGDWOKprYk=",
      "requires": {
        "event-lite": "^0.1.1",
        "ieee754": "^1.1.8",
        "int64-buffer": "^0.1.9",
        "isarray": "^1.0.0"
      }
    },
    "simple-node-logger": {
      "version": "18.12.21",
      "resolved": "http://jam.clickfox.net:80/artifactory/api/npm/npm/simple-node-logger/-/simple-node-logger-18.12.21.tgz",
      "integrity": "sha1-nv0ITxis/erSfK0SVNevP3R2gkY=",
      "requires": {
        "lodash": "^4.17.10",
        "moment": "^2.20.1"
      }
    }
  }
}
[nakanishi@elastic03 sample-app]$

index.js

[nakanishi@elastic03 sample-app]$ cat index.js
const SimpleNodeLogger = require('simple-node-logger');
const opts = {
  timestampFormat:'YYYY-MM-DD HH:mm:ss.SSS'
};
const log = SimpleNodeLogger.createSimpleLogger(opts);

(function repeatMe() {
  setTimeout(() => {
    log.info('it works');
    repeatMe();
  }, 1000)
})();
[nakanishi@elastic03 sample-app]$

合計4つのファイルを用意した。

[nakanishi@elastic03 sample-app]$ ls -la
total 24
drwx------. 2 nakanishi nakanishi 4096 May 26 23:28 .
drwx------. 3 nakanishi nakanishi 4096 May 26 23:33 ..
-rw-------. 1 nakanishi nakanishi  145 May 26 23:24 Dockerfile
-rw-------. 1 nakanishi nakanishi  277 May 26 23:25 index.js
-rw-------. 1 nakanishi nakanishi   66 May 26 23:26 package.json
-rw-------. 1 nakanishi nakanishi 2314 May 26 23:25 package-lock.json
[nakanishi@elastic03 sample-app]$

イメージをビルドする。

[nakanishi@elastic03 sample-app]$ docker build -t fluentd-node-sample:latest ./
Sending build context to Docker daemon 7.168 kB
Step 1/7 : FROM node:10.11.0-alpine
......()
Successfully built 7d1c9aabd8f8
[nakanishi@elastic03 sample-app]$

ビルドしたイメージを確認する。

[nakanishi@elastic03 sample-app]$ docker images fluentd-node-sample
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
fluentd-node-sample   latest              7d1c9aabd8f8        2 days ago          75 MB
[nakanishi@elastic03 sample-app]$

イメージをtarファイル化する

[nakanishi@elastic03 sample-app]$ docker save fluentd-node-sample:latest > fluentd-node-sample.tar
[nakanishi@elastic03 sample-app]$ ls -la
total 78260
drwx------. 2 nakanishi nakanishi     4096 May 29 02:19 .
drwx------. 3 nakanishi nakanishi     4096 May 26 23:33 ..
-rw-------. 1 nakanishi nakanishi      145 May 26 23:24 Dockerfile
-rw-------. 1 nakanishi nakanishi 80024576 May 29 02:20 fluentd-node-sample.tar
-rw-------. 1 nakanishi nakanishi      277 May 26 23:25 index.js
-rw-------. 1 nakanishi nakanishi       66 May 26 23:26 package.json
-rw-------. 1 nakanishi nakanishi     2314 May 26 23:25 package-lock.json
[nakanishi@elastic03 sample-app]$

イメージをmicrok8sのリポジトリにインポートする。

[nakanishi@elastic03 sample-app]$ microk8s.ctr -n k8s.io image import ./fluentd-node-sample.tar
[sudo] password for nakanishi:
unpacking docker.io/library/fluentd-node-sample:latest (sha256:eea68fd106755a230c9f681ab1e96ea17f9dff2f79ca650199645b913650341c)...done
[nakanishi@elastic03 sample-app]$

インポートしたイメージを確認する。

[nakanishi@elastic03 sample-app]$ microk8s.ctr -n k8s.io images ls | grep sample
docker.io/library/fluentd-node-sample:latest      application/vnd.oci.image.manifest.v1+json     sha256:eea68fd106755a230c9f681ab1e96ea17f9dff2f79ca650199645b913650341c 76.3 MiB  linux/amd64       io.cri-containerd.image=managed
[nakanishi@elastic03 sample-app]$

ステップ④microk8sでビルドしたイメージを動かす。

デプロイメントを作成する

[nakanishi@elastic03 sample-app]$ cd ../
[nakanishi@elastic03 testapp]$ pwd
/home/nakanishi/k8s/testapp
[nakanishi@elastic03 testapp]$ ls
sample-app    //sampleappディレクトリにはアプリのファイル群がある。
[nakanishi@elastic03 testapp]$
[nakanishi@elastic03 testapp]$ vim node-deployment.yaml
[nakanishi@elastic03 testapp]$ cat node-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: node
  labels:
    name: node
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: node
    spec:
      containers:
      - name: node
        image: fluentd-node-sample:latest
        imagePullPolicy: IfNotPresent
[nakanishi@elastic03 testapp]$

今回はサービスリソースは作成しない。(fluentdに転送するログを取得できれば良いため)

デプロイメントをデプロイする。

#デプロイ
[nakanishi@elastic03 testapp]$ kubectl apply -f node-deployment.yaml
deployment.extensions/node created
#確認
[nakanishi@elastic03 testapp]$ kubectl  get pod --all-namespaces   -w
NAMESPACE     NAME                                     READY   STATUS    RESTARTS   AGE
default       node-8684bdfccf-fnmps                    1/1     Running   0          3s
kube-system   kube-dns-6bfbdd666c-qrwlg                3/3     Running   0          3d
^C[nakanishi@elastic03 testapp]$

以上。