netatalk を docker コンテナ化して TimeMachine バックアップ先にしてみた

# netatalk を docker コンテナ化して TimeMachine バックアップ先にしてみた

## 目的

- macOS Sierra にしてから netatalk ごしの TimeMachine バックアップが取れてないような感じ…
    - 正確に書くと、最初の FullBackup は取れるが、その後の 差分バックアップ が取れない
- 現在 Host OS は Ubuntu14.04 ちょっと古いがすぐに Host 上の netatalk のバージョンアップはしづらい
- docker で最新バージョンにして試してみよう(切り分け)

## netatalk とは

- 簡単に言うと Unixマシン(Linuxなど) を TimeMachine のバックアップ先として利用できるようにするソフト
  - https://ja.wikipedia.org/wiki/Netatalk
  - Apple Talk 時代からある割りと歴史のあるソフトです(おっさん乙)

## 対象

- netatalk を TimeMachine バックアップ先として利用されてる方、したい方
- Host と netatalk 部分をコンテナで分離して管理したい方
  - たぶん samba とか他のサービスにも応用可能と思われる

## 環境

HostOS:

```shell-session
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"

$ uname -r
3.13.0-24-generic
```
```shell-session
$ docker version
Client:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 21:44:32 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.3
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   6b644ec
 Built:        Wed Oct 26 21:44:32 2016
 OS/Arch:      linux/amd64
```
```shell-session
$ sudo dpkg -l netatalk
[sudo] password for hirofumi:
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                 Version         Architecture    Description
+++-====================-===============-===============-==============================================
ii  netatalk             2.2.2-1ubuntu2  amd64           AppleTalk user binaries
```

## リファレンス

- https://docs.docker.com/engine/reference/commandline/run/
- https://docs.docker.com/engine/installation/linux/ubuntulinux/
  - 必要に応じて docker のバージョンアップを実行します
- https://docs.docker.com/engine/userguide/networking/
  - ネットワークの設定も適宜
  - 今回は Isolated Network で試しています
- http://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af
- https://github.com/docker/docker/issues/2174
- https://github.com/docker/docker/issues/15306

## 手順

### 0. 事前情報収集

- ポート確認

```shell-session
$ sudo su -
root# cat /etc/services | grep afpovertcp
afpovertcp      548/tcp                         # AFP over TCP
afpovertcp      548/udp
```
```shell-session
root# lsof -iTCP -P | grep afpd
afpd      11498            root    4u  IPv4 207626697      0t0  TCP *:548 (LISTEN)
afpd      11502        hirofumi    4u  IPv6 207632827      0t0  TCP localhost:56018->localhost:4700 (ESTABLISHED)
afpd      11502        hirofumi   11u  IPv4 207625023      0t0  TCP fs1:548->mba:51302 (ESTABLISHED)
```

- IPv6 forwarding enabled (issues/2174)

```shell-session
root# grep forward /etc/sysctl.conf | grep -v ^#
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
```

- コンテナ名のユニーク確認

```shell-session
root# docker ps -a | grep netatalk
root#
```

### 1. ホストOS 上の netatalk をいったん止めます

```shell-session
root# service netatalk stop
Stopping Netatalk Daemons: afpd cnid_metad papd timelord atalkd.
```

### 2. 最新の ubuntu コンテナを立てる

- ホストOS 上の /mnt/export/Timemachine99 を コンテナ 上の /Timemachine99 にマウントします

```shell-session
root# mkdir /mnt/export/TimeMachine99
```
- クライアントから接続するユーザ権限に付け替えます

```shell-session
root# chown hirofumi: /mnt/export/TimeMachine99
```
- コンテナの作成

```shell-session
root# docker pull ubuntu:latest

root# docker images ubuntu
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              latest              88f79970fa20        3 weeks ago         127.2 MB

root# container_name='netatalk01'
root# echo $container_name
netatalk01

root# docker network ls | grep isolated_nw
23f5539f9f5e        isolated_nw         bridge              local

root# docker run -itd --name $container_name \
-v /mnt/export/TimeMachine99:/TimeMachine99 \
-p 0.0.0.0:548:548 \
--network=isolated_nw \
-t ubuntu:latest /bin/bash

root# # docker network inspect isolated_nw | jq .[].Containers | less
{
  "cfa8fff637853d3ea4f7822951355a2f06a2c020d3c62377cf3a40451cf59c4f": {
    "IPv6Address": "",
    "IPv4Address": "172.19.0.2/16",
    "MacAddress": "02:42:ac:13:00:02",
    "EndpointID": "31823ae5ee8da43dfc3b8bc52c752d4589af4419099b914cfb124e055c196d3b",
    "Name": "netatalk01"
  }
}

root# ping -w 3  172.19.0.2
PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
64 bytes from 172.19.0.2: icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from 172.19.0.2: icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 172.19.0.2: icmp_seq=3 ttl=64 time=0.067 ms
64 bytes from 172.19.0.2: icmp_seq=4 ttl=64 time=0.065 ms

root# docker attach netatalk01

root@cfa8fff63785:/# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"

root@cfa8fff63785:/# apt-get update -y
root@cfa8fff63785:/# apt-get upgrade -y
```

