Docker版　NFS/Samba　の構築

# 実現したいこと

ファイル共有サービスを１つのDockerで定義してみる

# 前提
「198.168.0.0/16」セグメント内でのサービス提供
ホストOSの「/mnt/data」へ共有オブジェクトを格納

Sambaは、お使いの環境に合わせる必要が多分にあります。
クライアントOSがwindows2008以前であれば、ユーザ認証不要
それ以降、ホストOSのユーザIDが必要。

# Samba
・主にWindowsサーバ向けにファイル共有サービスを展開

# NFS
・主にLinuxサーバ向けにファイル共有サービスを展開

# 事前準備

- docker engine

### 向いているひと

OSを汚したくないきれい好きな人向け。
とにかくシンプルにOS機能で実現させたい。

### Docker構成
ディレクトリ
```
nfs_server
├── compose.yml
├── Dockerfile.samba
├── Dockerfile.nfs
└── docker-entrypoint.sh

```
### 構成ファイル

```yml:compose.yml
x-environment: &environment
  EXEC_USERID: ${EXEC_USERID}
  EXEC_GROUPID: ${EXEC_GROUPID}
  NFS_EXP: ${NFS_EXP}

services:
  samba:
    build:
      context: .
      dockerfile: Dockerfile.samba
    ports:
      - 445:445
    restart: always
    cap_add:
      - CAP_NET_ADMIN
    environment:
      - TZ=Asia/Tokyo
    volumes:
      - /mnt/data:/mount
    networks:
      app_net:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"

  file-share:
    build:
      context: .
      args:
        - APT_PROXY=${HTTP_PROXY}
      dockerfile: Dockerfile.nfs
    environment:
      - TZ=Asia/Tokyo
      - USERID=${EXEC_USERID}
      - GROUPID=${EXEC_GROUPID}
      - NFS_EXP=${NFS_EXP}
    volumes:
      - /mnt/data:/exports
    privileged: true
    restart: always
    ports:
      - "2049:2049"
      - "20048:20048"
    networks:
      app_net:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"

networks:
  app_net:
    name: app_net
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"
      com.docker.network.bridge.name: br0
    ipam:
      driver: default
      config:
      - subnet: 172.16.238.0/24
```

```Dockerfile:Dockerfile.nfs
# Copyright 2016 The Kubernetes Authors.
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# FROM gcr.io/google-appengine/debian9
FROM debian:bullseye-slim
# FROM debian:11-slim

ARG APT_PROXY
RUN if [ "$APT_PROXY" != "" ]; then echo "Acquire::http { Proxy \"$APT_PROXY\"; };" > /etc/apt/apt.conf.d/01proxy; fi

ENV NFS_VERSION 1:1.3.4-2.1

ENV C2D_RELEASE 1.3.4

#RUN echo "deb http://archive.debian.org/debian-archive/debian/ stretch main" > /etc/apt/sources.list && \
#    echo "deb http://archive.debian.org/debian-archive/debian-security stretch/updates main" >> /etc/apt/sources.list && \
#    apt-get update && apt-get install -qq -y nfs-kernel-server && \
#    rm -rf /var/lib/apt/lists/* && \
#    mkdir /exports

RUN apt-get update && apt-get install -qq -y nfs-kernel-server && \
    rm -rf /var/lib/apt/lists/* && \
    mkdir /exports

COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +rx /usr/local/bin/docker-entrypoint.sh

VOLUME /exports

EXPOSE 2049/tcp
EXPOSE 20048/tcp

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["/exports"]

```

```Dockerfile:Dockerfile.samba
FROM alpine:3.10

RUN mkdir -p /mount && \
    chmod -R 0777 /mount && \
    chown -R nobody:nobody /mount

# install samba
RUN apk update && \
    apk add samba
RUN { \
    echo "[global]"; \
    echo "  security = user"; \
    echo "  map to guest = Bad User"; \
    echo "  guest account = nobody"; \
    echo "  min protocol = SMB2"; \
    echo "[data]"; \
    echo "  path = /mount"; \
    echo "  writable = yes"; \
    echo "  guest ok = yes"; \
    echo "  guest only = yes"; \
    echo "  create mode = 0666"; \
    echo "  directory mode = 0777"; \
} > /etc/samba/smb.conf
EXPOSE 139 445

# start smbd as foreground
ENTRYPOINT ["/bin/ash"]
CMD ["-c", "nmbd restart -D && smbd restart -FS --no-process-group </dev/null"]
```


