ポータブルなGlusterFSコンテナを作成する（レプリカ数２の場合）

# 1. はじめに
　複数のサーバでコンテナを運用する際、コンテナ内で動作するアプリケーションが保存するファイルをどのように保持するかを考える必要があります。Kubernetesでは、CephやGlusterFSなどの分散ストレージが利用できます。この記事では、十数台程度の小規模なオンプレミスのdocker実行環境で、GlusterFSによるデータ保持機構を構築するときに検討した内容をまとめたものです(下図のように、コンテナの参照先をファイルサーバにすることで、どのサーバでコンテナが稼働しても同じデータを参照できます。)。

![arch1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/2302ba99-79d3-1e43-1bd3-dc7a68b1c223.png)

記事にまとめるにあたり、「オンプレミスな環境で0からGluster側の構築を如何に簡単に行うか」に焦点を当てるため、以降の説明ではアプリケーションサーバは1台、Glusterサーバは2台とします。

# 2. ねらい
[参考１：GlusterFS Containers](https://github.com/gluster/gluster-containers)
[参考２：Official GlusterFS Image [ CentOS-7 + GlusterFS ] ](https://hub.docker.com/r/gluster/gluster-centos/tags?page=1&ordering=last_updated)

* 本番環境の構築を易化するため、Glusterサーバはコンテナで構築する。検証として、Glusterコンテナは、Officialのものを活用する。
* 本番環境は、ホスト側にネットワークが構築された環境であり、[参考1](https://github.com/gluster/gluster-containers)にあるよう本番環境では、--net=hostオプションを使用する。ただし、開発環境で常に2サーバ用意するのは手間なので、開発環境ではdokcer networkを用いて本番環境を模擬する。（ネットワークアドレスは仮のものです）

![deploy-pattern.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/1424a992-5a1d-a54a-2526-4fa849398b5a.png)

# 3. 検討
## 3.1. 基本的なこと
* 本番環境のGlusterサーバのホスト名は、それぞれserver1とserver2とする。
* Glusterコンテナの内部ホスト名は、gluster-server-1とgluster-server-2とする。
* [参考1](https://github.com/gluster/gluster-containers)より、Glusterコンテナは/sbin/initで起動し、glusterdをサービス起動する。D-Bus関連のサービスはdisableとなっているが、privilegedオプションを使用する。
* systemdを使用する関係で、CMD設定を/sbin/initから変更できないので、entry-pointを仕込むためにentry-point.service（このサービスでentry-point.shを呼び出す）を設定する。
* Glusterのボリューム名はVOL1とし、それぞれ/home/HDD1にBrickを作成する。

## 3.2. Glusterの設定を構築し、コンテナイメージに組み込む方法
[参考３：CentOS7でGlusterFSの環境構築](https://qiita.com/Yuki-Inamoto/items/2ea1efe862aeba34019c)
* 開発環境に、以下のようなdocker-compose.ymlでコンテナを構築する。マウントディレクトリの選定は、[参考1](https://github.com/gluster/gluster-containers)で示されたディレクトリに加えて、Brickの隠しディレクトリがあるHDD1を指定している。

```yml
version: "3.7"
services:
  gluster-server-1:
    hostname: gluster-server-1
    image: gluster/gluster-centos:gluster3u10_centos7
    volumes:
      - ${PWD}/volume/gluster-server-1/etc-glusterfs:/etc/glusterfs
      - ${PWD}/volume/gluster-server-1/var-lib-glusterd:/var/lib/glusterd
      - ${PWD}/volume/gluster-server-1/HDD1:/home/HDD1
    extra_hosts:
      - "gluster-server-2:192.168.3.20"
    privileged: true
    networks:
      app_net:
        ipv4_address: 192.168.3.10

  gluster-server-2:
    hostname: gluster-server-2
    image: gluster/gluster-centos:gluster3u10_centos7
    volumes:
      - ${PWD}/volume/gluster-server-2/etc-glusterfs:/etc/glusterfs
      - ${PWD}/volume/gluster-server-2/var-lib-glusterd:/var/lib/glusterd
      - ${PWD}/volume/gluster-server-2/HDD1:/home/HDD1
    extra_hosts:
      - "gluster-server-1:192.168.3.10"
    privileged: true
    networks:
      app_net:
        ipv4_address: 192.168.3.20

networks:
  app_net:
    name: app_net
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 192.168.3.0/24
```

* docker-compose up -dでコンテナ起動後、[参考３](https://qiita.com/Yuki-Inamoto/items/2ea1efe862aeba34019c)に従って設定を行う。この設定を行うことで、必要なコンフィグファイルをマウントディレクトリに格納される。
* docker buildでコンテナイメージ内に組み込むのだが、設定ファイルを以下のように配置する。リンク作成やディレクトリ移動は、起動時に呼ばれるentry-point.serviceを組み込み、その中で実施する。

![directory4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/336231b1-aca4-590a-68f3-3a260bf904b9.png)


* Dockerfileは以下のように作成した。

```dockerfile
FROM gluster/gluster-centos:gluster3u10_centos7

COPY ./volume /tmp/volume
COPY ./script /tmp/script

RUN systemctl disable glusterd.service; systemctl disable gluster-setup.service; \
mkdir -p /home/gluster; \
mv /tmp/volume/gluster-server-1 /home/gluster/; mv /tmp/volume/gluster-server-2 /home/gluster/; \
mkdir -p /home/HDD1; \
mv /tmp/script/entry-point.service /etc/systemd/system/; \
systemctl enable entry-point.service; \
mv /tmp/script/entry-point.sh /entry-point.sh; \
rm -rf /tmp/*
```

* entry-point.shは以下のように作成した。

```bash
#!/bin/bash

function main() {
  echo "entry-point start." > /tmp/start.log

  # delete default gluster setting
  rm -rf /etc/glusterfs
  rm -rf /var/lib/glusterd

  # gluster-server-1 ?
  echo $HOSTNAME | grep "gluster-server-1" >/dev/null
  local ret=$?
  local gluster=""
  if [ $ret = "0" ]; then
    gluster="gluster-server-1"
  fi

  # gluster-server-2 ?
  echo $HOSTNAME | grep "gluster-server-2" >/dev/null
  ret=$?
  if [ $ret = "0" ]; then
    gluster="gluster-server-2"
  fi

  mv /home/gluster/$gluster/etc-glusterfs /etc/glusterfs
  mv /home/gluster/$gluster/var-lib-glusterd /var/lib/glusterd

  local init_flag="0"
  if [ -d /home/HDD1/.glusterfs ]; then
    # non-first start
    echo "exist /home/HDD1/.glusterfs" >>/tmp/start.log
  else
    # first start
    echo "no exist /home/HDD1/.glusterfs" >>/tmp/start.log
    echo "mv /home/gluster/$gluster/HDD1/.glusterfs /home/HDD1/" >>/tmp/start.log
    mv /home/gluster/$gluster/HDD1/.glusterfs /home/HDD1/
    init_flag="1"
  fi

  sleep 1

  # starting glusterd
  systemctl restart glusterd

  if [ $init_flag != "0" ]; then
    sleep 10
    # gluster force-restart
    echo "gluster vol start VOL1 force" >>/tmp/start.log
    gluster vol start VOL1 force
  fi

  echo "entry-point started." >>/tmp/start.log
  return 0
}

main
exit 0
```

## 3.3 本番環境へデプロイする設定
* 実行環境で動作させるためのdocker-compose.ymlを以下のように作成し、コンテナイメージのsaveデータを展開して動作させる。(コンテナイメージ名は適当につけているため、docker build時に適切な名前を設定すること。)

```yml
version: "3.7"
services:
  gluster-server-1:
    hostname: gluster-server-1
    image: my-gluster:0.0
    volumes:
      - ${PWD}/HDD1:/home/HDD1
      - ${PWD}/log:/var/log/glusterfs
    extra_hosts:
      - "gluster-server-1:192.168.3.10"
      - "gluster-server-2:192.168.3.20"
    privileged: true
    network_mode: host

  gluster-server-2:
    hostname: gluster-server-2
    image: my-gluster:0.0
    volumes:
      - ${PWD}/HDD1:/home/HDD1
      - ${PWD}/log:/var/log/glusterfs
    extra_hosts:
      - "gluster-server-1:192.168.3.10"
      - "gluster-server-2:192.168.3.20"
    privileged: true
    network_mode: host
```

## 3.4 プロジェクトの全体構成
上記の情報をまとめると、以下のような構成となった。setupが開発環境で構築する内容で、deployが本番環境の設定をまとめるところ、としている。
![directory3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/77a4f16c-79e4-978f-d7dc-f41522575367.png)


# 4. まとめ
　自分がこの構成を検討するとき、なかなかGlusterの設定内容をコンテナイメージ内に組み込んでデプロイする事例が見つからなかったため、備忘録として記事にまとめてみました。コンテナ内でglusterを起動するときに、事前にコンフィグを移動したり、強制起動し直す、といったハマるポイントがあったので注意が必要です。
　また、検証の側面が強かったので、IPアドレスとかの設定が直書きです。そのあたりを環境変数にするなど、実際にデプロイするものに仕上げるにはもう少し改良が必要です。

(2021/3/28 追記)
　本記事の設定スクリプトやまとめでの改善内容を加味したものをGithubにコミットしました。
https://github.com/tomoten-umino/portable-gluster