- コンテナ内に OS 展開するところまでは終わりました

### 3. コンテナ内に netatalk をいれる

```shell-session
root@cfa8fff63785:/# apt-get install vim -y
root@cfa8fff63785:/# apt-get install netatalk -y
```
- 若干新しくなりましたね

```shell-session
root@cfa8fff63785:/# dpkg -l netatalk
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                       Version            Architecture       Description
+++-==========================-==================-==================-==========================================================
ii  netatalk                   2.2.5-1            amd64              AppleTalk user binaries
```

- 最終行に足す

```shell-session
root@cfa8fff63785:/# vim /etc/netatalk/AppleVolumes.default

/TimeMachine99  "TM-for-MBA-on-docker"      options:usedots,upriv,tm ea:ad allow:hirofumi volsizelimit:300000
```
- 最終行に足す

```shell-session
root@cfa8fff63785:/# vim /etc/netatalk/afpd.conf

- -tcp -noddp -uamlist uams_guest.so,uams_dhx.so,uams_dhx2.so -nosavepassword
```

- マウントポイント/バックアップ保存先の確認

```shell-session
root@cfa8fff63785:/# ls -al /TimeMachine99
total 8
drwxr-xr-x  2 1002 1002 4096 Nov  8 14:38 .
drwxr-xr-x 45 root root 4096 Nov  8 16:14 ..
```

- Host 上のユーザの UID GID の確認

```shell-session
root# grep hirofumi /etc/passwd
hirofumi:x:1002:1002::/home/hirofumi:/bin/bash

root# grep 1002 /etc/group
hirofumi:x:1002
```
> UID: 1002
> GID: 1002

- コンテナ内にユーザの追加
  - ホスト上の netatalk 運用とユーザを合わせました

```shell-session
root@cfa8fff63785:/# groupadd -g 1002 hirofumi

root@cfa8fff63785:/# useradd -m -u 1002 -g hirofumi hirofumi

root@cfa8fff63785:/# passwd hirofumi
New password:
Retype new password:
passwd: password updated successfully

root@cfa8fff63785:/# ls -al /TimeMachine99
total 8
drwxr-xr-x  2 hirofumi hirofumi 4096 Nov  8 14:38 .
drwxr-xr-x 46 root     root     4096 Nov  8 16:21 ..
```

### 4. コンテナ内で netatalk サービスの開始

```shell-session
root@cfa8fff63785:/# service netatalk start
Starting Netatalk services (this will take a while):  cnid_metad afpd.
```

### 5. バックアップ先の登録 on mac

```shell-session
% sudo tmutil setdestination -p afp://hirofumi@192.168.100.5/TM-for-MBA-on-docker
Password:
Destination password:
```
```shell-session
% tmutil destinationinfo
====================================================
Name          : TM-for-MBA-on-docker
Kind          : Network
URL           : afp://hirofumi@192.168.100.5/TM-for-MBA-on-docker
ID            : BDD304C8-5B3A-40F4-BF9A-45B3E1BA1357
```

### 6. バックアップ開始、ステータス確認

```shell-session
% tmutil startbackup --auto
% tmutil status
Backup session status:
{
    BackupPhase = MountingBackupVol;
    ClientID = "com.apple.backupd";
    DateOfStateChange = "2016-11-08 17:09:50 +0000";
    DestinationID = "BDD304C8-5B3A-40F4-BF9A-45B3E1BA1357";
    Percent = "-1";
    Running = 1;
    Stopping = 0;
}
```
```shell-session
% tmutil status
Backup session status:
{
    BackupPhase = Copying;
    ClientID = "com.apple.backupd";
    DateOfStateChange = "2016-11-08 17:11:56 +0000";
    DestinationID = "BDD304C8-5B3A-40F4-BF9A-45B3E1BA1357";
    DestinationMountPoint = "/Volumes/Time Machine Backups";
    FirstBackup = 1;
    Percent = "7.019195447394897e-07";
    Progress =     {
        "_raw_totalBytes" = 95890477056;
        bytes = 74786;
        files = 1;
        totalBytes = 105479524761;
        totalFiles = 2007952;
    };
    Running = 1;
    Stopping = 0;
    "_raw_Percent" = "7.799106052660996e-07";
}
```

- とりあえずバックアップは始まりました。

### 7. コンテナからデタッチしてイメージとして保存する

