- 投稿日:2019-12-15T23:59:27+09:00
Naumachiaを使ったペネトレーションテストのトレーニング環境構築
本記事は、NTTコミュニケーションズ Advent Calendar 2019 15日目の記事です。
昨日は @Mahito さんの記事、 保育園にChaos Engineeringを提案した話 でした。はじめに
先日公開されたNTTコミュニケーションズの開発者ブログの記事にもあったように、NTTコミュニケーションズグループではグループ社員を対象としたセキュリティコンテスト「ComCTF」を開催しています。
私は決勝で出題した「Pentest」という問題を作問しました。
Pentest(ペンテスト)は、ペネトレーションテストと呼ばれるセキュリティテストの略称で、明確な意図を持った攻撃者にその目的が達成されてしまうかを検証します。 1この問題は仮想の企業ネットワークに侵入し、複数のサーバの脆弱性を悪用、最終的に重要データが保存されているサーバから情報を入手できるかを問う問題で、まさに攻撃者の気持ちになって重要なデータを入手するという目的が達成可能かどうかを検証してもらう、ペネトレーションテストをしてもらう問題でした。
今回、この問題の基盤を作るにあたり、Dockerを使ってペネトレーションテストのトレーニング環境を構築できる Naumachia と呼ばれるOSSを使用しました。
この記事では、Naumachiaの概要と構築方法、この基盤を使ったペネトレーションテストのトレーニング環境構築について紹介します。
Naumachia とは
Naumachiaは、Dockerを使ってクローズドネットワークと脆弱なサーバを構築できるOSSです。
私がこのOSSを知ったきっかけは、Texas A&M University が主催する TAMUctf 19 と呼ばれるCTFです。
NetworkPentest
というジャンルの問題の基盤にこの Naumachia が使用されています。なお、このCTFの問題はGitHubで公開されているので興味がある方は見てみてください。
https://github.com/tamuctf/TAMUctf-2019
Naumachia には、以下の機能が実装されています。
- ユーザごとにトレーニング用のDockerコンテナとネットワークを作成、管理
- トレーニング環境を他のユーザの環境と分離
- OpenVPNを使ったトレーニング環境ネットワークへのL2レベルの接続の提供
これにより、以下のようなインターネットからVPNの接続情報を持つユーザのみアクセス可能な専用のトレーニング環境を構築できます。
例えば、Drupalの任意コード実行の脆弱性(CVE-2018-7600)を使ってシステムに侵入できるか試すような問題を作ろうとした場合、インターネットからアクセスできる問題サーバを作ろうとすると、インターネット上の脆弱性のスキャンに引っかかり、最悪サーバが踏み台にされる可能性もあります。
Naumachia を使えば、インターネットからはVPNの接続情報を持つユーザのみ問題に挑戦できるので、そのようなリスクなく作問できます。また、L2レベルでのアクセスも提供してくれるので、ARPスプーフィングにような同一LAN内で行われる攻撃手法を試すような問題も作ることができます。
詳しい機能や仕組みは、Naumachia のREADME に書いてあるので、こちらを読むと良いと思います。
Naumachia の構築
ここからは Naumachia の構築手順を紹介します。
動作環境
READMEには、
Obtain a Linux server (tested on Ubuntu 16.04 and 18.04)
と書いてあるので、使うOSは Ubuntu 18.04 がベストでしょう。
しかし、今回のコンテストでは諸事情ありCentOS 7を使ったので、CentOS 7 で検証した構築手順を書いておきます。構築手順を検証したOSの情報は以下のとおりです。
# uname -a Linux localhost.localdomain 3.10.0-957.21.3.el7.x86_64 #1 SMP Tue Jun 18 16:35:19 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core)Naumachia のインストール準備
Naumachiaを構築するには、
docker
,docker-compose
,Python3
,pip3
が必要となるので、これらをまずインストールする必要がある。
その後、GitHubにあるNaumachiaのリポジトリからソースコードをCloneし、requirements.txt
に書かれているPython3のライブラリをインストールする。dockerのインストール
# yum install -y yum-utils device-mapper-persistent-data lvm2 # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # yum install -y docker-ce docker-ce-cli containerd.io # systemctl start docker # systemctl enable dockerdocker-composeのインストール
# curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose # chmod +x /usr/local/bin/docker-composePython3.6、pip3のインストール
# yum install -y https://centos7.iuscommunity.org/ius-release.rpm # yum install python36u python36u-libs python36u-devel python36u-pipGitHubからソースコードをCloneする
# git clone https://github.com/nategraf/Naumachia.gitPython3のライブラリをインストール
# cat requirements.txt jinja2==2.10.1 PyYAML==4.2b4 requests==2.21.0 nose2==0.8.0 pytest==4.5.0 hypothesis==4.23.5 # pip3 install -r requirements.txtNaumachia のセットアップ
トレーニング用のDockerコンテナとネットワークの準備
Naumachiaでユーザに対して提供するトレーニング用のDockerコンテナとネットワークは、
docker-compose.yml
で定義します。
Naumachia起動後、OpenVPNでユーザが接続してくると、このdocker-compose.yml
をもとに自動でdocker-composeが実行されトレーニングの環境が構築されます。今回の説明では、Naumachiaの問題集 (nategraf/Naumachia-challenges) から、
example
というチャレンジを動かしてみます。問題集のGitHubのリポジトリをCloneし、Naumachiaディレクトリ内の
challenges
ディレクトリにexample
チャレンジに必要なファイルをコピーします。# git clone https://github.com/nategraf/Naumachia-challenges # mkdir Naumachia/challenges # cp -r Naumachia-challenges/example Naumachia/challengesちなみに、
example
のdocker-compose.yml
は以下のとおりです。
bob
とalice
という2つのコンテナと、default
という1つのネットワークが作成されるのがわかります。docker-compose.ymlversion: '2.4' # The file defines the configuration for simple Nauachia challenge where a # sucessful man-in-the-middle (MTIM) attack (such as ARP poisoning) provides a # solution # If you are unfamiliar with docker-compose this might be helpful: # * https://docs.docker.com/compose/ # * https://docs.docker.com/compose/compose-file/ # # But the gist is that the services block below specifies two containers, which # act as parties in a vulnerable communication services: bob: build: ./bob image: naumachia/example.bob environment: - CTF_FLAG=fOOBaR restart: unless-stopped networks: default: ipv4_address: 172.30.0.2 alice: build: ./alice image: naumachia/example.alice depends_on: - bob environment: - CTF_FLAG=fOOBaR restart: unless-stopped networks: default: ipv4_address: 172.30.0.3 networks: default: driver: l2bridge ipam: driver: static config: - subnet: 172.30.0.0/28カスタマイズされたDocker libnetwork Driverのインストール・起動
上記のNaumachiaのチャレンジでは、すべてのユーザに同じ環境を提供、安全なトレーニング環境を構築するために、カスタマイズされたDocker libnetowrk driverを使用しています。
https://github.com/nategraf/l2bridge-driver
https://github.com/nategraf/static-ipam-driverこれを使うことで、デフォルトのDocker libnetowrk driverではできない以下のことが可能となります。
- 重複したIPサブネットの許可
- コンテナネットワークからインターネットへのアクセス禁止
ここでUbuntuやDebianであれば、サービスとしてDriverをインストールする方法が紹介されてますが、今回はCentOSであったため以下のようなスクリプトを作成し、無理やりDriverのプログラムを動かしました。(sysv.sh をRedHat系のOS向けに書き直す余裕はなかった…
driver_start.sh# Download the static-ipam driver to usr/local/bin if [ ! -e /usr/local/bin/l2bridge ]; then echo "[!] l2bridge driver is not installed" echo "[+] Download the l2bridge driver to usr/local/bin" curl -L https://github.com/nategraf/l2bridge-driver/releases/latest/download/l2bridge-driver.linux.amd64 -o /usr/local/bin/l2bridge chmod +x /usr/local/bin/l2bridge else echo "[*] l2bridge driver is installed" fi # Download the static-ipam driver to usr/local/bin if [ ! -e /usr/local/bin/static-ipam ]; then echo "[!] static-ipam driver is not installed" echo "[+] Download the static-ipam driver to usr/local/bin" curl -L https://github.com/nategraf/static-ipam-driver/releases/latest/download/static-ipam-driver.linux.amd64 -o /usr/local/bin/static-ipam chmod +x /usr/local/bin/static-ipam else echo "[*] static-ipam driver is installed" fi # Activate the service echo "[+] Startup the servicies" if [ ! -e /run/docker/plugins/l2bridge.sock ]; then nohup /usr/local/bin/l2bridge > /dev/null 2>&1 & echo "[*] Done: l2bridge" else echo "[!] Started l2bridge driver" fi if [ ! -e /run/docker/plugins/static.sock ]; then nohup /usr/local/bin/static-ipam > /dev/null 2>&1 & echo "[*] Done: static-ipam" else echo "[!] Started static-ipam driver" fi sleep 0.5 # Verify that it is running echo "[+] Verify that it is running" echo "" echo "[*] stat /run/docker/plugins/l2bridge.sock" stat /run/docker/plugins/l2bridge.sock # File: /run/docker/plugins/l2bridge.sock # Size: 0 Blocks: 0 IO Block: 4096 socket # ... echo "" echo "[*] stat /run/docker/plugins/static.sock" stat /run/docker/plugins/static.sock # File: /run/docker/plugins/static.sock # Size: 0 Blocks: 0 IO Block: 4096 socket # ... echo "" echo "[*] Complete!!"なお、シャットダウンするとDriverのプログラムは停止し、再起動時に立ち上がらないので、再起動時には必ずこれを実行する必要があります。
bridgeを通るパケットのフィルタリング無効
bridgeを通るパケットがフィルタ対象になっているとうまく動かないことがあるようなので、
disable-bridge-nf-iptables.sh
を実行します。disable-bridge-nf-iptables.shecho 0 > /proc/sys/net/bridge/bridge-nf-call-iptables echo 0 > /proc/sys/net/bridge/bridge-nf-call-ip6tablesconfig.yml の修正
config.example.yml
をconfig.yml
にコピーして一部を書き換えます。
書き換えるのは、challenges
の部分。
変更する点は以下のとおり。
files:
に、「トレーニング用のDockerコンテナとネットワークの準備」で作ったdocker-compose.yml
ファイルの場所を書くcommonname:
にサーバのアドレス(ドメイン、IPアドレス)を書く# [required] Configurations for each challenge challenges: # [required] An indiviual challenge config. The key is the challenge name # This should be a valid unix filename and preferably short example: # [default: 1194] The exposed external port for this challenges OpenVPN server port: 2000 # [default: [{challenge name}/docker-compose.yml] ] The compose files to which define this challenge # Paths should be relative to the challenges directory files: - example/docker-compose.yml # [default: {challenge name}.{domain}] The commonname used for the OpenVPN's certificates # This should be the domain name or ip that directs to this challenge commonname: 192.168.91.130 # [default: None] If set, the OpenVPN management interface will be opened on localhost and the given port openvpn_management_port: null # [default: None] If set, the OpenVPN server will inform the client what IPv4 address and mask to apply to their tap0 interface ifconfig_push: 172.30.0.14/28Naumachiaのビルド
configure.py
を実行すると、config.yml
に書かれている内容をもとにNaumachiaをbuildします。
これにより、Naumachiaのdocker-compose.yml
やOpenVPNの鍵や証明書、設定のファイルが自動で生成されます。# ./configure.py [INFO] Using config from /root/Naumachia/config.yml [INFO] Using easyrsa installation at /root/Naumachia/tools/EasyRSA-v3.0.6/easyrsa [INFO] Rendered /root/Naumachia/docker-compose.yml from /root/Naumachia/templates/docker-compose.yml.j2 [INFO] Configuring 'example' [INFO] Created new openvpn config directory /root/Naumachia/openvpn/config/example [INFO] Initializing public key infrastructure (PKI) [INFO] Building certificiate authority (CA) [INFO] Generating Diffie-Hellman (DH) parameters [INFO] Building server certificiate [INFO] Generating certificate revocation list (CRL) [INFO] Rendered /root/Naumachia/openvpn/config/example/ovpn_env.sh from /root/Naumachia/templates/ovpn_env.sh.j2 [INFO] Rendered /root/Naumachia/openvpn/config/example/openvpn.conf from /root/Naumachia/templates/openvpn.conf.j2また、競技用のコンテナもbuildしておきます。
# docker-compose -f ./challenges/example/docker-compose.yml build競技環境の実行
ここまでの作業を行うと、
docker-compose.yml
が自動で生成されているはずなので、buildしてupします。# docker-compose build # docker-compose up -dこの状態で
docker ps -a
で立ち上がってるコンテナを見てみると、以下のようなコンテナが立ち上がっているはずです。# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dd9e858277bd naumachia/manager "python -m app" 27 seconds ago Up 25 seconds build_manager_1 f80057d9dc2e naumachia/openvpn "/scripts/naumachia-…" 27 seconds ago Up 25 seconds 0.0.0.0:2000->1194/udp build_openvpn-example_1 86fc3709d4e3 redis:alpine "docker-entrypoint.s…" 27 seconds ago Up 26 seconds build_redis_1 a0f45e1f292a naumachia/registrar "gunicorn -c python:…" 27 seconds ago Up 26 seconds 0.0.0.0:3960->3960/tcp build_registrar_1 9d1ef7902351 alpine "/bin/true" 27 seconds ago Exited (0) 27 seconds ago build_bootstrapper_1ユーザへ配布するOpenVPN設定ファイルの生成
ユーザがOpenVPNサーバに接続し、トレーニング環境にアクセスするためには設定ファイルが必要です。
これもNaumachiaが自動で生成してくれます。生成する方法には、以下の2つの方法があります。
- registrar CLIのPythonスクリプトを使用する
- registrar serverのREST APIを使用する
3960/tcp
で待ち受けてるコンテナがそう- 認証がないので外部に公開するときは注意
今回はregistrar CLIのPythonスクリプトを使って、設定ファイルを作成、取得します。
registrar-cliを以下のように実行すると、OpenVPNの鍵、サーバ証明書、認証局の証明書を含んだOpenVPNの設定ファイルが作成できるので、これをユーザに配ります。# ./registrar-cli example add user1 # ./registrar-cli example get user1 > user1.ovpn # cat user1.ovpn client nobind dev tap remote-cert-tls server float explicit-exit-notify remote 192.168.91.130 2000 udp <key> -----BEGIN PRIVATE KEY----- (省略) -----END PRIVATE KEY----- </key> <cert> -----BEGIN CERTIFICATE----- (省略) -----END CERTIFICATE----- </cert> <ca> -----BEGIN CERTIFICATE----- (省略) -----END CERTIFICATE----- </ca> key-direction 1 cipher AES-256-CBC auth SHA256 comp-lzo構築したトレーニング環境で遊んでみる
それでは、構築したトレーニング環境にアクセスして遊んでみましょう。
検証に使用する環境
今回はユーザ側はデフォルトでOpenVPNのクライアントとペネトレーションテスト用のツールがインストールされている
Kali Linux
を使用します。# grep VERSION /etc/os-release VERSION="2018.1" VERSION_ID="2018.1"OpenVPNでトレーニング環境へ接続
生成したOpenVPNの設定ファイルを使って、Naumachia上のトレーニング環境にアクセスします。
Initialization Sequence Completed
と出れば成功です!# openvpn user1.ovpn Sun Dec 15 06:33:45 2019 OpenVPN 2.4.5 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Mar 4 2018 Sun Dec 15 06:33:45 2019 library versions: OpenSSL 1.1.0h 27 Mar 2018, LZO 2.08 Sun Dec 15 06:33:45 2019 TCP/UDP: Preserving recently used remote address: [AF_INET]192.168.91.130:2000 Sun Dec 15 06:33:45 2019 UDP link local: (not bound) Sun Dec 15 06:33:45 2019 UDP link remote: [AF_INET]192.168.91.130:2000 Sun Dec 15 06:33:45 2019 [192.168.91.130] Peer Connection Initiated with [AF_INET]192.168.91.130:2000 Sun Dec 15 06:33:46 2019 Options error: Unrecognized option or missing or extra parameter(s) in [PUSH-OPTIONS]:1: dhcp-renew (2.4.5) Sun Dec 15 06:33:46 2019 TUN/TAP device tap0 opened Sun Dec 15 06:33:46 2019 do_ifconfig, tt->did_ifconfig_ipv6_setup=0 Sun Dec 15 06:33:46 2019 /sbin/ip link set dev tap0 up mtu 1500 Sun Dec 15 06:33:46 2019 /sbin/ip addr add dev tap0 172.30.0.14/28 broadcast 172.30.0.15 Sun Dec 15 06:33:46 2019 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this Sun Dec 15 06:33:46 2019 Initialization Sequence Completedifconfigでインターフェースの状態を見てみると、
tap0
というインターフェースが作成され、172.30.0.14
というIPアドレスが割り当てられていると思います。# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.91.129 netmask 255.255.255.0 broadcast 192.168.91.255 inet6 fe80::20c:29ff:fe18:a0c8 prefixlen 64 scopeid 0x20<link> ether 00:0c:29:18:a0:c8 txqueuelen 1000 (Ethernet) RX packets 14781 bytes 9483880 (9.0 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 6484 bytes 645921 (630.7 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 31612 bytes 10003030 (9.5 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 31612 bytes 10003030 (9.5 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.30.0.14 netmask 255.255.255.240 broadcast 172.30.0.15 inet6 fe80::c0d8:eeff:fe38:d79b prefixlen 64 scopeid 0x20<link> ether c2:d8:ee:38:d7:9b txqueuelen 100 (Ethernet) RX packets 16 bytes 1272 (1.2 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 21 bytes 1622 (1.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0このとき、NaumachiaのサーバでDockerコンテナとネットワークの状態を見ると、新たに
user1_example_
というプレフィックスがついたコンテナとネットワークが作成されているはずです。これがユーザ専用のトレーニング用のコンテナとネットワークです。ユーザが増えると、コンテナとネットワークも増えていきます。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 17c4ef2ccbb9 naumachia/example.alice "python /app/alice.py" About a minute ago Up About a minute user1_example_alice_1 ff271a01eba9 naumachia/example.bob "python /app/bob.py" About a minute ago Up About a minute user1_example_bob_1 dd9e858277bd naumachia/manager "python -m app" 32 minutes ago Up 32 minutes build_manager_1 f80057d9dc2e naumachia/openvpn "/scripts/naumachia-…" 32 minutes ago Up 32 minutes 0.0.0.0:2000->1194/udp build_openvpn-example_1 86fc3709d4e3 redis:alpine "docker-entrypoint.s…" 32 minutes ago Up 32 minutes build_redis_1 a0f45e1f292a naumachia/registrar "gunicorn -c python:…" 32 minutes ago Up 32 minutes 0.0.0.0:3960->3960/tcp build_registrar_1 9d1ef7902351 alpine "/bin/true" 32 minutes ago Exited (0) 32 minutes ago build_bootstrapper_1# docker network ls NETWORK ID NAME DRIVER SCOPE 743f747a01b3 bridge bridge local 7017ddd37ba8 build_default bridge local dce5de7a2fa2 build_internal bridge local de7c1746cc32 host host local 6dc0c89a9ccf none null local b1649b2f2e93 user1_example_default l2bridge localARPスプーフィングを試してみる
この問題は example の docker-compose.yml に書かれているとおり、ARPスプーフィングのようなMITM(中間者攻撃)を行う問題です。
The file defines the configuration for simple Nauachia challenge where a sucessful man-in-the-middle (MTIM) attack (such as ARP poisoning) provides a solution
今回は
172.30.0.2
と172.30.0.3
のIPアドレスを持つ2台の端末がいるので、この2台が行っている通信をARPスプーフィングして盗聴することを試みます。ARPスプーフィングの仕組みや具体的な手法についてはここでは詳しくは説明しませんが、成功すると以下のようにパケットキャプチャすることで、
172.30.0.2
と172.30.0.3
の2つのホスト間の通信が見えてしまいます。# tcpdump -i tap0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tap0, link-type EN10MB (Ethernet), capture size 262144 bytes 06:40:47.791591 ARP, Reply 172.30.0.2 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:48.042999 ARP, Reply 172.30.0.3 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:48.696193 IP 172.30.0.3.55672 > 172.30.0.2.5005: UDP, length 30 06:40:49.792320 ARP, Reply 172.30.0.2 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:50.044301 ARP, Reply 172.30.0.3 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:51.700769 IP 172.30.0.3.55672 > 172.30.0.2.5005: UDP, length 30 06:40:51.793616 ARP, Reply 172.30.0.2 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:52.044971 ARP, Reply 172.30.0.3 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:53.794367 ARP, Reply 172.30.0.2 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:54.045958 ARP, Reply 172.30.0.3 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:54.705584 IP 172.30.0.3.55672 > 172.30.0.2.5005: UDP, length 30 06:40:55.795642 ARP, Reply 172.30.0.2 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28 06:40:56.047136 ARP, Reply 172.30.0.3 is-at 3e:d6:f2:ca:92:81 (oui Unknown), length 28L2で接続されている同じネットワークにいる場合、このようなリスクがあることを認識しなければいけません。
おわりに
この記事では、NaumachiaというOSSを使ったペネトレーションテストのトレーニング環境の構築について紹介しました。
ペネトレーションテストは実際に攻撃を行うことなので、それをトレーニングすることは攻撃者を養成したいのか?と思われる方がいるかもしれませんが、そうではありません。
近年のサイバー攻撃は高度になってきており、防御側の視点だけでは守りきれないことが増えてきています。
このような攻撃から守るためには、実際の攻撃手法を知り、それに合わせた効果的な防御手法を考えることが重要です。
トレーニングで手を動かして実際の攻撃手法を試すことで攻撃手法への理解も進み、より効率のよい防御ができる人材を育成できるのでないかと考えています。明日は @nyakuo さんの担当となります。
それでは良いお年を!
ペネトレーションテストについて by 脆弱性診断士スキルマッププロジェクト ( https://github.com/ueno1000/about_PenetrationTest ) ↩
- 投稿日:2019-12-15T23:48:38+09:00
Windows10HomeにDockerを導入する
動機
会社でDockerを使い始めてその便利さを実感したところ、自宅のPCでもDockerを使いたくなった。
で、Docker Desktop for WindowsをインストールしようとしたらWindowsのHyper-Vという機能を利用しているらしく、Windows 10 Homeではこの機能が使えない。
Docker-Toolboxなら使えるとのことなのだが、その際に今回インストール方法をちょっと調べたのでせっかくなので記事にする。
誰かの調べる手間が少しでも省けたらなーと思う。対象
- Windows 10 Home 64bit
Windows 10 Pro, Enterprise, Educationの人はDocker Desktop for Windowsを利用できると思うのでそちらの利用をおすすめする。
またDocker-Toolboxは32bit版では使えないそうなのでこの記事では対象外とする。ステップ
- CPUの仮想化を有効にする
- Docker-Toolboxをインストール
- Dockerの動作確認
1. CPUの仮想化を有効にする
1-1. 仮想化が有効になっているか確認
タスクマネージャを起動してCPUの情報を確認する。
仮想化の欄が有効になっていればOKだが、無効の場合はBIOSの設定を変更して有効にする必要がある。
1-2. BIOSからCPUを仮想化する
BIOSのメニューは人によって設定場所が違うと思うので各自で探してほしい。
参考にうちの場合は、詳細→CPU設定→Intel(VMX) Virtualization Technologyを有効にした。
再起動後タスクマネージャーで確認すると、以下のように仮想化の項目が有効になっている。
2. Docker-Toolboxをインストール
2-1. Docker-Toolboxをダウンロード
下記リンクからインストーラーをダウンロードする
https://github.com/docker/toolbox/releases
2-2. Docker-Toolboxをインストール
インストーラーを起動して、基本的にデフォルト設定ですべてNextで良い。
変更したい項目があれば適宜修正すること。
下の画面が出ればインストール完了
3.Dockerの動作確認
3-1. Docker Quickstart Terminalを起動
インストールすると以下のショートカットが生成されていると思う。
その中のDocker Quickstart Terminalを起動する。
初回起動はいろいろ準備が入る。クジラのアスキーアートが表示されたら準備完了。
3-2. お試しで
docker run hello-world
を実行するお試しで実行するコマンドは
docker run hello-world
。
docker run hello-world
が具体的にどんなことをしているかまとめてくれている方がいたので、気になる方はこちらの記事をみて。最後に
それでは良いDockerライフを!
参考資料
- 投稿日:2019-12-15T23:32:37+09:00
Text To Speech (Open Jtalk) を、Kubernetes Cronjob からホストのオーディオインターフェイスを使って喋らせる
TORICOでは、社内にツール用サーバが何台かあり、社内ツールはすべて Kubernetes + Docker で起動しています。
オフィスでは、決まった時間に Text To Speech (Open Jtalk)で、「換気しましょう」といったアナウンスをするようにしています。
以前は Ubuntu にそのまま Open JTalk をインストールし、生cron で実行していたのですが、最近そのサーバマシンを停止してすべて Kubernetes運用になりましたので、Text To Speech していたタスクを生 cron から Kubernetes Cronjob に移行しました。
Dockerイメージを作る
Dockerfile
まず、Open-JTalk がインストールされた Docker イメージを作ります。
apt install open-jtalk でもインストールできますが、バージョンが古いのでソースからビルドしたほうが使えるオプションが増えていて良いです。音量設定など。
mei ボイスを 1.7, 1.8 の2バージョン入れているのは、切り替えて使えるようにするためです。1.8では1.7からけっこう変化があり、、声のトーンが落ち着いてます。1.7の方がよく通る声なのでそっちを多く使っています。
マルチステージビルドしない場合、1GBほどのイメージサイズになります。この Dockerfile のようにマルチステージビルドした場合、130MBほどで済みました。Alpineは試していません。
DockerfileFROM ubuntu:18.04 as builder WORKDIR /var/speech RUN apt update && \ apt install -y \ unzip \ curl \ build-essential \ && apt clean \ && rm -rf /var/lib/apt/lists/* RUN curl -L -O https://downloads.sourceforge.net/hts-engine/hts_engine_API-1.10.tar.gz RUN tar zxvf hts_engine_API-1.10.tar.gz RUN cd hts_engine_API-1.10 && ./configure && make && cd - RUN curl -L -O https://downloads.sourceforge.net/open-jtalk/open_jtalk-1.11.tar.gz RUN tar zxvf open_jtalk-1.11.tar.gz RUN cd open_jtalk-1.11 && ./configure --with-charset=UTF-8 \ --with-hts-engine-header-path=/var/speech/hts_engine_API-1.10/include \ --with-hts-engine-library-path=/var/speech/hts_engine_API-1.10/lib \ && make && make install RUN mkdir /usr/share/hts-voice RUN curl -L -O https://downloads.sourceforge.net/mmdagent/MMDAgent_Example-1.7.zip RUN unzip MMDAgent_Example-1.7.zip RUN curl -L -O https://downloads.sourceforge.net/mmdagent/MMDAgent_Example-1.8.zip RUN unzip MMDAgent_Example-1.8.zip FROM ubuntu:18.04 WORKDIR /var/speech RUN apt update && \ apt install -y \ open-jtalk-mecab-naist-jdic \ alsa-utils \ && apt clean \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/bin/open_jtalk /usr/local/bin/open_jtalk COPY --from=builder /var/speech/MMDAgent_Example-1.7/Voice/mei /usr/share/hts-voice/mei17 COPY --from=builder /var/speech/MMDAgent_Example-1.8/Voice/mei /usr/share/hts-voice/mei18 COPY wav ./wav COPY sh ./shTTS再生スクリプト
sh ディレクトリの中身はこのようになっています。
sh/chime-speech.sh#!/usr/bin/env bash if [ ! "$1" ]; then echo "Usage: $0 <speech-text>" >2 exit 1 fi cd "$(dirname $0)" || exit ./ring-chime.sh ./jsay-female.sh "$1"sh/jsay-female.sh#!/bin/sh TMP=/tmp/jsay.wav echo "$1" | open_jtalk \ -m /usr/share/hts-voice/mei/mei_normal.htsvoice \ -x /var/lib/mecab/dic/open-jtalk/naist-jdic \ -r 0.7 \ -g 6 \ -ow $TMP && \ ./play-wav.sh $TMPsh/play-wav.sh#!/usr/bin/env bash aplay -D plughw:1 ${1}ring-chime.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit ./play-wav.sh ../wav/chime.wav
./chime-speech.sh こんにちは
というコマンドで、チャイム効果音を鳴らした後、「こんにちは」とTTSで発声するようになっています。なお、
sh/play-wav.sh
のplughw:1
の「1」はサウンドカード番号であり、Dockerホストの環境に依存すると思います。詳細は後ほど書きます。ビルドスクリプト
docker-compose でも良いのですが、私は下記のような bash スクリプトで Docker イメージのビルドとサーバへのデプロイをしています。
config.sh#!/usr/bin/env bash image_name=torico/torico-speech container_name=torico-speech deploy_host=user@deploy-server.example.combuild.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit . config.sh docker build . -t ${image_name}docker-image-copy-to-remote.sh#!/usr/bin/env bash . config.sh docker save ${image_name} | bzip2 | ssh ${deploy_host} 'bunzip2 | sudo docker load'↑手元でビルドした Docker イメージをリモートサーバにコピーします
login.sh#!/usr/bin/env bash ./run.sh /bin/bash
run.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit . config.sh docker run \ --rm -it \ --device /dev/snd \ --name=${container_name} ${image_name} \ "$@"スクリプトファイルをたくさん作るのは、エディタ (IntelliJなど) で右クリックからの実行を簡単にするためです。
build.sh でビルドしたら、docker-image-copy-to-remote.sh で SSH でサーバに送りつけます。今回は Docker リポジトリは使っていません。
./run.sh は動作確認のために作っています。Ubuntu用です。Mac では /dev/snd が無いので動きません。
サウンドインターフェイスの確認
--device /dev/snd
をつけて docker コンテナを起動し、サウンドカードの様子を見ます。--privileged
はなくても動きましたsudo docker run --rm -it --device /dev/snd --name=torico-speech torico/torico-speech /bin/bash# alsamixer
root@f3a4dc37f277:/var/speech# amixer Simple mixer control 'IEC958',0 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',1 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',2 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',3 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',4 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] root@f3a4dc37f277:/var/speech# amixer -c 1 Simple mixer control 'Master',0 Capabilities: pvolume pvolume-joined pswitch pswitch-joined Playback channels: Mono Limits: Playback 0 - 87 Mono: Playback 87 [100%] [0.00dB] [on] Simple mixer control 'Headphone',0 Capabilities: pvolume pswitch Playback channels: Front Left - Front Right Limits: Playback 0 - 87 Mono: Front Left: Playback 87 [100%] [0.00dB] [on] Front Right: Playback 87 [100%] [0.00dB] [on] Simple mixer control 'Speaker',0 Capabilities: pswitch Playback channels: Front Left - Front Right Mono: Front Left: Playback [on] Front Right: Playback [on] Simple mixer control 'Speaker+LO',0 Capabilities: pvolume Playback channels: Front Left - Front Right Limits: Playback 0 - 87 Mono: Front Left: Playback 87 [100%] [0.00dB] Front Right: Playback 87 [100%] [0.00dB] Simple mixer control 'Front Mic',0 Capabilities: pvolume pswitch Playback channels: Front Left - Front Right Limits: Playback 0 - 31 Mono: Front Left: Playback 0 [0%] [-34.50dB] [off] Front Right: Playback 0 [0%] [-34.50dB] [off] ... root@f3a4dc37f277:/var/speech# aplay wav/chime.wav ALSA lib pcm_dmix.c:1052:(snd_pcm_dmix_open) unable to open slave aplay: main:788: audio open error: No such file or directory root@f3a4dc37f277:/var/speech# aplay -D plughw:1 wav/chime.wav Playing WAVE 'wav/chime.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo (再生される) root@f3a4dc37f277:/var/speech#サウンドカードは2つ認識されていて、使いたいカード番号は 1 でした。
なので、aplay の引数に-D plughw:1
をつけます。Kubernetes cronjob
ローカルにある Docker イメージを使って Cronjob を起動します。
ローカルの Docker イメージを使うので、imagePullPolicy は Never です。
cronjob.ymlapiVersion: batch/v1beta1 kind: CronJob metadata: name: speech-12-open namespace: torico labels: cronjob: speech-12-open spec: concurrencyPolicy: Replace schedule: "0 12 * * *" jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: torico-speech image: torico/torico-speech imagePullPolicy: Never args: - "/var/speech/sh/chime-speech.sh" - "12時になりました。…窓を開けて、5分間換気をしてください。" volumeMounts: - mountPath: /dev/snd name: dev-snd securityContext: privileged: true volumes: - name: dev-snd hostPath: path: /dev/snddocker run の
--device
オプションの代わりに、volumeMounts を使います。privileged が必要です。ちなみに私は、上記ファイルと同じディレクトリに apply.sh とか作って、エディタから右クリックでkubectl を実行するようにしていまします。
apply.sh#!/usr/bin/env bash export KUBECONFIG=${HOME}/.kube/remote-server-kubeconfig kubectl apply -f cronjob.yml
- 投稿日:2019-12-15T23:32:37+09:00
Text To Speech (Open Jtalk) を、Kubernetes Crontab からホストのオーディオインターフェイスを使って喋らせる
TORICOでは、社内にツール用サーバが何台かあり、社内ツールはすべて Kubernetes + Docker で起動しています。
オフィスでは、決まった時間に Text To Speech (Open Jtalk)で、「換気しましょう」といったアナウンスをするようにしています。
以前は Ubuntu にそのまま Open JTalk をインストールし、生cron で実行していたのですが、最近そのサーバマシンを停止してすべて Kubernetes運用になりましたので、Text To Speech していたタスクを生 cron から Kubernetes Cronjob に移行しました。
Dockerイメージを作る
Dockerfile
まず、Open-JTalk がインストールされた Docker イメージを作ります。
apt install open-jtalk でもインストールできますが、バージョンが古いのでソースからビルドしたほうが使えるオプションが増えていて良いです。音量設定など。
mei ボイスを 1.7, 1.8 の2バージョン入れているのは、切り替えて使えるようにするためです。1.8では1.7からけっこう変化があり、、声のトーンが落ち着いてます。1.7の方がよく通る声なのでそっちを多く使っています。
マルチステージビルドしない場合、1GBほどのイメージサイズになります。この Dockerfile のようにマルチステージビルドした場合、130MBほどで済みました。Alpineは試していません。
DockerfileFROM ubuntu:18.04 as builder WORKDIR /var/speech RUN apt update && \ apt install -y \ unzip \ curl \ build-essential \ && apt clean \ && rm -rf /var/lib/apt/lists/* RUN curl -L -O https://downloads.sourceforge.net/hts-engine/hts_engine_API-1.10.tar.gz RUN tar zxvf hts_engine_API-1.10.tar.gz RUN cd hts_engine_API-1.10 && ./configure && make && cd - RUN curl -L -O https://downloads.sourceforge.net/open-jtalk/open_jtalk-1.11.tar.gz RUN tar zxvf open_jtalk-1.11.tar.gz RUN cd open_jtalk-1.11 && ./configure --with-charset=UTF-8 \ --with-hts-engine-header-path=/var/speech/hts_engine_API-1.10/include \ --with-hts-engine-library-path=/var/speech/hts_engine_API-1.10/lib \ && make && make install RUN mkdir /usr/share/hts-voice RUN curl -L -O https://downloads.sourceforge.net/mmdagent/MMDAgent_Example-1.7.zip RUN unzip MMDAgent_Example-1.7.zip RUN curl -L -O https://downloads.sourceforge.net/mmdagent/MMDAgent_Example-1.8.zip RUN unzip MMDAgent_Example-1.8.zip FROM ubuntu:18.04 WORKDIR /var/speech RUN apt update && \ apt install -y \ open-jtalk-mecab-naist-jdic \ alsa-utils \ && apt clean \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /usr/local/bin/open_jtalk /usr/local/bin/open_jtalk COPY --from=builder /var/speech/MMDAgent_Example-1.7/Voice/mei /usr/share/hts-voice/mei17 COPY --from=builder /var/speech/MMDAgent_Example-1.8/Voice/mei /usr/share/hts-voice/mei18 COPY wav ./wav COPY sh ./shTTS再生スクリプト
sh ディレクトリの中身はこのようになっています。
sh/chime-speech.sh#!/usr/bin/env bash if [ ! "$1" ]; then echo "Usage: $0 <speech-text>" >2 exit 1 fi cd "$(dirname $0)" || exit ./ring-chime.sh ./jsay-female.sh "$1"sh/jsay-female.sh#!/bin/sh TMP=/tmp/jsay.wav echo "$1" | open_jtalk \ -m /usr/share/hts-voice/mei/mei_normal.htsvoice \ -x /var/lib/mecab/dic/open-jtalk/naist-jdic \ -r 0.7 \ -g 6 \ -ow $TMP && \ ./play-wav.sh $TMPsh/play-wav.sh#!/usr/bin/env bash aplay -D plughw:1 ${1}ring-chime.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit ./play-wav.sh ../wav/chime.wav
./chime-speech.sh こんにちは
というコマンドで、チャイム効果音を鳴らした後、「こんにちは」とTTSで発声するようになっています。なお、
sh/play-wav.sh
のplughw:1
の「1」はサウンドカード番号であり、Dockerホストの環境に依存すると思います。詳細は後ほど書きます。ビルドスクリプト
docker-compose でも良いのですが、私は下記のような bash スクリプトで Docker イメージのビルドとサーバへのデプロイをしています。
config.sh#!/usr/bin/env bash image_name=torico/torico-speech container_name=torico-speech deploy_host=user@deploy-server.example.combuild.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit . config.sh docker build . -t ${image_name}docker-image-copy-to-remote.sh#!/usr/bin/env bash . config.sh docker save ${image_name} | bzip2 | ssh ${deploy_host} 'bunzip2 | sudo docker load'↑手元でビルドした Docker イメージをリモートサーバにコピーします
login.sh#!/usr/bin/env bash ./run.sh /bin/bash
run.sh#!/usr/bin/env bash cd "$(dirname $0)" || exit . config.sh docker run \ --rm -it \ --device /dev/snd \ --name=${container_name} ${image_name} \ "$@"スクリプトファイルをたくさん作るのは、エディタ (IntelliJなど) で右クリックからの実行を簡単にするためです。
build.sh でビルドしたら、docker-image-copy-to-remote.sh で SSH でサーバに送りつけます。今回は Docker リポジトリは使っていません。
./run.sh は動作確認のために作っています。Ubuntu用です。Mac では /dev/snd が無いので動きません。
サウンドインターフェイスの確認
--device /dev/snd
をつけて docker コンテナを起動し、サウンドカードの様子を見ます。--privileged
はなくても動きましたsudo docker run --rm -it --device /dev/snd --name=torico-speech torico/torico-speech /bin/bash# alsamixer
root@f3a4dc37f277:/var/speech# amixer Simple mixer control 'IEC958',0 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',1 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',2 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',3 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] Simple mixer control 'IEC958',4 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on] root@f3a4dc37f277:/var/speech# amixer -c 1 Simple mixer control 'Master',0 Capabilities: pvolume pvolume-joined pswitch pswitch-joined Playback channels: Mono Limits: Playback 0 - 87 Mono: Playback 87 [100%] [0.00dB] [on] Simple mixer control 'Headphone',0 Capabilities: pvolume pswitch Playback channels: Front Left - Front Right Limits: Playback 0 - 87 Mono: Front Left: Playback 87 [100%] [0.00dB] [on] Front Right: Playback 87 [100%] [0.00dB] [on] Simple mixer control 'Speaker',0 Capabilities: pswitch Playback channels: Front Left - Front Right Mono: Front Left: Playback [on] Front Right: Playback [on] Simple mixer control 'Speaker+LO',0 Capabilities: pvolume Playback channels: Front Left - Front Right Limits: Playback 0 - 87 Mono: Front Left: Playback 87 [100%] [0.00dB] Front Right: Playback 87 [100%] [0.00dB] Simple mixer control 'Front Mic',0 Capabilities: pvolume pswitch Playback channels: Front Left - Front Right Limits: Playback 0 - 31 Mono: Front Left: Playback 0 [0%] [-34.50dB] [off] Front Right: Playback 0 [0%] [-34.50dB] [off] ... root@f3a4dc37f277:/var/speech# aplay wav/chime.wav ALSA lib pcm_dmix.c:1052:(snd_pcm_dmix_open) unable to open slave aplay: main:788: audio open error: No such file or directory root@f3a4dc37f277:/var/speech# aplay -D plughw:1 wav/chime.wav Playing WAVE 'wav/chime.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo (再生される) root@f3a4dc37f277:/var/speech#サウンドカードは2つ認識されていて、使いたいカード番号は 1 でした。
なので、aplay の引数に-D plughw:1
をつけます。Kubernetes cronjob
ローカルにある Docker イメージを使って Cronjob を起動します。
ローカルの Docker イメージを使うので、imagePullPolicy は Never です。
cronjob.ymlapiVersion: batch/v1beta1 kind: CronJob metadata: name: speech-12-open namespace: torico labels: cronjob: speech-12-open spec: concurrencyPolicy: Replace schedule: "0 12 * * *" jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: torico-speech image: torico/torico-speech imagePullPolicy: Never args: - "/var/speech/sh/chime-speech.sh" - "12時になりました。…窓を開けて、5分間換気をしてください。" volumeMounts: - mountPath: /dev/snd name: dev-snd securityContext: privileged: true volumes: - name: dev-snd hostPath: path: /dev/snddocker run の
--device
オプションの代わりに、volumeMounts を使います。privileged が必要です。ちなみに私は、上記ファイルと同じディレクトリに apply.sh とか作って、エディタから右クリックでkubectl を実行するようにしていまします。
apply.sh#!/usr/bin/env bash export KUBECONFIG=${HOME}/.kube/remote-server-kubeconfig kubectl apply -f cronjob.yml
- 投稿日:2019-12-15T23:17:20+09:00
docker imageファイルの保存先
https://stackoverflow.com/questions/24309526/how-to-change-the-docker-image-installation-directory
以下やろうと思ったけど symlinkだといろいろエラーになるのでやめた
do the trick:
/etc/docker/daemon.json
{
"graph": "/mnt",
"storage-driver": "overlay2"
}
Despite the method you have to reload configuration and restart Docker:sudo systemctl daemon-reload
sudo systemctl restart docker
To confirm that Docker was reconfigured:docker info|grep "loop file"
In recent version (17.03) different command is required:docker info|grep "Docker Root Dir"
Docker Root Dir: /mnt/dockerストレージドライバ
overlay2じゃないと buildでエラーになる?
https://qiita.com/NaotoHanaue/items/b9f395a63f7aae2a41b7sudo docker info
(snip)
Storage Driver: overlay2
- 投稿日:2019-12-15T23:12:39+09:00
docker coreos
esxi
https://serverfault.com/questions/372443/curl-on-esxi-5-0
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_vmware_ova.ovawget http://stable.release.core-os.net/amd64-usr/current/coreos_production_qemu.sh
esxi
https://qiita.com/ka2asd/items/456b55b9958c0f2f206b
https://qiita.com/fabiiw05/items/b6dde0e1dbd620c3e7fa
パスワードなし
https://coreos.com/os/docs/latest/booting-with-iso.html
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_iso_image.iso
vi ~/cloud-config.yml
改行とハイフンとスペースが適切でないとだめっぽい
users:
- name: coreuser
passwd: $xxxxxxxxx/ # パスワード認証。openssl passwdコマンドを叩いて実行した結果を貼り付け
groups: #所属するgroupの指定
- sudo
- docker
ssh-authorized-keys:
- ssh-rsa #coreuserに持たせる公開鍵user: core
pass: password秘密インストールが完了したらネットワーク設定をおこないましょう。
ネットワークの設定は/etc/systemd/network/static.networkファイルを作成します。$ sudo vi /etc/systemd/network/static.network
記述内容(内容は自分の環境に合わせて変更してください)[Match]
Name=enp0s3[Network]
Address=192.168.0.105
Gateway=192.168.0.1
DNS=192.168.0.1https://www.hitsumabushi.org/blog/2017/02/08/2231.html
自宅 vSphere 上の CoreOS (Container Linux) のデプロイメモ
- 投稿日:2019-12-15T23:09:23+09:00
dockerまとめ
docker pull ubuntu
docker run -it --name=ping_in_ubuntu ubuntu /bin/bash
docker container prune
イメージ削除
docker rmi ping_in_ubuntu:ver.1.00
docker commit 644f7f59030e ping_in_ubuntu
saveしたimage 取り込み
docker load < ping_save.tar
デタッチモードで起動
docker run -p 8080:80 -d httpd
停止
docker stop 5c67acf81f90
再開
docker start 5c67acf81f90
マウント
docker run -v /Users/N/_work/00_docker/webContents/:/usr/local/apache2/htdocs/ -p 80:80 -d httpd
データvolume作成
docker volume create --name=datavolume
登録
docker run -it -v datavolume:/tmp/ ubuntu /bin/bash
ボリューム削除
exit
ボリューム一覧
docker volume ls
DRIVER VOLUME NAME
local datavolume削除
docker volume rm datavolume
docker run --volumes-from data-container -it ubuntu /bin/bash
データボリューム・コンテナを使う場合は、利用する側のコンテナに
「volume-from」を使う
というだけなので、他のコンテナと同じように思えますが、一つ大きな特徴
があります。
それは、データボリューム・コンテナは、‘‘稼働していなくても利用でき
る” という点です。
先ほどの、手順[2]ではボリュームのバックアップ
docker run --volumes-from data-container -v /Users/N/_work/00_docker/:/backup ubuntu tar cvf /backup/container-bkup.tar -C / tmp
リストア
docker run --volumes-from data-container -v /Users/N/_work/00_docker/:/backup ubuntu tar xvf /backup/container-bkup.tar -C /
データボリュームの所在
docker inspect data-container
nginx
docker run -d -p 80:80 --name webserver nginx
dockerFile
docker build -t ping-image .
ログの見方
docker logs 2e2ef2184c07
============
django テスト
https://qiita.com/homines22/items/2730d26e932554b6fb58停止
docker stop test
再開
docker start 1429509e1e5b
runserver
docker exec test python3 manage.py runserver 0.0.0.0:8000
django & docker compose
https://qiita.com/kyhei_0727/items/e0eb4cfa46d71258f1bedocker-compose rm
docker rm $(docker ps -aq)docker-compose build
tensorflow
Dockerイメージをプル(Python3の最新安定板を使用する場合)
その他のイメージを使用する場合はこちら:https://www.tensorflow.org/install/docker?hl=jadocker pull tensorflow/tensorflow:latest-gpu-py3
Dockerコンテナを作成&実行
docker run --runtime=nvidia -it --name TestContainerName -p 8888:8888 -v /Users/N/_work/00_docker/tensorflow:/tmp tensorflow/tensorflow:latest-gpu-py3 bash
docker run -it --name TestContainerName -p 8888:8888 -v /Users/N/_work/00_docker/tensorflow:/tmp tensorflow/tensorflow:latest bash
Jupyter Notebookを起動
jupyter notebook --allow-root
表示された下記の文字列をコピーして…
http://(*** or 127.0.0.1):8888/?token=***
ブラウザのアドレスバーに下記のように編集してペーストhttp://127.0.0.1:8888/?token=***
https://qiita.com/y_kani/items/27a965b952db729e30f5
- デフォルトでvimが入っていないため、Jupyter Notebook起動前に設定ファイルを編集したい場合は以下を実行してvimをインストールすること。 # apt-get update # apt-get install vim
https://qiita.com/yoshiyasu1111/items/cc3b9ca71f98bd66d9b8
docker pull jupyter/tensorflow-notebook
docker run -d --name jupyter -p 8088:8888 -v /Users/N/_work/00_docker/jupyter:/home/work jupyter/tensorflow-notebook
docker exec 43aa18101a01 jupyter notebook list
画像認識
https://qiita.com/hikarut/items/c7a0e45a962b16c7907a
http://localhost:8088/tree/work/classify
python classify_image.py --image_file c1.jpg
scraping
https://oliversi.com/2019/01/07/python-docker-selenium-chrome/
https://qiita.com/sikkim/items/447b72e6ec45849058cd
git clone https://github.com/sikkimtemi/selenium
cd selenium
docker-compose up -dcd script
docker exec -it python ./sample.pydocker compose 終了
docker-compose down
コンテナ停止
docker stop rm-container wp-container pma-container mysql-container
docker start mysql-container rm-container wp-container pma-container
- 投稿日:2019-12-15T21:24:30+09:00
docker勉強 その①
dockerの基本的なコマンドを覚える
dockerでubuntu18.04を構築して基本的なコマンドを覚える
dockerイメージを取得
ubuntu18.04のイメージを取得する。
$ docker pull ubuntu:18.04 18.04: Pulling from library/ubuntu 7ddbc47eeb70: Pull complete c1bbdc448b72: Pull complete 8c3b70e39044: Pull complete 45d437916d57: Pull complete Digest: sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d Status: Downloaded newer image for ubuntu:18.04 docker.io/library/ubuntu:18.04dockerイメージの確認
先ほど取得したubuntu18.04のイメージがあるか確認する。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 18.04 775349758637 6 weeks ago 64.2MB
dockerイメージからコンテナを起動する
$ docker run -it -d --name ubuntu18-04 ubuntu:18.04 8389c53ba63b5c1a45ca256a6ec91cce6f1c3b889f12f1c4a6f64289b612ffeaoption
-it:コンテナのプロセスにttyを割り当てる。(標準入出力の割り当て)
-d:コンテナをバックグラウンドで起動する
--name:コンテナに指定した名前をつける
コンテナの起動確認
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8389c53ba63b ubuntu:18.04 "/bin/bash" 8 seconds ago Up 6 seconds ubuntu18-04dockerのubuntu18.04にアクセス
$ docker exec -it ubuntu18-04 /bin/bash root@8389c53ba63b:/#これでdockerのubuntu18.04で色々と操作ができる。
exit
で抜けれる。コンテナの停止
ubuntu18.04を停止する。
$ $ docker stop ubuntu18-04 ubuntu18-04
停止しているか確認する。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8389c53ba63b ubuntu:18.04 "/bin/bash" 2 minutes ago Exited (0) 40 seconds ago ubuntu18-04停止したコンテナを再度起動する。
$ docker start ubuntu18-04 ubuntu18-04
コンテナの削除
ubuntu18.04を削除する。
$ docker rm ubuntu18-04 ubuntu18-04 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESdockerイメージの削除
ubuntu18.04のイメージを削除する。
$ docker rmi ubuntu:18.04 Untagged: ubuntu:18.04 Untagged: ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d Deleted: sha256:775349758637aff77bf85e2ff0597e86e3e859183ef0baba8b3e8fc8d3cba51c Deleted: sha256:4fc26b0b0c6903db3b4fe96856034a1bd9411ed963a96c1bc8f03f18ee92ac2a Deleted: sha256:b53837dafdd21f67e607ae642ce49d326b0c30b39734b6710c682a50a9f932bf Deleted: sha256:565879c6effe6a013e0b2e492f182b40049f1c083fc582ef61e49a98dca23f7e Deleted: sha256:cc967c529ced563b7746b663d98248bc571afdb3c012019d7f54d6c092793b8b $ docker images REPOSITORY TAG IMAGE ID CREATED SIZEこれで基本的なdockerのコマンドは覚えれたと思います。
次はdocker-composeやdockerでwebサーバーを構築し、ポートフォワーディングの設定などやろうと思います。はてなブログにも投稿しています。
- 投稿日:2019-12-15T21:21:39+09:00
Docker上でDjango開発開始準備
目的
Dangoの開発を開始するにあたり、Docker上での開発環境を作成します。
公式のDjango Tutorialの1つ目の完了までを目標とします。開発環境構築
DjangoのDocker環境を構築します。
Docker file作成
現時点のPythonの最新は3.8ですので、それをベースに作成します。
FROM python:3.8 # Python 標準入出力バッファーを無効(反応速度優先のため。性能は下がる。) ENV PYTHONUNBUFFERED 1 # # オススメのパッケージは入れない.最小限とする. --no-install-recommends # DBを変更する場合は postgresql-client等を追加. RUN apt-get update \ && apt-get install -y --no-install-recommends \ && rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install -r requirements.txt COPY . . EXPOSE 8000 # 開発完了したら、以下を有効にする. # CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]Python追加パッケージの設定
requirements.txtにPythonのパッケージを記述します。
requirements.txtdjangoイメージ作成
イメージ名「django」でイメージをビルドします。
docker build -t django .bash 起動
開発を行うため、bash起動します。
$ docker run -p 127.0.0.1:8000:8000 -it django bashDjango開発
以下のURLを参考にしてアプリを作成します。
Django ドキュメントdjangoアプリ作成
サンプル作成
確認のためにサンプルを作成します。
$ django-admin startproject sampleappサンプル起動
動作確認のため、一旦起動してみます。
$ python manage.py runserver 0:8000HOST側からアクセスするため、「runserver 8000」ではなく「runserver 0:8000」で起動します。
確認したら、Ctrl+Cで終了します。チュートリアルで確認
チュートリアルでサンプルアプリを作成します。詳細は以下のURLを参照します。
はじめての Django アプリ作成、その 1以下のURLにアクセスし、表示されることを確認します。
http://127.0.0.1:8000/polls/dokcer環境でdjango開発の準備はできた。
- 投稿日:2019-12-15T21:02:56+09:00
Docker Compose で AWX + Gitea 環境を作る
はじめに
AWX は Docker Compose によるインストール方法をサポートしています。ただ、docker-compose.yml を用意して docker-compose コマンドを実行するのではなく、ansible-playbook コマンドを使用する方法になっています。何故 docker-compose コマンドを使用しないのでしょうか?
また、AWX だけ準備できてもソースコードリポジトリのコンテナが無いと、Github 等の既存のサービスが必要です。環境次第では何らかのソースコードリポジトリをデプロイする必要があるでしょう。個人的には Github クローンの1つ、Giteaがお勧めです。Go 言語で開発されており、GitLab より高速に動作します。
無いなら作ってしまいましょう、という事で、docker-compose.yml を用意するシェルスクリプトを作成しました。もっと良い方法があるのかも知れません。あればコメント欄で教えてください。
準備
- docker-compose パッケージをインストールします。
- docker サービスを起動します。
- こちら からシェルスクリプトをダウンロードします。
- シェルスクリプトの冒頭にある変数を適切に変更します。
- シェルスクリプトを実行して docker-compose.yml を作成します。
$ bash gen-dc-awx-gitea.sh
- docker-compose コマンドを実行します(1回目)
$ sudo docker-compose up各コンテナの実行ログがコンソール上に表示されます。そのうち、AWX 用の DB マイグレーションが実行されるので、マイグレーションが終わるまで待ちます。
7. CTRL-C で一旦実行を止めます。
8. docker-compose コマンドを実行します(2回目)$ sudo docker-compose up -d後はサービスにアクセスするだけです。
使用
デフォルトでは、以下のポートが使用されます。
- 443/TCP:AWX WebUI (HTTPS)
- 8443/TCP: Gitea WebUI (HTTPS)
- 10022/TCP: Gitea Git (SSH)
Gitea 画面の右上の sign-in をクリックすると、初回はサーバのセットアップ画面になります。デフォルト値は事前に docker-compose.yml で設定済みなので、ほとんど設定値を変更する必要はありませんが、管理者アカウントを追加するのであればこの画面で設定します。
利用上の注意
- AWX から見て Gitea のホスト名は gitea になります。ですので、AWX のプロジェクト登録時に Gitea 上の Git リポジトリを入力する際、URL のホスト名部分は Gitea の FQDN ではなく gitea にする必要があります。
- 投稿日:2019-12-15T19:41:43+09:00
令和元年に送る!Docker for WindowsでのJenkins(Docker in Docker)環境構築ハンズオン
はじめに
元号が変わり、2020年を迎えるにあたって「CI環境も存在しない開発体制をこの先も続けていくつもりなのか?」と悶々とする日々から脱却すべく「JenkinsのパイプラインでDockerfileを指定してビルド実行」を行うための環境構築に試行錯誤をした成果を紹介します。
目的
- ゼロからDocker入りJenkinsコンテナの立ち上げまでを、最小手順で実現する
- 手順の意図を理解する
以上の2点を目指しています。
私自身、DockerもJenkinsも最低限の知識しか持ち合わせておらず、結論に到達するまでに数多くのWebページを駆けずり回ることとなりました。
この記事は、まさしく「一ヶ月前の私がほしかったモノ」です。動作確認環境
- Windows10 Pro 1903 - 64bit
- Docker Desktop for Windows 2.1.0.5 (stable)
1. Docker入りJenkinsコンテナの構築〜立ち上げ
1.1.
Dockerfile
作成Dockerfile.sample# 1.1.1. FROM jenkins:2.60.3 # 1.1.2. USER root # 1.1.3. RUN apt-get update && apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg2 \ software-properties-common \ && curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - \ && apt-key fingerprint 0EBFCD88 \ && add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" \ && apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io \ && apt-get clean && rm -rf /var/lib/apt/lists/* # 1.1.4. RUN usermod -aG docker jenkins # 1.1.5. RUN cd /tmp/ \ && wget https://updates.jenkins-ci.org/latest/jenkins.war \ && mv ./jenkins.war /usr/share/jenkins/ # 1.1.6. USER jenkins1.1.1. ベースイメージ指定
ここでは奇をてらわずに、Jenkinsの公式イメージを指定しています。
タグについては、今後の更新で手順が変更になる可能性を考慮して、投稿時点で最新の2.60.3
を明示的に指定しています。1.1.2. ユーザー変更(
root
<-jenkins
)jenkinsイメージ内で、ユーザーが
jenkins
に変更されています。
jenkins
ユーザーはroot権限を持たないため、以降のコマンドを実行できるよう一時的にroot
ユーザーに変更します。1.1.3. Dockerインストール
Get Docker Engine - Community for Debian | Docker Documentationを参考に、Dockerエンジンを導入します。
インストール後には、Dockerfileのお作法としてキャッシュを削除しておきます。余談ですが、
curl
で指定するURLは、Docker v17.09以前のドキュメントでは$(. /etc/os-release; echo "$ID")
の結果を参照していました。
ホスト環境がRaspberry Piの場合等、URLにしたい文字列と$(. /etc/os-release; echo "$ID")
の結果とが一致しないケースがあることから、最新のドキュメントでは見直されているのではないかと想像します。 ※要出典1.1.4.
docker
をjenkins
ユーザーのセカンダリグループとして追加Post-installation steps for Linux | Docker Documentationを参考に、
jenkins
ユーザーがsudo
を指定せずにdocker
コマンドを実行するための準備としてグループ設定を行います。1.1.5. Jenkinsアップデート
jenkins:2.60.3
の最終更新日は、投稿時点で一年以上前となっていることから、最新のJenkinsを利用するために、アップデートします。1.1.6. ユーザー変更(
root
<-jenkins
)一時的に変更したユーザーをもとに戻します。
1.2.
docker-compose.yml
作成docker-compose.ymlversion: "3" services: jenkins: build: . ports: - 8080:8080 volumes: # 1.2.1. - ./jenkins_home:/var/jenkins_home # 1.2.2. - /var/run/docker.sock:/var/run/docker.sock:rw1.2.1. ホスト環境との共有ディレクトリの指定
JenkinsコンテナにホストPC上で作成した
Dockerfile
を送り込めるように、Jenkinsのホームディレクトリを共有ディレクトリ化します。1.2.2. Dockerデーモンの共有
Dockerコンテナ内でDockerコンテナを動かせるようにするために、ホストPCのDockerソケットを共有します。
1.3.
.env
作成(しません)Docker for WindowsでDockerデーモンを共有するために
.env
を作成してCOMPOSE_CONVERT_WINDOWS_PATHS=1
を指定する必要がある、という記事を目にしましたが、私の環境では作成せずに進めることができました。.envCOMPOSE_CONVERT_WINDOWS_PATHS=11.4. イメージ構築~コンテナ作成~バックグラウンド実行
カレントディレクトリに先に示した
Dockerfile
とdocker-compose.yml
とを配置して、コマンドプロンプトから以下のコマンドを実行します。$ docker-compose up --build -d && docker-compose exec -u root jenkins chown root:docker /var/run/docker.sockDocker for Windowsでは(?)
docker
グループに/var/run/docker.sock
へのアクセス権限が割り当てられていないようです。
そのため、コンテナのバックグラウンド実行後にグループ所有権を設定します。※コマンドプロンプト以外のCUIツールを仕様した場合、パスの解決がうまくいかずに
chown root:docker /var/run/docker.sock
を実行できないケースがあるようです。私はこれにハマって半日つぶしました。2. Jenkinsコンテナ上でDocker Pipeline Pluginの登録〜実行
2.1. Jenkinsセットアップ
任意のWebブラウザで
localhost:8080
へアクセスし、正規の手順でセットアップします。
※以下、テキストベースで説明していますが、他に詳しく正確で分かりやすい記事が山のようにありますので、そちらも参考にしてください。2.1.1. Unlock Jenikins
いきなり「Administrator password」を求められます。
ここにはdocker-compose logs -f jenkins
を実行して、以下のとおり出力されるパスワードを入力します。... jenkins_1 | 2019-12-15 08:10:47.628+0000 [id=30] INFO jenkins.install.SetupWizard#init: jenkins_1 | jenkins_1 | ************************************************************* jenkins_1 | ************************************************************* jenkins_1 | ************************************************************* jenkins_1 | jenkins_1 | Jenkins initial setup is required. An admin user has been created and a password generated. jenkins_1 | Please use the following password to proceed to installation: jenkins_1 | jenkins_1 | <Administrator password> jenkins_1 | jenkins_1 | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword jenkins_1 | jenkins_1 | ************************************************************* jenkins_1 | ************************************************************* jenkins_1 | ************************************************************* jenkins_1 | jenkins_1 | --> setting agent port for jnlp jenkins_1 | --> setting agent port for jnlp... done ...2.1.2. Customize Jenkins
特にこだわりがなければ「Install suggested plugins」を選択して問題ないでしょう。
2.1.3. Gettings Started
オールグリーンになるまで数分の休憩です。
![]()
2.1.4. Create First Addmin User
初期ユーザの情報を求められるので、適宜入力欄を埋めます。
2.1.5. Instance Configuration
JenkinsのURLを指定することができます。
特にこだわりがなければデフォルトのhttp://localhost:8080/
で問題ないでしょう。2.1.6. Jenkins is ready!
これでJenkinsのセットアップです!
2.2. パイプライン登録
以下、「sample」という名前のジョブを作成し、Dockerfileを指定してコンソールに「hello world.」と表示する例における手順です。
2.2.1. 下準備
- 以下内容の
Dockerfile
を作成DockerfileFROM alpine:latest
~/jenkins_home/workspace/sample/
ディレクトリを作成し、配下に1.
のファイルを配置2.2.2. WEB画面操作
- ホーム画面「新規ジョブ作成」をクリック
- 「Enter an item name」に「sample」と入力して「パイプライン」を選択し、「OK」をクリック
- Generalタブ「パイプライン」「Pipeline script」を選択して「Script」に以下の内容を入力し、「保存」をクリック
Scriptnode { docker.build("${BUILD_ID}", "-f Dockerfile .").inside() { sh 'echo "Hello World!"' } }2.3. Docker Pipeline Plugin実行〜結果確認
2.2.
で作成したジョブ画面の「ビルド実行」をクリックします。
今回のサンプルでは、コンソールにHello World!
と出力するだけなので、ビルド履歴画面「Console Output」から、以下のような出力がなされていれば成功です!コンソール出力Started by user admin Running in Durability level: MAX_SURVIVABILITY [Running on Jenkins in /var/jenkins_home/workspace/sample [Pipeline] { [Pipeline] isUnix [Pipeline] sh + docker build -t 8 -f Dockerfile . Sending build context to Docker daemon 2.048kB Step 1/1 : FROM alpine:latest ---> 965ea09ff2eb Successfully built 965ea09ff2eb Successfully tagged 8:latest [Pipeline] isUnix [Pipeline] sh + docker inspect -f . 8 . [Pipeline] withDockerContainer Jenkins seems to be running inside container 0fb06afff12dcba3803da391819176848ca54934737d486d99a72210b37c9955 $ docker run -t -d -u 1000:1000 -w /var/jenkins_home/workspace/sample --volumes-from 0fb06afff12dcba3803da391819176848ca54934737d486d99a72210b37c9955 -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** 8 cat $ docker top 873e72d4af7ed99be93d4cdc85b800bc36f1bf8df4992597c18ad4ac67575dd0 -eo pid,comm [Pipeline] { [Pipeline] sh + echo 'Hello World!' Hello World! [Pipeline] } $ docker stop --time=1 873e72d4af7ed99be93d4cdc85b800bc36f1bf8df4992597c18ad4ac67575dd0 $ docker rm -f 873e72d4af7ed99be93d4cdc85b800bc36f1bf8df4992597c18ad4ac67575dd0 [Pipeline] // withDockerContainer [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESSおわりに
0 -> 1のステップを超えるためには多大な労力を要します(要しました)。
この記事が、第二、第三のワタシの労力を減らすお役にたつことががあれば幸いです。参考
Docker関連
- docker/Dockerfile at 2.60.3 · jenkinsci/docker
- Dockerfileにおけるキャッシュの削除 - ばいばいバイオ
- Get Docker Engine - Community for Debian | Docker Documentation
- Post-installation steps for Linux | Docker Documentation
- Docker in Docker のベタープラクティス - Qiita
- Docker for windows で /var/run/docker.sock をマウントできるようにする - Qiita
- How to fix docker: Got permission denied while trying to connect to the Docker daemon socket | DigitalOcean
- Docker build does not work on Windows · Issue #1341 · containous/traefik
Jenkins(Docker Pipeline Plugin)関連
- Jenkins 導入手順 2018年版 - Qiita
- Jenkinsジョブ(ビルド~テスト)をDockerコンテナ上で実行する ~Docker Pipeline Pluginを使ってみる~ - SIerだけど技術やりたいブログ
- 爆速でJenkinsをマスターしよう(Docker編) ~ JenkinsコンテナへのDockerインストール方法からJob DSL、Jenkins Pipelineまで ~ | Casual Developers Note
CIツール選定
- 投稿日:2019-12-15T18:34:44+09:00
Nginx + uWSGI + Python(Django)の環境をdockerで作成する
この記事はウェブクルー Advent Calendar 2019の16日目の記事です。
昨日は@Hideto-Kiyoshima-wcさんのScalaのOption/Either/Try超入門でした。はじめに
株式会社ウェブクルーに新卒で入社して、2年目の@yagiyuuuuです。
現在、Nginx + uWSGI + Python(Django)のアプリ環境をDockerで作成して、開発をしています。
これから、Djangoでアプリ開発をする人の助けになればと思い、この記事を書きました。Docker for Windowsのインストール
コントロールパネルを開いて、
「プログラムと機能」→「Windowsの機能を有効化または無効化」→「Hyper-V」にチェックが入っているか確認します。
チェックが入っていなかった場合は、チェックを入れてPCを再起動させて有効化させます。
次に「Docker Desktop for Windows」のインストールをする。
インストールはここからできます。Djangoを動かす環境構築
ディレクトリ構成
Infrastrcuture作成
Alpineにpython + uWSGI、Nginxをインストールします。
docker-compose.yml作成
Nginxとpython + uWSGIのコンテナを作成します。
今回はログをdjango-sample配下に出力するようにしていますが、お好きなところにログを吐き出すように設定してください。django-sample/docker-compose.ymlversion: '2' services: nginx: build: "./Infrastructure/nginx/" volumes: - ./logs/nginx:/var/log/nginx ports: - "80:80" networks: django-sample-network: ipv4_address: 172.23.0.4 python: build: "./Infrastructure/python/" volumes: - ./Application/django-sample:/home/work/django-sample - ./logs/django:/home/work/django - ./logs/uwsgi:/home/work/uwsgi ports: - "8000:8000" networks: django-sample-network: ipv4_address: 172.23.0.5 networks: django-sample-network: driver: bridge ipam: driver: default config: - subnet: 172.23.0.0/24Dockerfile作成
Nginx
django-sample/Infrastructure/nginx/DockerfileFROM nginx:1.13.1-alpine COPY work/nginx.conf /etc/nginx RUN apk --no-cache add tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ apk del tzdata CMD ["nginx", "-g", "daemon off;"]uWSGI
django-sample/Infrastructure/python/DockerfileFROM python:3.7 ENV LANG C.UTF-8 ENV TZ Asia/Tokyo RUN mkdir /home/work RUN mkdir /home/work/django RUN mkdir /home/work/uwsgi COPY work/ /home/work WORKDIR /home/work RUN pip install --upgrade pip RUN pip install -r requirements.txt CMD ["uwsgi", "--ini", "/home/work/uwsgi.ini"]Nginxの設定
django-sample/Infrastructure/nginx/work/nginx.confworker_processes auto; error_log /var/log/nginx/error_app.log; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access_app.log main; sendfile on; tcp_nopush on; keepalive_timeout 120; proxy_read_timeout 120; proxy_send_timeout 120; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 80 default_server; server_name _; fastcgi_read_timeout 60s; client_max_body_size 1m; location ~ ^/app/ { add_header Cache-Control no-cache; include uwsgi_params; uwsgi_pass 172.23.0.5:8000; uwsgi_read_timeout 60s; } } }uWSGI + Djangoの設定
django-sample/Infrastructure/python/work/uwsgi.ini[uwsgi] chdir=/home/work/django-sample module=django-sample.wsgi master=True vacuum=True max-requests=5000 socket=:8000 py-autoreload=1 logto=/home/work/uwsgi/django-app.log buffer-size=10240 log-format=%(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size)`` "%(referer)" "%(uagent)"django-sample/Infrastructure/python/work/requirements.txtdjango==2.2 uwsgi==2.0.17.1
requirements.txt
にインストールしたいモジュールを記載します。.envファイル作成
django-sample/.envCOMPOSE_FILE=docker-compose.ymlApplication作成
ここではアプリを作成することに焦点を当てていますので、
Djangoアプリの詳細に関しては、公式サイトなどをみていただきたいです。
また、__init__.py
と__pycache__
にはコードを書きませんが、作成をしてください。
作成されていないとアプリが動かなくなってしまいます。プロジェクト作成
django-sample/Application/django-sample/manage.py#!/usr/bin/env python import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django-sample.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv)django-sample/Application/django-sample/django-sample/settings.py""" Django settings for django-sample project. Generated by 'django-admin startproject' using Django 2.0.3. For more information on this file, see https://docs.djangoproject.com/en/2.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.0/ref/settings/ """ import os import json import traceback # ログ出力で仕様するハンドラを指定する LOG_HANDLER = ["app"] # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'ekf!&30u3&idt-qr3250(t+j#%@(vyxr02c-7fj!a81$!)#q=(' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True # 接続を許可するサーバのIPやドメインを設定する # 何も設定していない場合は、ローカルホスト(localhost)からの接続のみ可能な状態 ALLOWED_HOSTS = ["localhost"] # Application definition # 「app」を追加。これを追加しないとtemplatetagsに定義したカスタムタグが認識されない INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app', ] ROOT_URLCONF = 'django-sample.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR, 'templates'), ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'django-sample.wsgi.application' # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.0/topics/i18n/ #LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'ja' #TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Tokyo' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.0/howto/static-files/ STATIC_URL = '' LOGGING = { 'version': 1, 'formatters': { 'app': { 'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d %(message)s' } }, 'handlers': { 'app': { 'level': 'DEBUG', 'class': 'logging.handlers.TimedRotatingFileHandler', 'filename': '/home/work/django/app.log', 'formatter': 'app', 'when': 'D', # 単位 Dは日 'interval': 1, # 何日おきか指定 'backupCount': 30, # バックアップ世代数 } }, 'loggers': { 'django': { 'handlers': ['app'], 'level': 'DEBUG', 'propagate': True, }, 'django.server': { 'handlers': ['app'], 'level': 'DEBUG', 'propagate': True, }, 'app': { 'handlers': LOG_HANDLER, 'level': 'DEBUG', 'propagate': True, }, }, } # セッションエンジンの設定 # cookieを用いたセッションを使用する SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # ログイン状態の有効期限(秒) # ここに指定した有効期限(秒)を超えるまでログイン状態を保つ事ができる # セッション自体の有効期限はSESSION_COOKIE_AGE # 8h * 60m * 60s LOGIN_LIMIT = 28800 # セッションの有効期間(秒) # 利用者毎にセッション有効期間を変えたい場合は、request.session.set_expiry(value)を用いる SESSION_COOKIE_AGE = 1800django-sample/Application/django-sample/django-sample/urls.py"""django-sample URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.urls import path, include urlpatterns = [ path('app/', include("app.urls")), ]django-sample/Application/django-sample/django-sample/wsgi.py""" WSGI config for django-sample project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ """ import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django-sample.settings") application = get_wsgi_application()アプリ作成
djnago-sample
プロジェクト内にアプリを作成します。django-sample/Application/django-sample/app/urls.pyfrom django.urls import path from app.views.login import view as login_view urlpatterns = [ path("", login_view.top, name="login_top") ]django-sample/Application/django-sample/app/views/login/view.pyfrom django.http import HttpResponse from django.http.request import HttpRequest from django.template import loader def top(request: HttpRequest): template = loader.get_template("login/index.html") return HttpResponse(template.render({}, request))画面表示させるテンプレート作成
django-sample/Application/django-sample/templates/login/index.htmlHello Django!!コンテナを立ち上げる
docker-compose.yml
がある階層で以下コマンドを叩くコンテナのビルド、起動
$ docker-compose up --build -d
-d
をつけることでバックグラウンドで起動できるコンテナを確認する
$ docker-compose psコンテナを削除する
$ docker-compose down作成したアプリにアクセスする
コンテナを起動したら、
http://localhost/app/
にアクセスすると
Hello Django!!
が表示される終わりに
Djangoアプリを作成していく上で、自分好みの環境にしていってください!!
明日の記事は@yuko-tsutsuiさんです。
よろしくお願いします。
- 投稿日:2019-12-15T18:32:09+09:00
Dockerで開発用のMySQLを構築する
Dockerでサクッと開発用のMySQLを構築する
勉強用にサクッとMySQLの環境がほしかったのでメモ。
環境
Docker Desktop 2.1.0.5構築と利用
MYSQL_ALLOW_EMPTY_PASSWORD
でパスワード不要にする。$ docker run --name mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql:5.7docker containerに入ってMySQLを試す。
$ docker exec -it mysql mysql削除
終わったら削除する。
$ docker stop mysql $ docker rm mysql参考
- 投稿日:2019-12-15T18:09:03+09:00
起動中のDockerコンテナのstdinに入力する
概要
こんにちは、haniokasaiです。
Dockerでdocker attach するとき、インタラクティブに操作できるのはpid 1だけです。1
通常それで困りませんが、私は困りました。
私のコンテナではDockerfileはシェルスクリプトを呼び出し、そのシェルスクリプトがPHP CGIを実行します。その場合は、phpのpidは1ではないので入力するすべがありません。(出力はattachで見れます。)
ですので、stdinに直接入力してあげました。環境
- Ubuntu 18.04 on XFS
- Docker
ホスト to コンテナのstdin
注意
docker attachはしていても構いませんが、interactiveにはしないでください。
していると、stdinは「Text file busy」と返して成立しません。
attach時には以下のようにします。(この場合はattachではstdinを受けません。attachかファイル直接入力かどちらかを選ぶということ。)attachdocker -H DOCKERHOST attach コンテナ名 --no-stdinまず、topで標準入力先のpidを確認します。
# docker top zzzzzzzz_container UID PID PPID C STIME TTY TIME CMD root 25312 25287 0 16:09 ? 00:00:00 /bin/sh -c sh /minecraft/resources/run-Main.sh root 25366 25312 0 16:10 ? 00:00:00 sh /minecraft/resources/run-Main.sh root 25434 25366 0 16:10 ? 00:00:00 sh /minecraft/resources/run-BE-BDS.sh root 25472 25434 13 16:10 ? 00:14:22 /minecraft/bin/bedrock_server標準入力をコマンドで実行します
# echo "help" > /proc/25472/fd/0
helpをbedrock_serverに標準入力すると、ヘルプがちゃんと返されます。
# docker logs zzzzzzzz_container --tail=10 [2019-12-15 08:09:39 INFO] Player disconnected: hanicraft, xuid: 2535460621431466 §2--- Showing help page 1 of 18 (/help <page>) --- /? [command: CommandName] /? <page: int> /alwaysday [lock: Boolean] /changesetting allow-cheats <value: Boolean> /changesetting difficulty <value: Difficulty> /changesetting difficulty <value: int> /clear [player: target] [itemName: Item] [data: int] [maxCount: int] §2Tip: Use the <tab> key while typing a command to auto-complete the command or its argumentsコンテナ to コンテナのstdin
送信元コンテナ作成
docker create --name コンテナ名 --memory=3500mb --network="host" --storage-opt size=2G --cap-add SYS_PTRACE -v /proc:/newproc:ro注目ポイントは
- SYS_PTRACE権限の追加
- ホストの/procを/newprocとして読み取り専用でマウント
あとはさっきと同じです。
コンテナ内# echo "help" > /newproc/25472/fd/0
利用して作ったライブラリ
@itsu_dev と作りました。
いつくんがtopのスクレイピングしてくれているので興味深いでしょう。参考文献
https://serverfault.com/questions/178457/can-i-send-some-text-to-the-stdin-of-an-active-process-running-in-a-screen-sessi
https://orebibou.com/2016/04/linux%E3%81%A7%E5%8B%95%E4%BD%9C%E4%B8%AD%E3%81%AE%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%81%AE%E5%87%BA%E5%8A%9B%E5%86%85%E5%AE%B9%E3%82%92%E3%81%BF%E3%82%8B/脚注
- 投稿日:2019-12-15T17:52:49+09:00
Docker Toolboxでローカルホストにアクセスする
Docker-Toolboxを使っているとき、localhostにアクセスできずに少し詰まったのですが、意外と忘れてしまうのでメモしておきます。
環境
- windows 10 home
- Docker-Toolbox
Docker-Toolboxとは
macやwindows 10 ProではないPCにdockerを導入する際に利用するもの。
詳しくはこちらの記事がわかりやすいです。
windows 10 home で docker を導入するメモlocalhostへアクセス
Docker-Toolboxは他のDockerと違い、localhostへアクセスする際にはひと手間必要です。
コンテナを立ち上げたあと、localhostでアクセスしようとしてもアクセスできません。
docker-machineのIPを確認する
docker-machine ip
で自分が今コンテナを動かしている仮想マシンのIPを確認します。$ docker-machine ip 192.168.99.102取得したIPとポートでアクセス
今回はコンテナに3000ポートでマッピングしているため
http://192.168.99.102:3000
でアクセス。
コンテナで起動しているRailsが無事表示されました。
まとめ
Docker-Toolbox上のコンテナにアクセスする場合は、仮想マシンのIPを確認する。
何度やってもたまに忘れてしまうので、気をつけたい。。。
- 投稿日:2019-12-15T17:47:19+09:00
Dockerのコンテナ内で設定したエイリアスがログアウトしたら無効になってしまう件について
Dockerで開発環境を構築してTDDを用いて個人開発をしてたのですが、テストを実行する度に
$ vendor/bin/phpunitと入力するのめんどくさいですよね。
そこでエイリアスを設定して、puと入力したらテストを走らせるようにしようとしたのですが、コンテナ無いから抜けたらエイリアスが使えないという現象に出くわしたので忘備録として残しておきます。
// ashでAppコンテナ内に入る $ docker-compose exec app ash // ルートディレクトリに移動 $ cd / // .profileファイルをviコマンドで開く $ vi .profile #.profileファイル内に下記を追加 alias pu="clear && vendor/bin/phpunit" // ファイルの読み込み直し $ source .profile // ドキュメントルートに移動 $ cd /work/ // エイリアスで設定したコマンドを実行 $ pu ←ここでは実行できる // 一旦コンテナを抜ける $ exit // ashでAppコンテナ内に再び入る $ docker-compose exec app ash // エイリアスで設定したコマンドを実行 $ pu ←ここではエイリアスで設定したコマンドが実行できない ash: pu: not found原因として、コンテナ内に入った時はデフォルトでは非ログインシェル状態だそうです。
そのためユーザーを変更して上げる必要があるみたいです。// ashでAppコンテナ内に入る $ docker-compose exec app ash // ashユーザーにスイッチ $ ash -l // エイリアスで設定したテストを走らせる $ pu間違ってたら優しくご指摘お願いします。
- 投稿日:2019-12-15T17:18:00+09:00
Docker チートシート
- 投稿日:2019-12-15T13:13:28+09:00
Dockerの CentOS8 イメージのlocale 設定
- 投稿日:2019-12-15T12:05:14+09:00
CentOS8イメージでコンテナを作成 ユーザ追加とsudo権限付与
概要
Docker のCentOS8 イメージを取得し、sudo権限を持ったユーザを作成するところまで。
以前書いた下記の記事のCentOS8版になります。
Docker(CentOS)イメージから新規ユーザを追加し運用できるようにするまで
https://qiita.com/libra_lt/items/dd98297cb00aaf1c4c67手順
イメージ取得
docker pull centos:8起動
デタッチ起動する場合のみ-dオプションつけます。
docker run --name cos8 --privileged -d centos:8 /sbin/init実行
デタッチ起動した場合は下記コマンドでインタラクティブモードに。
docker exec -it コンテナID /bin/bashsudo付与
ユーザを追加してsudo権限を付与する手順
sudoインストール
dnf -y update dnf -y sudo passwd cracklib-dictsユーザ追加
useradd -m ユーザ名パスワード設定
下記コマンド実行後、パスワードを設定する
passwd ユーザ名sudo設定追加
sudo設定ファイルにユーザを追加
echo "ユーザ名 ALL=(ALL) ALL" >> /etc/sudoers以上
- 投稿日:2019-12-15T11:36:01+09:00
Dockerにおけるbinding.pryの使い方
はじめに
今回はdockerでポートフォリオを作成中なのですがこれまで使用していた仮想環境とdockerでbinding.pryの使い方が違ったのでまとめておきます。
全体流れ
gemのインストール
↓
デバッグしたい箇所にpry
↓
コンテナを再起動
↓
railsコンテナにアタッチして接続
↓
デバッグgemのインストール
gemfileに記入してbundle installです。開発環境でしか使用しないのでdevelopmentに書いています。
デバッグしたい箇所にpry
コンテナを再起動、アタッチで接続
docker psで起動中のコンテナの確認、docker attach コンテナ名でコンテナに接続します。この状態で記入した画面でリロード、操作すると中断されてインスタンス変数の中身の確認等を行うことができます。
ctrキー→p→qの順番で抜けれます
- 投稿日:2019-12-15T09:32:08+09:00
Mac+Docker+ubuntu (??)
動作環境
Mac OS Catalina 10.15.1
概要
Mac上でROSを動かしたいと思い、公式を確認したところサポートされてるのがubuntu上だけだったので、Dockerを使ってubuntuを入れた後、その中でROSを動かしたいと思ったのでその実行手順をまとめておこうと思う。rosを入れる手順は別の記事でまとめようと思う。
まずはDockerをインストールする
とりあえず、MacにDockerをインストールする
https://hub.docker.com/editions/community/docker-ce-desktop-mac
公式サイトでまずは自分のアカウントを作ってログインする
そして右上のGet Dockerからインストールできる
この時、ターミナル上で以下のコマンドでちゃんとインストールされたか確認できる
docker versionこの時、macのアプリケーションフォルダに入ってるDockerをクリックして起動させてないといけないらしく、参考にした記事には載ってなかったのでこちらには載せておく
ubuntuを入れる
これでDockerは入ったのでubuntuを入れていく
docker pull ubuntu:16.04今回はubuntu 16.04を入れる
https://hub.docker.com/_/ubuntu/
こちらのdockerhubの方でpull可能なubuntuのバージョンは載ってるので好きなのを入れましょう
docker imagesこれでpullしたものを確認する
ubuntu16.04があればきちんとpullできている
ubuntuが入ったら
まずはubuntuの起動をする
docker run -it -d --name ubuntu1604 ubuntu:16.04dockerのrunコマンドで起動する
正しく起動されてるか確認する
docker psコンテナ名はubuntu1604なので、正しく起動されてたら出てくると思う
もし、出てこない場合は
docker ps -aこれでpullがちゃんとできてるか確認する
起動したらそのコンテナに入る
docker exec -it ubuntu1604 /bin/bashこれでコンテナ内に入れた
抜けたい時は
exit再度入りたい場合は
docker exec -it ubuntu1604 bashこれで入れる
コンテナを停止させる場合
docker stop ubuntu1604再度動かす場合
docker start ubuntu1604停止と再起動はどちらもコンテナから抜けてからやる必要がある
ubuntuに入った状態でまずはユーザーを追加する
adduser user_nameuser_nameには自分の好きな名前を入れよう
gpasswd -a user_name sudoこれでubuntu内でユーザーが追加された
これで一通りできたわけだが、例えばubuntu内でpythonのコードを書いて実行するには
ファイルの読み書きができないといけないが、docker内で処理されるので、macに入れてるテキストエディタは使えないということでubuntuにvimを入れておいた
sudo apt-get update sudo apt-get install vimこれでvimをインストールできた
参考文献
Dockerをインストールした時に参考にさせていただいた
https://qiita.com/kurkuru/items/127fa99ef5b2f0288b81ubuntu入れる時に参考にさせていただいた
https://weblabo.oscasierra.net/docker-ubuntu1604/ユーザーを追加する時に参考にさせていただいた
https://qiita.com/white_aspara25/items/c1b9d02310b4731bfbaavim入れる時参考にさせていただいた
https://qiita.com/YumaInaura/items/3432cc3f8a8553e05a6e
- 投稿日:2019-12-15T07:19:14+09:00
DockerのMySQLに,GDALを使ってシェープファイルをインポートしてみる
概要
本記事では,Docker環境において,シェープファイルをもとにしたジオメトリデータを提供するサーバを構築してみます.
ジオメトリデータはMySQLに格納し,クライアントからのリクエストに応じてデータを受け渡すことを想定します.シェープファイル のジオメトリデータを MySQL にインポートするには,GDALというGISライブラリの ogr2ogr を用います.GDALのインポート方法はいくつかあるのですが,本記事ではGDALのDockerイメージを使用します.例としてNode.js(Express)のDockerアプリにGDALを組み込んで,Docker Composeで構築していきます.
環境
- Windows10 Pro 64bit
- Docker for Windows 19.03.2
- docker-conpose 1.24.1
- Node.js 12.13.0 ※expressの雛形形成のためにローカルで使います
- npm --version 6.12.0
実装
Expressの雛形を準備
ExpressのDocker環境の構築は,基本的に docker-compose(Docker for mac)で実践的なnode.js開発環境を作る の手順を継承します.
まず,作業ディレクトリで
express
とexpress-generator
をインストールします.ただし,global環境へのインストールは避けたいので,下記のようにします.$ npm install --save express $ npm install --save express-generator次に,雛形を作るコマンドを実行します.npmでライブラリをローカルにインストール際にはpathが通らないので,下記のようにcmdファイルを指定します.
myapp
は各自任意の命名をしてください.
テンプレートエンジンはhtmlをほぼそのまま扱えるejs
を指定していますが,各自の開発に合わせて設定してください.なにも指定しない場合のデフォルトは,jade
になります.ejsやjadeの違いはこちらを参照.$ ./node_modules/.bin/express.cmd myapp --view=ejs以上で ,
myapp
配下に Express の雛形が生成されました.以降の作業ディレクトリは,./myapp
配下になります.docker-compose.ymlの作成
myapp
直下に,下記の docker-compose.yml を置きます.docker-compose.ymlversion: '2' services: nginx: image: nginx:alpine container_name: nginx ports: - "80:80" volumes: - "./conf.d:/etc/nginx/conf.d" links: - node_express networks: - app-net node_express: image: node:6.9-alpine container_name: node_express hostname: node_express volumes: - ".:/src" working_dir: /src command: [sh, -c, npm install && npm start] ports: - "3000:3000" links: - mysql networks: - app-net mysql: image: mysql:5.7 container_name: mysql hostname: mysql command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci ports: - "3306:3306" environment: - "MYSQL_ROOT_PASSWORD=root" volumes: - ./db/mysql-data:/var/lib/mysql networks: - app-net gdal: image: osgeo/gdal:ubuntu-full-3.0.2 container_name: gdal hostname: gdal volumes: - "./geodata:/home" tty: true networks: - app-net networks: app-net: driver: bridgeポイントは,以下の3点.
- gdalコンテナは
tty: true
をつけないとコンテナが維持されない.- gdalコンテナは
./geodata:/home
をマウントし,ここにMySQLに入力したいシャープファイルを配置する.- 各コンテナに
networks
を指定し,この後 MySQL の入出力データを各コンテナから通信できるようにする.また,参考記事と同様に
./conf.d
フォルダを作成し,その配下に下記 nginx 用のファイルを置きます.nodejs.confserver { listen 80; server_name _; client_max_body_size 10M; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://node_express:3000/; } }シェープファイルのダウンロード と 作業ディレクトリへの配置
今回は例として,国土交通省が公開している国土数値情報のうち,
低位地帯データ(神奈川県)
のシェープファイルをインポートしてみます.
ダウンロードサイトにアクセスし,神奈川県にチェックのうえアンケートに回答しダウンロードします.
G08-15_14_GML.zip
がDLされたと思うので,解凍します.解凍したフォルダ内にG08-15_14.shp
があることを確認します.作業ディレクトリに戻り,docker-compose.ymlと同じ階層に ,docker-compose.yml内でgdalコンテナのマウント先に設定した
geodataフォルダ
を作成します.ここに先程解凍したデータをフォルダごと配置します.Dockerコンテナの立ち上げ
ここまでの作業でDockerコンテナを立ち上げる準備ができたので,
docker-compose.yml
と同じ階層で下記コマンドを実行してコンテナを起動します.
起動後,ブラウザからhttp://localhost:3000
にアクセスして何か表示されれば成功です.また,$ docker ps
コマンドでコンテナが4つ起動していることを確認します.$ docker-compose up -d --buildGDAL(ogr2ogr)を使って シェープファイル を MySQL にインポート
まずはMySQLのDockerコンテナに入り,データベースを作成します.DBの名前は
flood_map
としていますが,ご自身の開発に合わせてDB名を設定します.$ docker exec -i -t mysql bash $ mysql -h 127.0.0.1 -u root -proot mysql> create database flood_map;次に,gdalのDockerコンテナに入り,ogr2ogr を使ってMySQLにデータを入れていきます.
home ディレクトリ配下にシェープファイルを含むファイル群がマウントされますので,ご自身の環境にあわせてシェープファイルを指定します.MySQLのホスト名はMySQLのコンテナ名を指定することでうまくいきます.$ docker exec -i -t gdal bash $ ogr2ogr -f "MySQL" MySQL:"flood_map,host=mysql,user=root,password=root,port=3306" ./home/G08-15_14_GML/G08-15_14.shpMySQLでデータを確認しインデックスを張る
再び MySQL コンテナに戻り,SQLを実行してみてデータが入っていることを確認します.たくさん表示すると問題があるので,上から10件のデータを表示してみます.
mysql> use flood_map; mysql> SELECT ogr_fid,AsText(Envelope(ExteriorRing(shape))) from g08_15_14 limit 10; +---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ogr_fid | AsText(Envelope(ExteriorRing(shape))) | +---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | 1 | POLYGON((139.52142804001 35.6371572663072,139.523032038531 35.6371572663072,139.523032038531 35.6379951881551,139.52142804001 35.6379951881551,139.52142804001 35.6371572663072)) | | 2 | POLYGON((139.521452996084 35.6376134289269,139.521644357377 35.6376134289269,139.521644357377 35.6376736855994,139.521452996084 35.6376736855994,139.521452996084 35.6376134289269)) | | 3 | POLYGON((139.52196220354 35.6369668672147,139.522425630462 35.6369668672147,139.522425630462 35.6371686759932,139.52196220354 35.6371686759932,139.52196220354 35.6369668672147)) | | 4 | POLYGON((139.541073491975 35.6360655457882,139.543607066891 35.6360655457882,139.543607066891 35.6382958203003,139.541073491975 35.6382958203003,139.541073491975 35.6360655457882)) | | 5 | POLYGON((139.540973950349 35.6380131944947,139.541300259083 35.6380131944947,139.541300259083 35.6382231275051,139.540973950349 35.6382231275051,139.540973950349 35.6380131944947)) | | 6 | POLYGON((139.543183728112 35.6372670693054,139.543547637788 35.6372670693054,139.543547637788 35.6377649038623,139.543183728112 35.6377649038623,139.543183728112 35.6372670693054)) | | 7 | POLYGON((139.543439171221 35.6369067894177,139.543604469296 35.6369067894177,139.543604469296 35.6370422598022,139.543439171221 35.6370422598022,139.543439171221 35.6369067894177)) | | 8 | POLYGON((139.540877273964 35.6326687791813,139.543489041583 35.6326687791813,139.543489041583 35.6348299205534,139.540877273964 35.6348299205534,139.540877273964 35.6326687791813)) | | 9 | POLYGON((139.20295027585 35.6304782158446,139.204943801785 35.6304782158446,139.204943801785 35.6336142552756,139.20295027585 35.6336142552756,139.20295027585 35.6304782158446)) | | 10 | POLYGON((139.541693310682 35.6317030003044,139.544202942505 35.6317030003044,139.544202942505 35.6332801242532,139.541693310682 35.6332801242532,139.541693310682 35.6317030003044)) | +---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+SQLの説明をすると,MySQLにはジオメトリデータを扱うための関数が用意されています.今回 g08_15_14 テーブルの shape カラムの中に格納されているものは,POLYGON型(≒多角形)のデータで,それぞれが低位地帯の1領域を表します.ExteriorRing()で POLYGON の外周を構成する座標の集合を取得できます.またDB内にはデータがバイナリで保存されていますが,AsText(Envelope()) で人間の読める形に変換しています.
データが格納されていることが確認できたら,インデックスを張ります.MySQLにはジオメトリデータ用のインデックスが用意されています.
mysql> ALTER TABLE g08_15_14 ADD SPATIAL INDEX(shape);DBアクセス用のユーザ作成
rootを使ってDBにアクセスするのはセキュリティ的によろしくないので,権限を絞ったユーザを作成します.APIサーバからアクセスする際はユーザを使ってアクセスすることを想定します.
mysql> CREATE USER 'user1'@"%" IDENTIFIED BY "user1"; mysql> GRANT SELECT ON flood_map.g08_15_14 TO user1@"%";【補足】SRIDについて
ジオメトリデータにはSRID(空間参照識別子)があります.SRIDが何かについて詳細はこちら.今回の神奈川県の低位地帯データは,JGD2011の緯度経度の座標系ですので,本来はSRIDは6668が設定されているべきです.ただ,MySQL5.7でogr2ogrを使うと,SRIDを1から連番で振ってしまいます.※MySQL8であれば正しく設定される模様...
mysql> SELECT * from geometry_columns; +-----------------+----------------+--------------+-------------------+-----------------+------+---------+ | F_TABLE_CATALOG | F_TABLE_SCHEMA | F_TABLE_NAME | F_GEOMETRY_COLUMN | COORD_DIMENSION | SRID | TYPE | +-----------------+----------------+--------------+-------------------+-----------------+------+---------+ | NULL | NULL | g08_15_14 | SHAPE | 2 | 1 | POLYGON | +-----------------+----------------+--------------+-------------------+-----------------+------+---------+SRIDが6668だと思ってるとエラーになります.
mysql> SET @g1 = GeomFromText('Polygon((139.695773 35.532169,139.695773 35.5068084,139.615388 35.5068084,139.615388 35.532169,139.695773 35.532169))', 6668); Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select count(*) from g08_15_14 where MBRIntersects(SHAPE, @g1) = 1; ERROR 3033 (HY000): Binary geometry function mbrintersects given two geometries of different srids: 1 and 6668, which should have been identical.下記であれば通ります.
mysql> SET @g1 = GeomFromText('Polygon((139.695773 35.532169,139.695773 35.5068084,139.615388 35.5068084,139.615388 35.532169,139.695773 35.532169))', 1); Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select count(*) from g08_15_14 where MBRIntersects(SHAPE, @g1) = 1; +----------+ | count(*) | +----------+ | 29 | +----------+ 1 row in set (0.04 sec)コンテナの終了
下記コマンド実行.
$ docker-compose downまとめ
本記事では,Docker環境でジオメトリデータを扱うためのサーバ環境を構築し,実際にデータをMySQLに入れてみました.MySQL内のデータを取り出すためには,node.jsでSQLを叩くAPIを用意し,フロントからアクセスすれば実現可能です.
参考文献
- docker-compose(Docker for mac)で実践的なnode.js開発環境を作る: https://qiita.com/devalon/items/dd0fdce02156855b5df5 (accessed 2019/12/8).
- MySQLに対応したogr2ogr(GDAL)をインストールする方法まとめ: https://qiita.com/miyauchi/items/87921eb3ad630db1624a (accessed 2019/12/8).
- GISのための測地成果、測地系、楕円体、投影座標系、EPSGコードのまとめ: http://tmizu23.hatenablog.com/entry/20091215/1260868350 (accessed 2019/12/8).
- MySQL 空間分析関数: https://dev.mysql.com/doc/refman/5.6/ja/spatial-analysis-functions.html (accessed 2019/12/8).