```file:docker-entrypoint.sh
#!/bin/bash
# Copyright 2015 The Kubernetes Authors.
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

function start()
{
    unset gid
    # accept "-G gid" option
    while getopts "G:" opt; do
        case ${opt} in
            G) gid=${OPTARG};;
        esac
    done
    shift $(($OPTIND - 1))

    # prepare /etc/exports
    for i in "$@"; do
        # fsid=0: needed for NFSv4
        echo "$i ${NFS_EXP}" > /etc/exports
        if [ -v gid ] ; then
            chmod 070 $i
            chgrp $gid $i
        fi
        echo "Serving $i"
    done

    # start rpcbind if it is not started yet
    /usr/sbin/rpcinfo 127.0.0.1 > /dev/null; s=$?
    if [ $s -ne 0 ]; then
       echo "Starting rpcbind"
       /sbin/rpcbind -w
    fi

    mount -t nfsd nfds /proc/fs/nfsd

    # -V 3: enable NFSv3
    /usr/sbin/rpc.mountd -N 2 -V 3

    /usr/sbin/exportfs -r
    # -G 10 to reduce grace time to 10 seconds (the lowest allowed)
    /usr/sbin/rpc.nfsd -G 10 -N 2 -V 3
    /sbin/rpc.statd --no-notify
    echo "NFS started"
}

function stop()
{
    echo "Stopping NFS"

    /usr/sbin/rpc.nfsd 0
    /usr/sbin/exportfs -au
    /usr/sbin/exportfs -f

    kill $( pidof rpc.mountd )
    umount /proc/fs/nfsd
    echo > /etc/exports
    exit 0
}

trap stop TERM

start "$@"

# Ugly hack to do nothing and wait for SIGTERM
while true; do
    sleep 5
done
```

```file:.env
EXEC_USERID="600"
EXEC_GROUPID="600"
NFS_EXP="192.168.0.0/16(rw,fsid=0,sync,insecure,no_subtree_check,no_root_squash)"
```

# 実行方法

`compose.yml`のディレクトリがある場所まで移動する。
その後、以下のコマンドで起動

```sh
docker-compose up -d
```

```exec:docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED        STATUS         PORTS                                                                                      NAMES
a1126d7e8bec   nfs_server-samba        "/bin/ash -c 'nmbd r…"   44 hours ago   Up 5 minutes   139/tcp, 0.0.0.0:445->445/tcp, :::445->445/tcp                                             nfs_server-samba-1
59016b7d5745   nfs_server-file-share   "/usr/local/bin/dock…"   44 hours ago   Up 5 minutes   0.0.0.0:2049->2049/tcp, :::2049->2049/tcp, 0.0.0.0:20048->20048/tcp, :::20048->20048/tcp   nfs_server-file-share-1
```

■接続例
・Samba
ホストサーバ「192.168.XXX.XXX」に対して、WindowsコマンドプロンプトよりユーザID「XXX_user」、パスワード「XXX_pass」Zドライブに接続
（OS画面から接続する場合はユーザIDを「localhost\XXX_user」とする必要があると思います）
```command:コマンドプロンプト
net use * /delete /yes

net use Z: \\192.168.XXX.XXX\data XXX_pass /user:XXX_user
```

・NFS
ホストサーバ「192.168.XXX.XXX」に対して、「/mnt/sample」へマウントさせる。下記のように「/etc/fstab」ファイル設定後に「mount -a」にて反映

```file:/etc/fstab
192.168.XXX.XXX:/    /mnt/sample  nfs     auto,rw,noexec,nosuid,nodev,soft,intr,timeo=300,retrans=1  0 0
```
# 補足
windowsサーバについては事前設定が必要。(@loxsols(Naoya Kawaguchi)記事を引用)

[Windows10/11]クライアントからサーバの共有フォルダにアクセスするとエラーが表示され、アクセスできない
https://faq.mypage.otsuka-shokai.co.jp/app/answers/detail/a_id/314207/~/%5Bwindows10%2F11%5D%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%81%8B%E3%82%89%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E5%85%B1%E6%9C%89%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%E3%81%A8%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%80%81%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84

SMB2 と SMB3 のゲスト アクセスが無効になっている - Windows Server | Microsoft Learn
https://learn.microsoft.com/ja-jp/troubleshoot/windows-server/networking/guest-access-in-smb2-is-disabled-by-default