- コンテナを起動したままデタッチしてホストOSのシェルに戻るには

> ctrl + p => ctrl +q

を押下します

- イメージに保存しておくと後で再利用が容易になります

```shell-session
root# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
cfa8fff63785        ubuntu:latest       "/bin/bash"         49 minutes ago      Up 21 minutes       0.0.0.0:548->548/tcp   netatalk01

root# docker commit netatalk01 hirofumi/netatalk01-20161109
sha256:df1c3ae87e9fce88bc0c74959fff2f3a8538d3177447f61ee4ee02aa61ebc92e

root# docker images | grep netatalk
hirofumi/netatalk01-20161109   latest              df1c3ae87e9f        12 seconds ago      375.6 MB
```

### 8. いったん終了

### 9. P.S.

- MBA は朝になったら持ち出すので最初の Full Backup を取るには土日を待つしかないんでした。
- 据え置きの Mac Mini でもバックアップ先にすべく作ったイメージで別コンテナを立てることにします。

#### 9-1. 既存のコンテナを止めます

```shell-session
root# docker stop netatalk01
```

#### 9-2. ホスト上に新たなバックアップ先ディレクトリを作成

```shell-session
root# mkdir /mnt/export/TimeMachine98
root# chown hirofumi: /mnt/export/TimeMachine98
```

#### 9-3. イメージから追加で TimeMachine98 をマウントしたコンテナを起動

```shell-session
root# docker run -itd --name netatalk02 \
-v /mnt/export/TimeMachine99:/TimeMachine99 \
-v /mnt/export/TimeMachine98:/TimeMachine98 \
-p 0.0.0.0:548:548 \
--network=isolated_nw \
-t hirofumi/netatalk01-20161109 /bin/bash
```
```shell-session
root# docker ps
CONTAINER ID        IMAGE                          COMMAND             CREATED             STATUS              PORTS                  NAMES
1aec5fd3ad73        hirofumi/netatalk01-20161109   "/bin/bash"         5 seconds ago       Up 3 seconds        0.0.0.0:548->548/tcp   netatalk02
```
```shell-session
root# docker network inspect isolated_nw | jq .[].Containers
{
  "1aec5fd3ad7307503a106a91d0670e0773f0ee582360094717819d2b5236b761": {
    "IPv6Address": "",
    "IPv4Address": "172.19.0.2/16",
    "MacAddress": "02:42:ac:13:00:02",
    "EndpointID": "6d0e555acd84965a156da02ad51026ed5923941bec9ea524fcd5b106c63d4e83",
    "Name": "netatalk02"
  }
}
```
#### 9-4. アタッチします

```shell-session
root# docker attach netatalk02
```

#### 9-5. netatalk の設定を追加します

```shell-session
root@1aec5fd3ad73:/# vi /etc/netatalk/AppleVolumes.default

/TimeMachine98  "TM-for-macmini-on-docker"      options:usedots,upriv,tm ea:ad allow:hirofumi volsizelimit:300000
```

#### 9-6. サービス再起動

```shell-session
root@1aec5fd3ad73:/# service netatalk restart
```

#### 9-7. バックアップ開始

```shell-session
macOS% sudo tmutil setdestination -p afp://hirofumi@192.168.100.5/TM-for-macmini-on-docker

macOS% tmutil destinationinfo
====================================================
Name          : TM-for-macmini-on-docker
Kind          : Network
URL           : afp://hirofumi@192.168.100.5/TM-for-macmini-on-docker
ID            : 234C7FCE-7C9D-4975-9226-58113E2EDCB9
```
```shell-session
macOS% tmutil startbackup --auto

macOS% tmutil status
Backup session status:
{
    BackupPhase = Starting;
    ClientID = "com.apple.backupd";
    DateOfStateChange = "2016-11-10 15:08:02 +0000";
    DestinationID = "234C7FCE-7C9D-4975-9226-58113E2EDCB9";
    Percent = "-1";
    Running = 1;
    Stopping = 0;
}
```
```shell-session
tmutil status
Backup session status:
{
    BackupPhase = Copying;
    ClientID = "com.apple.backupd";
    DateOfStateChange = "2016-11-10 15:08:49 +0000";
    DestinationID = "234C7FCE-7C9D-4975-9226-58113E2EDCB9";
    DestinationMountPoint = "/Volumes/Time Machine Backups";
    FirstBackup = 1;
    Percent = 0;
    Progress =     {
        "_raw_totalBytes" = 109091217408;
        bytes = 0;
        files = 0;
        totalBytes = 120000339148;
        totalFiles = 939306;
    };
    Running = 1;
    Stopping = 0;
    "_raw_Percent" = 0;
}
```

#### 9-8. 様子見

- これでだめなら最新の netatalk をソースからインストールですかね。。