プログラミングとかLinuxとかの備忘録

プログラミング、Linuxでハマった箇所や環境構築のメモ

DockerでOpenVPNサーバを動かす

ホスト環境

$ cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

$ docker --version
Docker version 1.13.1, build 8633870/1.13.1
$ docker-compose --version
docker-compose version 1.18.0, build 8dd22a9

Dockerfile

公式のalpine3.9のイメージにopenvpnとeasyrsaをインストールするぐらい

FROM alpine:3.9

RUN apk --update --no-cache --no-progress add \
        openvpn \
        easy-rsa \
        && \
    rm -rf /var/cache/apk/*

COPY run.sh /
CMD [ "/run.sh" ]

サービス起動用のスクリプトrun.shを作成

下記のスクリプトrun.shとして作成する。
--push "route 192.168.1.0 255.255.255.0"OpenVPNサーバのネットワークに応じて変更する。

#!/bin/sh

# ERROR: Cannot open TUN/TAP dev /dev/net/tun: No such file or directory (errno=2)が出ないようにするため
mkdir -p /dev/net
if [ ! -c /dev/net/tun ]; then
    mknod /dev/net/tun c 10 200
fi

# クライアント用のネットワーク
OVPN_SERVER=${OVPN_SERVER:-10.8.0.0}

# `ip addr`コマンドの結果からネットワークデバイス名を抽出する
OVPN_NATDEVICE=$(ip addr | awk 'match($0, /global [[:alnum:]]+/) {print substr($0, RSTART+7, RLENGTH)}')
if [ -z "${OVPN_NATDEVICE}" ]; then
    ip addr
    echo "Failed to extract OVPN_NATDEVICE."
    exit 1
fi

# iptablesの設定
iptables -t nat -C POSTROUTING -s ${OVPN_SERVER}/24 -o ${OVPN_NATDEVICE} -j MASQUERADE || {
    iptables -t nat -A POSTROUTING -s ${OVPN_SERVER}/24 -o ${OVPN_NATDEVICE} -j MASQUERADE
}

# OpenVPNサーバの起動
/usr/sbin/openvpn \
    --cd ${OVPN_DIR:-/etc/openvpn} \
    \
    --port  ${OVPN_PORT:-1194} \
    --proto ${OVPN_PROTO:-udp4} \
    --dev   ${OVPN_DEV:-tun} \
    \
    --ca    ${OVPN_CA:-"/opt/easy-rsa/pki/ca.crt"} \
    --cert  ${OVPN_CERT:-"/opt/easy-rsa/pki/issued/server.crt"} \
    --key   ${OVPN_KEY:-"/opt/easy-rsa/pki/private/server.key"} \
    --dh    ${OVPN_DH:-"/opt/easy-rsa/pki/dh.pem"} \
    --tls-auth /opt/easy-rsa/pki/ta.key 0 \
    \
    --server ${OVPN_SERVER} ${OVPN_SERVER_MASK:-255.255.255.0} \
    --ifconfig-pool-persist ipp.txt \
    --push "redirect-gateway def1" \
    --push "route ${OVPN_SERVER} 255.255.0.0" \
    --push "route 192.168.1.0 255.255.255.0" \
    --push "dhcp-option DNS 8.8.8.8" \
    \
    --keepalive 10 120 \
    --user nobody \
    --group nobody \
    --persist-key \
    --persist-tun \
    \
    --status openvpn-status.log \
    --verb ${OVPN_VERB:-3} \
    \
    --compress lz4 \
    --tun-mtu 1500 \
    --mssfix 1460

docker-compose.ymlの作成

  • WANには1194番ポートはさらさずに54321番ポートでアクセスするようにする
    • WAN → ルータ54321 → Dockerホスト54321 → Dockerコンテナ1194
  • ホスト再起動時に自動起動するようにする(restart: unless-stopped
version: '3.2'
services:
  openvpn:
    build: .
    image: openvpn
    cap_add:
      - NET_ADMIN
    ports:
      - "54321:1194/udp"
    volumes:
      - ./easy-rsa:/opt/easy-rsa
    working_dir: /opt/easy-rsa
    environment:
      - OVPN_PORT=1194
    restart: unless-stopped

OpenVPNサーバの設定

$ docker-compose build
$ docker-compose up -d

でコンテナを起動した状態で、マウントしている/opt/easy-rsa内でeasyrsaで証明書とかを生成する。

コンテナ内に入り、/opt/easy-rsa内に入り作業する。

$ docker-compose exec openvpn sh

# cd /opt/easy-rsa

PKIの初期化

# /usr/share/easy-rsa/easyrsa init-pki

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /opt/easy-rsa/pki

CA(認証局)構築

# /usr/share/easy-rsa/easyrsa build-ca nopass

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018
Generating RSA private key, 2048 bit long modulus (2 primes)
...............+++++
.........................+++++
e is 65537 (0x010001)
Can't load /opt/easy-rsa/pki/.rnd into RNG
140591198460776:error:2406F079:random number generator:RAND_load_file:Cannot open file:crypto/rand/randfile.c:98:Filename=/opt/easy-rsa/pki/.rnd
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: .

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/opt/easy-rsa/pki/ca.crt

Diffie-Helllmanパラメータの生成

# /usr/share/easy-rsa/easyrsa gen-dh

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
.............+.......
.....................
..........+..........
+....................
.....................
.......+.......+.....
DH parameters of size 2048 created at /opt/easy-rsa/pki/dh.pem

サーバー鍵の生成

# /usr/share/easy-rsa/easyrsa build-server-full server nopass

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018
Generating a RSA private key
...+++++
....+++++
writing new private key to '/opt/easy-rsa/pki/private/server.key.XXXXjcFHin'
-----
Using configuration from /usr/share/easy-rsa//safessl-easyrsa.cnf
Can't open /opt/easy-rsa/pki/index.txt.attr for reading, No such file or directory
140106217700200:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:72:fopen('/opt/easy-rsa/pki/index.txt.attr','r')
140106217700200:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:79:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Jan 29 14:12:50 2022 GMT (1080 days)

Write out database with 1 new entries
Data Base Updated

tls-auth用の鍵の生成

# openvpn --genkey --secret pki/ta.key

CRLファイルの生成

# /usr/share/easy-rsa/easyrsa gen-crl

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018
Using configuration from /usr/share/easy-rsa//safessl-easyrsa.cnf

An updated CRL has been created.
CRL file: /opt/easy-rsa/pki/crl.pem

クライアント鍵・設定ファイルを生成

<CLIENT-NAME>の部分にクライアント名に入れて実行する。

$ /usr/share/easy-rsa/easyrsa build-client-full <CLIENT-NAME> nopass

Using SSL: openssl OpenSSL 1.1.1a  20 Nov 2018
Generating a RSA private key
.................................................................................................+++++
..............................................................................+++++
writing new private key to '/opt/easy-rsa/pki/private/<CLIENT-NAME>.key.XXXXeDaKmJ'
-----
Using configuration from /usr/share/easy-rsa//safessl-easyrsa.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'<CLIENT-NAME>'
Certificate is to be certified until Jan 29 14:20:40 2022 GMT (1080 days)

Write out database with 1 new entries
Data Base Updated

下記の内容で<CLIENT-NAME>.ovpnを作成する。
<SERVER-IP>にはOpenVPNサーバのグローバルIPかホスト名を入れる。

client
dev tun
proto udp
remote <SERVER-IP> 54321
resolv-retry infinite
nobind
persist-key
persist-tun
auth-nocache
verb 3
key-direction 1
compress lz4
tun-mtu 1500
mssfix 1460
<ca>
  pki/ca.crtの内容をコピペ
</ca>
<cert>
  pki/issued/<CLIENT-NAME>.crtの内容をコピペ
</cert>
<key>
  pki/private/<CLIENT-NAME>.keyの内容をコピペ
</key>
<tls-auth>
  pki/ta.keyの内容をコピペ
</tls-auth>

作成したovpnをクライアントにインポートすれば接続できた。

CentOS7にdocker-ce、docker-composeをインストールする

CentOSのデフォルトのDockerが1.13.1でFROM前のARGが使えなかったので、新しいのDockerを入れる。

$ sudo yum list docker
docker.x86_64    2:1.13.1-88.git07f3374.el7.centos    extras

ホスト環境

$ uname -sr
Linux 3.10.0-957.1.3.el7.x86_64

$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

Dockerの削除

yumでDockerを入れていた場合は削除する

$ sudo yum -y remove docker docker-common

Dockerのインストール

リポジトリを追加

$ sudo yum -y install yum-utils
$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

docker-ceをインストール

$ sudo yum -y install docker-ce

おそらくdockerグループが自動作成されているはずなので、ユーザをdockerグループに追加する

$ cat /etc/group | grep docker
dockerroot:x:983:
docker:x:979:

$ sudo gpasswd -a <USER> docker
$ id
uid=1000(<USER>) gid=1000(<USER>) groups=1000(<USER>),10(wheel),979(docker)

デーモンを起動

$ sudo systemctl start docker
$ sudo systemctl enable docker

ログインし直せば使える

$ docker --version
Docker version 18.09.1, build 4c52b90

docker-composeのインストール

リポジトリがなさそうだったので公式(Install Docker Compose | Docker Documentation)の通りに下記コマンドでインストールする。

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod a+x /usr/local/bin/docker-compose

$ docker-compose --version
docker-compose version 1.23.2, build 1110ad01

KerasがGPUを認識できなくなった

2018年12月時点ではGPUで動いていたコードが2019年1月になるとGPUを認識できずにCPUで動くようになっていた。
Ubuntu自体のアップデート、Pythonパッケージのアップデートをしていた気がするのでそれが原因か?
記事執筆時点(2019年1月21日)での各バージョンは下記の通り。

  • Ubuntu 18.04.1 LTS
  • Docker
    • docker-ce/bionic,now 18.06.1~ce~3-0~ubuntu amd64
    • nvidia-docker2/now 2.0.3+docker18.06.1-1 all
  • pip
    • Keras==2.0.4
    • tensorflow-gpu==1.12.0

学習を開始すると

failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

が出て学習自体は動くが、GPUを使っていないため遅い。

GPUドライバの再インストール

最終的にはGPUドライバの再インストールはおそらく不要?

nvidia-396/now 396.54-0ubuntu0~gpu16.04.1 amd64

gpu16.04.1部分がUbuntuのバージョンを16.04からdist-upgradeしたときの残骸?のような感じで怪しいのでGPUドライバを再インストールしてみる。

削除後、一応再起動。

$ sudo apt remove nvidia-396
$ sudo apt autoremove

$ sudo reboot

アップデート後、最新版を確認してみる

$ sudo apt update
$ sudo apt search nvidia
nvidia-396/now 396.54-0ubuntu0~gpu16.04.1 amd64 [設定が残存]
  (none)

[設定が残存]になっているので

$ sudo apt purge nvidia-396
$ sudo reboot

完全に消えたのでppaを追加してインストールする。
nvidia-396はリポジトリにはなかったので、代わりにnvidia-390をインストールする。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update
$ sudo apt install nvidia-390

CUDA_VISIBLE_DEVICESが原因

コードのはじめの方でGPUが一枚しかないのに

os.environ["CUDA_VISIBLE_DEVICES"] = "1"

としていたことが原因。

os.environ["CUDA_VISIBLE_DEVICES"] = "0"

やCUDA_VISIBLE_DEVICESを設定しなければ問題なくGPUで動いた。

Raspberry Piとウェブカメラでmotionを使う

motionをインストール

$ sudo apt-get -y install motion

motionの設定

stream_localhost on
webcontrol_localhost on

stream_localhost off
webcontrol_localhost off

に変更する。

動作確認

USBカメラの確認

$ lsusb 
Bus 001 Device 005: ID 046d:082c Logitech, Inc. 

起動する

$ sudo motion -n
[0:motion] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
[0:motion] [NTC] [ALL] motion_startup: Motion 4.0 Started
[0:motion] [NTC] [ALL] create_path: creating directory /var/log/motion
[0:motion] [NTC] [ALL] motion_startup: Logging to file (/var/log/motion/motion.log)

Ctrl+Cで止めて、 /var/lib/motionに画像が保存るはずなのでsftp等で確認する。

Raspbian StretchをインストールしてSSHログインするまで

Raspbianをダウンロード

Download Raspbian for Raspberry Piから
Raspbian Stretch Lite (2018-11-13-raspbian-stretch-lite.img)をダウンロードする

Raspbianの書き込み

ddで書き込む

$ sudo fdisk -l
...
ディスク /dev/sdc: 14.5 GiB, 15548284928 バイト, 30367744 セクタ
ディスク型式: Flash Reader    
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: dos
ディスク識別子: 0x00000000

デバイス   起動 開始位置 終了位置   セクタ サイズ Id タイプ
/dev/sdc1  *        2048 30367743 30365696  14.5G  c W95 FAT32 (LBA)


$ sudo dd bs=64MB if=2018-11-13-raspbian-stretch-lite.img of=/dev/sdc
29+1 レコード入力
29+1 レコード出力
1866465280 bytes (1.9 GB, 1.7 GiB) copied, 411.178 s, 4.5 MB/s

sshd有効化

デフォルトでsshdが自動機能しないためSSHログインはできない。

How to enable SSH on Raspbian without a screen - howchoo
の通り下記コマンドを試したがssh: connect to host 192.168.1.17 port 22: Connection refusedで接続できなかった。

$ sudo fdisk -l
デバイス   起動 開始位置 終了位置   セクタ サイズ Id タイプ
/dev/sdc1           8192    98045    89854  43.9M  c W95 FAT32 (LBA)
/dev/sdc2          98304 30367743 30269440  14.4G 83 Linux

$ sudo mount /dev/sdc2 /mnt/pi
$ cd /mnt/pi/boot
$ sudo touch ssh

諦めてキーボード、ディスプレイを接続して下記コマンドで有効化する。

$ sudo systemctl start sshd
$ sudo systemctl enable sshd

SSHでログイン

ルータのDHCP割り当て状態からRaspberry PiMACアドレスB8:27:EB:??:??:??)に割り当てられているIPを調べる

Yamaha NVR510の場合はshow status dhcpでホスト名まで表示された

  Leased address: 192.168.1.17
(type) Client ID: (01) b8 27 eb 60 59 21
       Host Name: raspberrypi
 Remaining lease: 2days 23hours 59min. 31secs.

下記ユーザ名・パスワードでSSHログインする
- ユーザー名: pi - パスワード: raspberry


その他の設定

IP固定

インターフェース名の確認

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.17/24 brd 192.168.1.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::11cb:3d7e:78f0:2ead/64 scope link 
       valid_lft forever preferred_lft forever

/etc/dhcpcd.confの編集

interface eth0
static ip_address=192.168.1.27/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

再起動

$ sudo reboot

Ubuntu16.04でnvidia-dockerを動かす

構成

初期設定

ネットワーク

$ sudo apt-get -y install resolvconf

$ sudo nmcli con mod eno1 ipv4.method manual
$ sudo nmcli con mod eno1 ipv4.address 192.168.1.23/24
$ sudo nmcli con mod eno1 ipv4.dns 192.168.1.1
$ sudo nmcli con mod eno1 ipv4.gateway 192.168.1.1

$ sudo nmcli con down eno1 && sudo nmcli con up eno1

アップデート

$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo apt-get -y dist-upgrade

OpenSSHのインストール

$ sudo apt-get -y install openssh-server

$ sudo systemctl start sshd
$ sudo systemctl enable sshd

CUDA

確認

以下のコマンドで,何も出てこないことを確認する

$ sudo dpkg -l | grep nvidia
$ sudo dpkg -l | grep cuda

Nvidiaドライバのインストール

リポジトリ(Proprietary GPU Drivers : “Graphics Drivers” team)
を登録して,ドライバをインストールする
途中で,secure bootを無効にするかを聞かれたが,無効にせずに続行した

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt-get update

$ sudo apt-get -y install nvidia-387

再起動し,GPUが認識されているかを確認

$ sudo reboot

$ nvidia-smi
Sat Dec  9 10:19:09 2017       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.34                 Driver Version: 387.34                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  Off  | 00000000:01:00.0  On |                  N/A |
|  0%   37C    P8     6W / 156W |     91MiB /  6071MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1130      G   /usr/lib/xorg/Xorg                            89MiB |
+-----------------------------------------------------------------------------+

dockerのインストール

Ubuntu公式リポジトリdocker.ioではnvidia-dockerを実行できない (docker-engine, docker-ce, docker-eeのいずれかのパッケージが依存関係として必要) ので、Get Docker CE for Ubuntu | Docker Documentation の通りにインストールする

$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update

$ sudo apt-get -y install docker-ce

nvidia-dockerのインストール

GitHub - NVIDIA/nvidia-docker: Build and run Docker containers leveraging NVIDIA GPUsの通りにインストールする

$ sudo apt-get -y install curl

$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
$ sudo apt-get update

$ sudo apt-get install -y nvidia-docker2
$ sudo pkill -SIGHUP dockerd

テスト(nvidia-docker run --rm nvidia/cuda nvidia-smiでもいける)

$ docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
Unable to find image 'nvidia/cuda:latest' locally
latest: Pulling from nvidia/cuda
660c48dd555d: Pull complete
4c7380416e78: Pull complete
421e436b5f80: Pull complete
e4ce6c3651b3: Pull complete
be588e74bd34: Pull complete
f597507b3c37: Pull complete
9c5d4127a23d: Pull complete
398bf259fcdc: Pull complete
4f4092762618: Pull complete
94130a21e154: Pull complete
Digest: sha256:954c82d2d060f38de13b3d7933b7e1549b25330cc6412008dc1253f3c148448d
Status: Downloaded newer image for nvidia/cuda:latest
Sat Dec  9 01:59:36 2017       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.34                 Driver Version: 387.34                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 106...  Off  | 00000000:01:00.0  On |                  N/A |
|  0%   37C    P8     6W / 156W |     91MiB /  6071MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

Debian StretchでNFSサーバを動かす

インストール

$ sudo apt -y install nfs-kernel-server

共有ディレクトリの設定

NFSv4で共有するように/etc/exportsを編集する。
/srv/nfs4NFSのルートにし、shareを公開する。

$ sudo vim /etc/exports
/srv/nfs4         192.168.1.0/24(rw,async,fsid=0,crossmnt,no_root_squash)
/srv/nfs4/share   192.168.1.0/24(rw,async,no_root_squash)

共有ディレクトリのバインドマウント

ディレクトリ作成

$ sudo mkdir -p /srv/nfs4/share

/etc/fstabの編集、マウント

$ sudo vim /etc/fstab
/mnt/hdd    /srv/nfs4/share    none    bind    0 0

$ sudo mount -a

サービス起動

$ sudo systemctl start nfs-server
$ sudo systemctl enable nfs-server

公開状態の確認

$  sudo exportfs
/srv/nfs4       192.168.1.0/24
/srv/nfs4/share
                192.168.17.0/24

クライアント側からは下記コマンドでマウントできる

$ sudo mount.nfs <NFSサーバIP>:/ /mnt

$ ls /mnt
share