- 投稿日:2021-01-11T23:32:39+09:00
VSCode + Docker + PHP の開発環境を、XDebugでデバッグする。
はじめに
扱っていたプロジェクトは Laravel を使ったPHPアプリケーションで、VSCodeによって製作されていました。
Java や Swift を使った作業には慣れていたのですが、PHPのデバッグが久しぶりで大いにはまったので備忘録です。やったこと
PHPのデバッグには XDebug を使うということなので、XDebug解説記事 をふむふむと読み(大変わかりやすい記事です)作業に当たりました。
たくさんの記事が丁寧に説明しているので詳細は端折りますが
php.ini;...省略 [XDebug] zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so xdebug.default_enable=1 xdebug.remote_port=9000 xdebug.remote_autostart=1 xdebug.remote_handler=dbgp xdebug.remote_connect_back=0 xdebug.remote_host=host.docker.internal xdebug.remote_log=/tmp/xdebug.log xdebug.idekey=VSCODEDockerfileFROM php:7.4-apache # XDebug RUN pecl install xdebug \ && docker-php-ext-enable xdebug #...省略launch.json{ "version": "0.2.0", "configurations": [ { "name": "Listen for XDebug", "type": "php", "request": "launch", "port": 9000, "log": true, "pathMappings": { "/var/www/html": "${workspaceFolder}/src" }, "ignore": [ "**/vendor/**/*.php" ] } ] }こんな感じで、PHP初期化、Docker初期化、XCodeのデバッグ設定を終えました。
これが全然びくとも動かない。
解決策
いろんなパラメータをいじり倒しましたが全然動かず諦めかけましたが、最終的には xdebug のバージョンの問題ということに気づきました。
$ php -v | grep -i "xdebug" with Xdebug v3.0.2, Copyright (c) 2002-2021, by Derick RethansXdebug 2.x から 3.x で、設定値が様変わりしています。
https://xdebug.org/docs/upgrade_guide
このドキュメントに詳しくわかりやすく書いてあります。たとえば、
xdebug.remote_log
はxdebug.log
に Rename されています。どうりで、ログもさっぱり出ないわけです。細かい意味はそちらを見ていただくとして、上記の
php.ini
は正しくはこうなりました。php.ini;...省略 [XDebug] zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so xdebug.mode=debug xdebug.client_port=9000 xdebug.start_with_request=yes xdebug.discover_client_host=0 xdebug.client_host=host.docker.internal xdebug.log=/tmp/xdebug.log現場からは以上です。
- 投稿日:2021-01-11T22:50:09+09:00
Docker備忘録
Docker, docker-composeを使うときの備忘録。
最初にとても勉強になったサイト: docker と docker-compose の初歩 - Qiita
docker
コマンドdocker run [イメージ名] docker ps # 実行中コンテナ一覧 docker ps -a # 実行中+終了したコンテナ一覧 docker rm [ID] # 終了したコンテナを削除 sudo docker ps -a docker run --name [ラベル名] [コンテナ名] #ラベル名でコンテナを指定する docker image ls #手元にある(ダウンロードの必要がない)dockerイメージを表示 docker rmi [イメージ名] #dockerイメージを削除 docker restart [ID] # 終了したコンテナを実行中に docker attach [ID] # 実行中のコンテナに入る docker exec [ID] [コマンド] #実行中のコンテナにコマンドを与える docker exec -it [ID] /bin/bash # 実行中のコンテナに入る docker commit [停止中の元イメージ名] [作るイメージ名] # 元イメージから作るイメージを作る(以下は自分用に書き換える)
DockerfileFROM centos:7 RUN yum update -y \ && yum install httpd -y \ && echo "hello world from dockerfile" > /var/www/html/index2.html \ && yum clean all ADD ./httpd/www/index.html /var/www/html/ EXPOSE 80 ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
docker-compose
コマンドdocker-compose.ymlがあるディレクトリで
docker-compose up -d # Upにする docker-compose down # 停止中にする
- 投稿日:2021-01-11T22:42:35+09:00
Docker上のFRRoutingでMPLS-VPNを動かしてみる
はじめに
Docker上のFRRoutingでOSPFを動かしてみるに引き続き、個人のノートPCでお手軽に、なるべく省リソースでネットワークの勉強/検証をしたい、という動機から、Docker+FRRoutingを試してみています。今回はMPLS-VPNをやっていきます。
※誤り等ありましたらお気軽にコメントいただければと思います。参考にしたページ
MPLSについてはこちらのページにお世話になっているので、検証構成とコンフィグ設計はこちらをベースにしました。
また、FRRoutingを使ったMPLSの環境構築については、こちらを参考にさせていただきました。
検証環境
- Windows 10 (Core i7, 12GB RAM)
- VirtualBox 6.1
- Ubuntu 18.04 (2 Core, 4GB RAM, 10GB Disk)
- Docker 20.10.2
- FRRouting 7.5
Dockerまではインストールされた状態から始めます。
検証構成
MPLS-VPN 検証構成とコンフィグ設定(PE-CE間でスタティックルートを使用)に則った構成とアドレス設計です。違うのは、各ネットワークで.1ではなく.2を使っていること(Docker networkのbridge用アドレスを.1とするため)、PE1/PE2でコア側をeth0、ユーザ側を順にeth1, 2としている所です。
青字はdocker network(bridge)での実装におけるネットワーク名です。Dockerでは、複数のネットワークをコンテナにアタッチする際、GWやInternal等の属性が同じ場合は、ネットワーク名の辞書順にコンテナ内のeth0, 1, 2, ...に割り当てられるようです1 2。今回、PEルータではコア側をeth0、ユーザ側を順にeth1, 2, ...と統一したかったので、上記のような命名規則で対応することにしました。
全体の流れ
手順全体の流れと、設定対象機器は以下の通りです。
順番 内容 Pルータ PEルータ CEルータ 1 ホストOSの設定 - - - 2 Dockerネットワークとコンテナ作成 ○ ○ ○ 3 FRR daemonの設定 ○ ○ - 4 OSPFの設定 ○ ○ - 5 LDPの設定 ○ ○ - 6 MP-BGPの設定 - ○ - 7 VRFの設定 - ○ - 8 CEルータの設定 - - ○ 1. ホストOSの設定
はじめに、ホストOS(Ubuntu VM)の設定をします。
公式docsに従って、MPLSのカーネルモジュールをロードします。
/etc/modules-load.d/modules.confを編集し、mpls_router、mpls_iptunnelを追加。/etc/modules-load.d/modules.conf# /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. mpls_router mpls_iptunnel# modprobe mpls-router mopls-iptunnel modprobe: FATAL: Module mpls-router not found in directory /lib/modules/4.15.0-124-genericエラーになったので、公式の記載に従って拡張パッケージをインストールします。
# apt install linux-modules-extra-`uname -r`※公式では
apt-get install linux-modules-extra-`uname -r`-generic
となっていましたが最後の-generic
はいらないですね。これで改めてカーネルモジュールをロードします。
# modprobe mpls-router mpls-iptunnel# lsmod | grep mpls mpls_router 28672 0 ip_tunnel 24576 1 mpls_router無事ロードされました。
試しにコンテナを作って、コンテナ内でlsmodをすると、上記2つが反映されています。# docker run -dit --name test alpine # docker exec -it test lsmod | grep mpls mpls_router 28672 0 ip_tunnel 24576 1 mpls_routerMPLS転送を有効にするためのカーネルパラメータの変更は、コンテナ内でやればいいようなので、後でやることにします。
2. Dockerネットワークとコンテナ作成
Docker Network(bridge)を使って独自ネットワークを作り、そこにコンテナをつないでいきます。
ただし、ここで1つ問題があります。Docker Networkを使ったネットワーク作成はお手軽なのですが、コンテナをつないだ際、IPアドレスが自動で設定されます。(もしくは--ipオプションで手動指定)。こうして自動もしくは手動でコンテナkernelによって設定されたIPアドレスは、FRRoutingを使って変更・削除することはできません。また、デフォルトルートを含む複数のルートも自動で設定されてしまい、FRRoutingからは変更・削除できません(かつ、Kernel Routeは最優先)。IPアドレスであればコンテナ作成の際に手動設定してしまい、FRRoutingからは触らないようにする、というのも可能ですが、最大限vtyshを使って設定したいですし、ルートの方はネットワーク設定に支障がある場合もありますので、
ip addr del
やip route del
コマンドで削除する必要があります。
※こうした自動設定を止める設定があるかもしれませんが見つけられていません...地道に1つずつ手動で消していってもいいのですが、今回コンテナが7つもあるので、そういった初期設定済みのFRRイメージを作成するDockerfileを作りました。これを使って作った独自のFRRイメージを使って環境構築していきたいと思います。ついでにtcpdumpもインストールしています。
(tcpdumpに関してはホストOS側でvethを特定して...でもいいですが)初期設定済みのFRRoutingイメージを作る
適当なフォルダにDockerfileを作ります。
DockerfileFROM frrouting/frr:v7.5.0 RUN apk update && apk add tcpdump COPY docker-start /usr/lib/frr/docker-startもともとのFRRoutingのイメージに、tcpdumpをインストールし、かつヘルパースクリプトを独自のものに置き換えています。
同じディレクトリにdocker-startという名前でヘルパースクリプトを作成。
docker-start#!/bin/sh set -e # Delete all IP addresses on ethX devlist=`ip -o addr | cut -d\ -f 2 | sed '1d'` for dev in $devlist do IP=`ip -o addr show $dev | cut -d\ -f 7` ip addr del $IP dev $dev done # Delete all routes routelist=`ip route | cut -d\ -f 1` for route in $routelist do ip route del $route done ## # For volume mounts... ## chown -R frr:frr /etc/frr || true /usr/lib/frr/frrinit.sh start # Sleep forever exec tail -f /dev/nullこれは、もともとFRRoutingで使われているスクリプトに、IPアドレスとルート全削除の処理を加えたものです。
スクリプトに実行権限を与えて、docker build
# chmod +x docker-start # docker build -t frr . # docker images REPOSITORY TAG IMAGE ID CREATED SIZE frr latest 42eb8fb2ebb3 4 seconds ago 128MB以降、コンテナ作成の際は
frrouting/frr:v7.5.0
ではなく、frr
を使っていきます。ネットワークの作成
まずnetworkを作ります。
# docker network create net1 --subnet=10.1.1.0/24 # docker network create net2 --subnet=10.1.2.0/24 # docker network create net3 --subnet=172.16.1.0/24 # docker network create net4 --subnet=172.16.2.0/24 # docker network create net5 --subnet=172.16.3.0/24 # docker network create net6 --subnet=172.16.4.0/24# docker network ls NETWORK ID NAME DRIVER SCOPE 4f627b43f43a bridge bridge local 62dced673495 host host local b6c924d827f5 net1 bridge local ac750081ae13 net2 bridge local f96230418508 net3 bridge local 9553456d0ad7 net4 bridge local 5c39ee2ea4d7 net5 bridge local f2e362f4eaad net6 bridge local 20f96b0038a3 none null localPルータの作成
名前が1文字のコンテナは作れないようだったので、コンテナ名、ホスト名はPRとしました。
# docker create -it --name PR --hostname PR --privileged --net net1 frr # docker network connect net2 PR # docker start PRいきなり
docker run
するのではなく、docker create
docker network connect
でネットワークを全部つないでからコンテナを起動します。PEルータの作成
# docker create -it --name PE1 --hostname PE1 --privileged --net net1 frr # docker network connect net3 PE1 # docker network connect net5 PE1 # docker start PE1 # docker create -it --name PE2 --hostname PE2 --privileged --net net2 frr # docker network connect net4 PE2 # docker network connect net6 PE2 # docker start PE2CEルータの作成
# docker run -dit --name CE1 --hostname CE1 --privileged --net net3 frr # docker run -dit --name CE2 --hostname CE2 --privileged --net net4 frr # docker run -dit --name CE3 --hostname CE3 --privileged --net net5 frr # docker run -dit --name CE4 --hostname CE4 --privileged --net net6 frr動作確認
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 01c534d3bafa frr "/sbin/tini -- /usr/…" 5 seconds ago Up 3 seconds CE4 861ce203d498 frr "/sbin/tini -- /usr/…" 20 seconds ago Up 19 seconds CE3 acd7834f981b frr "/sbin/tini -- /usr/…" 32 seconds ago Up 31 seconds CE2 5ce59162b01b frr "/sbin/tini -- /usr/…" 56 seconds ago Up 54 seconds CE1 99bb821a4cb8 frr "/sbin/tini -- /usr/…" 4 minutes ago Up 3 minutes PE2 824e0a5a5337 frr "/sbin/tini -- /usr/…" 5 minutes ago Up 5 minutes PE1 aeaab8e9b887 frr "/sbin/tini -- /usr/…" 6 minutes ago Up 6 minutes PRコンテナが7つ起動していることを確認します。
3. FRR Daemonの設定
FRRの設定ファイルで、起動するdaemonを指定します。
/etc/frr/daemons
を編集し、起動するdaemonをyes
にしていきます。各ルータにおいて(追加で)起動するdaemonは以下の通り。
ルータ種別 起動するdaemon Pルータ ospfd, ldpd PEルータ bgpd, ospfd, ldpd CEルータ - 今回、CEルータとPEルータの間はStaticルーティングを使うため、CEルータでは特に追加でdaemonを起動する必要はありません。
Pルータ
/etc/frr/daemons(略) ospfd=yes (略) ldpd=yes (略)PEルータ
/etc/frr/daemons(略) bgpd=yes (略) ospfd=yes (略) ldpd=yes (略)それぞれ、設定ファイルの編集が終わったら設定反映のため、FRRのプロセスを再起動します。
Pルータの例:
PR/ # /usr/lib/frr/frrinit.sh restart Stopped watchfrr Cannot stop ldpd: pid file not found Cannot stop ospfd: pid file not found Stopped staticdStopped zebra Started watchfrrCannot stop ldpdとCannot stop ospfdが出ていますが、初回なので問題ありません。
動作確認
各コンテナ内で、指定したプロセスが立ち上がっているか確認します。
Pルータの例:PR/ # ps PID USER TIME COMMAND 1 root 0:00 /sbin/tini -- /usr/lib/frr/docker-start 7 root 0:00 tail -f /dev/null 56 root 0:00 /bin/sh 88 root 0:00 /usr/lib/frr/watchfrr -d -F traditional zebra ospfd ldpd staticd 106 frr 0:00 /usr/lib/frr/zebra -d -F traditional -A 127.0.0.1 -s 90000000 111 frr 0:00 /usr/lib/frr/ospfd -d -F traditional -A 127.0.0.1 114 frr 0:00 /usr/lib/frr/ldpd -L -u frr -g frr 115 frr 0:00 /usr/lib/frr/ldpd -E -u frr -g frr 116 frr 0:00 /usr/lib/frr/ldpd -d -F traditional -A 127.0.0.1 120 frr 0:00 /usr/lib/frr/staticd -d -F traditional -A 127.0.0.1 122 root 0:00 psospfdとldpdが立ち上がっています。
4. OSPFの設定
まずはMPLSコア網の土台となるアンダーレイネットワークを作っていきます。今回はIGPとしてOSPFを使用。また、各ルータのループバックIFとして、dummy IFを作るやり方のページもありますが、本記事では各コンテナに最初からある
lo
を活用していきます。Pルータ
PR(vtysh)PR# conf PR(config)# interface lo PR(config-if)# ip address 9.9.9.9/32 PR(config-if)# exit PR(config)# interface eth0 PR(config-if)# ip address 10.1.1.254/24 PR(config-if)# exit PR(config)# interface eth1 PR(config-if)# ip address 10.1.2.254/24 PR(config-if)# exit PR(config)# router ospf PR(config-router)# network 9.9.9.9/32 area 0 PR(config-router)# network 10.1.1.0/24 area 0 PR(config-router)# network 10.1.2.0/24 area 0 PR(config-router)# endPEルータ
PE1(vtysh)PE1# conf PE1(config)# interface lo PE1(config-if)# ip address 1.1.1.1/32 PE1(config-if)# exit PE1(config)# interface eth0 PE1(config-if)# ip address 10.1.1.2/24 PE1(config-if)# exit PE1(config)# interface eth1 PE1(config-if)# ip address 172.16.1.254/24 PE1(config-if)# exit PE1(config)# interface eth2 PE1(config-if)# ip address 172.16.3.254/24 PE1(config-if)# exit PE1(config)# router ospf PE1(config-router)# network 1.1.1.1/32 area 0 PE1(config-router)# network 10.1.1.0/24 area 0 PE1(config-router)# endPE2(vtysh)PE1# conf PE1(config)# interface lo PE1(config-if)# ip address 2.2.2.2/32 PE1(config-if)# exit PE1(config)# interface eth0 PE1(config-if)# ip address 10.1.2.2/24 PE1(config-if)# exit PE1(config)# interface eth1 PE1(config-if)# ip address 172.16.2.254/24 PE1(config-if)# exit PE1(config)# interface eth2 PE1(config-if)# ip address 172.16.4.254/24 PE1(config-if)# exit PE1(config)# router ospf PE1(config-router)# network 2.2.2.2/32 area 0 PE1(config-router)# network 10.1.2.0/24 area 0 PE1(config-router)# end動作確認
Pルータで確認してみます。
PR(vtysh)PR# show ip ospf neighbor Neighbor ID Pri State Dead Time Address Interface RXmtL RqstL DBsmL 1.1.1.1 1 Full/Backup 36.732s 10.1.1.2 eth0:10.1.1.254 0 0 0 2.2.2.2 1 Full/Backup 34.071s 10.1.2.2 eth1:10.1.2.254 0 0 01.1.1.1, 2.2.2.2とneighborが確立できていることを確認。
PR(vtysh)PR# show ip route Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup O>* 1.1.1.1/32 [110/10] via 10.1.1.2, eth0, weight 1, 00:04:48 O>* 2.2.2.2/32 [110/10] via 10.1.2.2, eth1, weight 1, 00:01:19 O 9.9.9.9/32 [110/0] is directly connected, lo, weight 1, 00:09:18 C>* 9.9.9.9/32 is directly connected, lo, 00:12:31 O 10.1.1.0/24 [110/10] is directly connected, eth0, weight 1, 00:09:08 C>* 10.1.1.0/24 is directly connected, eth0, 00:12:00 O 10.1.2.0/24 [110/10] is directly connected, eth1, weight 1, 00:08:45 C>* 10.1.2.0/24 is directly connected, eth1, 00:11:391.1.1.1/32, 2.2.2.2/32へのルートがOSPFによって学習できており、FIBに載っていること(*がついていること)を確認します。
念のためpingも。vtyshから抜けて確認。
PR/ # ping -I 9.9.9.9 1.1.1.1 PING 1.1.1.1 (1.1.1.1) from 9.9.9.9: 56 data bytes 64 bytes from 1.1.1.1: seq=0 ttl=64 time=0.093 ms 64 bytes from 1.1.1.1: seq=1 ttl=64 time=0.488 ms 64 bytes from 1.1.1.1: seq=2 ttl=64 time=0.220 ms ^C --- 1.1.1.1 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.093/0.267/0.488 ms / # ping -I 9.9.9.9 2.2.2.2 PING 2.2.2.2 (2.2.2.2) from 9.9.9.9: 56 data bytes 64 bytes from 2.2.2.2: seq=0 ttl=64 time=0.140 ms 64 bytes from 2.2.2.2: seq=1 ttl=64 time=0.340 ms 64 bytes from 2.2.2.2: seq=2 ttl=64 time=0.486 ms ^C --- 2.2.2.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.140/0.322/0.486 ms通りました。
ちなみに、この時点でPE1(1.1.1.1)→PE2(2.2.2.2)にpingを打つと、当然ですが普通のIPパケットとして転送されます。PルータでtcpdumpしながらPE1→PE2にpingしてみます。
PE1# ping -I 1.1.1.1 2.2.2.2 PING 2.2.2.2 (2.2.2.2) from 1.1.1.1: 56 data bytes 64 bytes from 2.2.2.2: seq=0 ttl=63 time=0.146 ms 64 bytes from 2.2.2.2: seq=1 ttl=63 time=0.374 ms 64 bytes from 2.2.2.2: seq=2 ttl=63 time=0.373 ms ^C --- 2.2.2.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.146/0.297/0.374 msPR/ # tcpdump -n -i any icmp tcpdump: data link type LINUX_SLL2 tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes 06:51:43.879037 eth0 In IP 1.1.1.1 > 2.2.2.2: ICMP echo request, id 44032, seq 0, length 64 06:51:43.879052 eth1 Out IP 1.1.1.1 > 2.2.2.2: ICMP echo request, id 44032, seq 0, length 64 06:51:43.879080 eth1 In IP 2.2.2.2 > 1.1.1.1: ICMP echo reply, id 44032, seq 0, length 64 06:51:43.879084 eth0 Out IP 2.2.2.2 > 1.1.1.1: ICMP echo reply, id 44032, seq 0, length 645. LDPの設定
MPLSの設定に入っていきます。公式docsに記載の通り、事前準備としてカーネルパラメータを変更してMPLS転送を有効にする必要があります。各ルータでカーネルパラメータ設定→LDP設定の順で進めます。
Pルータ
MPLSの有効化
カーネルパラメータを変更してMPLSを有効にします。
まずは状態確認。PR/ # sysctl -a | grep mpls sysctl: error reading key 'net.ipv6.conf.all.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.default.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.eth0.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.eth1.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.lo.stable_secret': I/O error net.mpls.conf.eth0.input = 0 net.mpls.conf.eth1.input = 0 net.mpls.conf.lo.input = 0 net.mpls.default_ttl = 255 net.mpls.ip_ttl_propagate = 1 net.mpls.platform_labels = 0ipv6関連のエラーが出ていますが、一旦気にしないで進めます。
Pルータではeth0, eth1の両方でMPLS転送を有効にします。
net.mpls.conf.eth0.input
とnet.mpls.conf.eth1.input
を1に、net.mpls.platform_labels
を100000に設定するため、下記のファイルに追記。/etc/sysctl.conf# content of this file will override /etc/sysctl.d/* net.mpls.conf.eth0.input = 1 net.mpls.conf.eth1.input = 1 net.mpls.platform_labels = 100000設定を反映します。
/ # sysctl -p net.mpls.conf.eth0.input = 1 net.mpls.conf.eth1.input = 1 net.mpls.platform_labels = 100000# sysctl -a | grep mpls sysctl: error reading key 'net.ipv6.conf.all.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.default.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.eth0.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.eth1.stable_secret': I/O error sysctl: error reading key 'net.ipv6.conf.lo.stable_secret': I/O error net.mpls.conf.eth0.input = 1 net.mpls.conf.eth1.input = 1 net.mpls.conf.lo.input = 0 net.mpls.default_ttl = 255 net.mpls.ip_ttl_propagate = 1 net.mpls.platform_labels = 100000値が反映されました。
LDPの設定
MPLSのラベル交換のため、LDPを動かします。
PR(vtysh)PR# conf PR(config)# mpls ldp PR(config-ldp)# address-family ipv4 PR(config-ldp-af)# discovery transport-address 9.9.9.9 PR(config-ldp-af)# interface eth0 PR(config-ldp-af-if)# exit PR(config-ldp-af)# interface eth1 PR(config-ldp-af-if)# exit PR(config-ldp-af)# endMPLS網に参加するインターフェースだけ登録します。(ループバックは不要)
PEルータ
PE1, PE2も同様にカーネルパラメータの設定とLDPの設定をします。
PE1
/etc/sysctl.conf# content of this file will override /etc/sysctl.d/* net.mpls.conf.eth0.input = 1 net.mpls.platform_labels = 100000vtyshPE1# conf PE1(config)# mpls ldp PE1(config-ldp)# address-family ipv4 PE1(config-ldp-af)# discovery transport-address 1.1.1.1 PE1(config-ldp-af)# interface eth0 PE1(config-ldp-af-if)# exit PE1(config-ldp-af)# endPE2
/etc/sysctl.conf# content of this file will override /etc/sysctl.d/* net.mpls.conf.eth0.input = 1 net.mpls.platform_labels = 100000vtyshPE2# conf PE2(config)# mpls ldp PE2(config-ldp)# address-family ipv4 PE2(config-ldp-af)# discovery transport-address 2.2.2.2 PE2(config-ldp-af)# interface eth0 PE2(config-ldp-af-if)# exit PE2(config-ldp-af)# end動作確認
Pルータで確認します。
PR(vtysh)PR# show mpls ldp neighbor AF ID State Remote Address Uptime ipv4 1.1.1.1 OPERATIONAL 1.1.1.1 00:04:41 ipv4 2.2.2.2 OPERATIONAL 2.2.2.2 00:00:50LDPのneighborが確立できています。
PR(vtysh)PR# show mpls ldp binding AF Destination Nexthop Local Label Remote Label In Use ipv4 1.1.1.1/32 1.1.1.1 16 imp-null yes ipv4 1.1.1.1/32 2.2.2.2 16 16 no ipv4 2.2.2.2/32 1.1.1.1 17 16 no ipv4 2.2.2.2/32 2.2.2.2 17 imp-null yes ipv4 9.9.9.9/32 1.1.1.1 imp-null 17 no ipv4 9.9.9.9/32 2.2.2.2 imp-null 17 no ipv4 10.1.1.0/24 1.1.1.1 imp-null imp-null no ipv4 10.1.1.0/24 2.2.2.2 imp-null 18 no ipv4 10.1.2.0/24 1.1.1.1 imp-null 18 no ipv4 10.1.2.0/24 2.2.2.2 imp-null imp-null no ipv4 172.16.1.0/24 1.1.1.1 - imp-null no ipv4 172.16.2.0/24 2.2.2.2 - imp-null no ipv4 172.16.3.0/24 1.1.1.1 - imp-null no ipv4 172.16.4.0/24 2.2.2.2 - imp-null no「LIBテーブル」の情報が確認できます。
PR(vtysh)PR# show mpls table Inbound Label Type Nexthop Outbound Label ----------------------------------------------- 16 LDP 10.1.2.2 implicit-null 17 LDP 10.1.1.2 implicit-nullこちらは「LFIBテーブル」ですね。
先ほどと同様、PE1(1.1.1.1)→PE2(2.2.2.2)にpingを打ってみます。
PE1/ # ping -c 1 -I 1.1.1.1 2.2.2.2 PING 2.2.2.2 (2.2.2.2) from 1.1.1.1: 56 data bytes 64 bytes from 2.2.2.2: seq=0 ttl=63 time=0.121 ms --- 2.2.2.2 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.121/0.121/0.121 msこの時、Pルータでパケットキャプチャをすると、生のIPパケットではなく、MPLSラベルのついたパケットが転送されていることがわかります。
PR/ # tcpdump -n -i any -l | grep ICMP tcpdump: data link type LINUX_SLL2 tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes 07:17:28.103630 eth0 In MPLS (label 17, exp 0, [S], ttl 64) IP 1.1.1.1 > 2.2.2.2: ICMP echo request, id 51200, seq 0, length 64 07:17:28.103636 eth1 Out IP 1.1.1.1 > 2.2.2.2: ICMP echo request, id 51200, seq 0, length 64 07:17:28.103668 eth1 In MPLS (label 16, exp 0, [S], ttl 64) IP 2.2.2.2 > 1.1.1.1: ICMP echo reply, id 51200, seq 0, length 64 07:17:28.103669 eth0 Out IP 2.2.2.2 > 1.1.1.1: ICMP echo reply, id 51200, seq 0, length 64行きはlabel 17が付けられたパケットがPルータのeth0から入り、PルータのLFIBテーブル(Label 17に対してimplicit-null)に従ってラベルが剥がされ、生のIPパケットになってeth1から出ていく様子がわかります。帰りはlabel 16で同様の処理が行われています。
6. MP-BGPの設定
PEルータでMP-BGPの設定をします。
まずPE間でiBGPピアを張る設定と、VPN-IPv4のアドレス情報を運ぶためのAddress Familyの設定です。
PE1(vtysh)PE1# conf PE1(config)# router bgp 65000 PE1(config-router)# neighbor 2.2.2.2 remote-as 65000 PE1(config-router)# neighbor 2.2.2.2 update-source 1.1.1.1 PE1(config-router)# address-family ipv4 vpn PE1(config-router-af)# neighbor 2.2.2.2 activate PE1(config-router-af)# exit-address-family PE1(config-router)# endPE2も同様に設定します。
PE2(vtysh)PE2# conf PE2(config)# router bgp 65000 PE2(config-router)# neighbor 1.1.1.1 remote-as 65000 PE2(config-router)# neighbor 1.1.1.1 update-source 2.2.2.2 PE2(config-router)# address-family ipv4 vpn PE2(config-router-af)# neighbor 1.1.1.1 activate PE2(config-router-af)# exit-address-family PE2(config-router)# end動作確認
PE1(vtysh)PE1# show ip bgp summary IPv4 Unicast Summary: BGP router identifier 1.1.1.1, local AS number 65000 vrf-id 0 BGP table version 0 RIB entries 0, using 0 bytes of memory Peers 1, using 14 KiB of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt 2.2.2.2 4 65000 13 16 0 0 0 00:01:16 0 0 Total number of neighbors 1 IPv4 VPN Summary: BGP router identifier 1.1.1.1, local AS number 65000 vrf-id 0 BGP table version 0 RIB entries 0, using 0 bytes of memory Peers 1, using 14 KiB of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt 2.2.2.2 4 65000 13 16 0 0 0 00:01:16 0 0 Total number of neighbors 1Up/Downの欄がneverになっていないことを確認します。
VPN-IPv4のBGPテーブルも見てみます。
PE1(vtysh)PE1# show bgp ipv4 vpn No BGP prefixes displayed, 0 existこの時点ではまだルートを学習していないので、エントリーはありません。
7. VRFの設定
PE1/PE2で各ユーザごとのVRFを作り、ユーザルートの設定とルート再配送の設定をします。
VRFの作成
各CEルータを収容するためのVRFを作成します。Linux VRFの機能を使っていきます。VRF作成はFRRoutingでできないので、ipコマンドを使って作ります。また、作ったVRFに、対応するIFを所属させます。A社用のVRF名はCUSTA、B社用はCUSTBとします。
PE1/ # ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 41: eth2@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:ac:10:03:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 43: eth0@if44: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:0a:01:01:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 45: eth1@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:ac:10:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 / # ip link add CUSTA type vrf table 10 / # ip link add CUSTB type vrf table 20 / # ip link set CUSTA up / # ip link set CUSTB up / # ip link set eth1 master CUSTA / # ip link set eth2 master CUSTB / # ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: CUSTA: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 12:1b:1d:12:01:7f brd ff:ff:ff:ff:ff:ff 3: CUSTB: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether de:06:68:aa:a5:ec brd ff:ff:ff:ff:ff:ff 41: eth2@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master CUSTB state UP mode DEFAULT group default link/ether 02:42:ac:10:03:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 43: eth0@if44: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:0a:01:01:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 45: eth1@if46: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master CUSTA state UP mode DEFAULT group default link/ether 02:42:ac:10:01:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0vtyshで確認できます。
PE1(vtysh)PE1# show int br Interface Status VRF Addresses --------- ------ --- --------- CUSTA up CUSTA eth1 up CUSTA 172.16.1.254/24 Interface Status VRF Addresses --------- ------ --- --------- CUSTB up CUSTB eth2 up CUSTB 172.16.3.254/24 Interface Status VRF Addresses --------- ------ --- --------- eth0 up default 10.1.1.2/24 lo up default 1.1.1.1/32PE2でも同様に作成します。
PE2/ # ip link add CUSTA type vrf table 10 / # ip link add CUSTB type vrf table 20 / # ip link set CUSTA up / # ip link set CUSTB up / # ip link set eth1 master CUSTA / # ip link set eth2 master CUSTB / # ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: CUSTA: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether b6:48:e9:21:1e:6b brd ff:ff:ff:ff:ff:ff 3: CUSTB: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 16:8f:42:1f:9b:84 brd ff:ff:ff:ff:ff:ff 47: eth0@if48: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:0a:01:02:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 49: eth1@if50: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master CUSTA state UP mode DEFAULT group default link/ether 02:42:ac:10:02:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 51: eth2@if52: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master CUSTB state UP mode DEFAULT group default link/ether 02:42:ac:10:04:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0PE2(vtysh)PE2# show int br Interface Status VRF Addresses --------- ------ --- --------- CUSTA up CUSTA eth1 up CUSTA 172.16.2.254/24 Interface Status VRF Addresses --------- ------ --- --------- CUSTB up CUSTB eth2 up CUSTB 172.16.4.254/24 Interface Status VRF Addresses --------- ------ --- --------- eth0 up default 10.1.2.2/24 lo up default 2.2.2.2/32ユーザ向けルートの設定
今回CE-PE間はスタティックルーティングを使います。VRF CUSTA, CUSTBそれぞれで設定。
PE1(vtysh)PE1# conf PE1(config)# ip route 192.168.1.0/24 172.16.1.2 vrf CUSTA PE1(config)# ip route 192.168.3.0/24 172.16.3.2 vrf CUSTB PE1(config)# exit PE1# show ip route vrf CUSTA Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTA: C>* 172.16.1.0/24 is directly connected, eth1, 04:55:40 S>* 192.168.1.0/24 [1/0] via 172.16.1.2, eth1, weight 1, 04:12:14 PE1# show ip route vrf CUSTB Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTB: C>* 172.16.3.0/24 is directly connected, eth2, 04:55:37 S>* 192.168.3.0/24 [1/0] via 172.16.3.2, eth2, weight 1, 04:09:52PE2も同様に設定。
PE2(vtysh)PE2# conf PE2(config)# ip route 192.168.2.0/24 172.16.2.2 vrf CUSTA PE2(config)# ip route 192.168.4.0/24 172.16.4.2 vrf CUSTB PE2(config)# exit PE2# show ip route vrf CUSTA Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTA: C>* 172.16.2.0/24 is directly connected, eth1, 05:00:25 S>* 192.168.2.0/24 [1/0] via 172.16.2.2, eth1, weight 1, 04:17:02 PE2# show ip route vrf CUSTB Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTB: C>* 172.16.4.0/24 is directly connected, eth2, 05:00:26 S>* 192.168.4.0/24 [1/0] via 172.16.4.2, eth2, weight 1, 04:16:34ルート再配送の設定
VRFのルートテーブルと「グローバルルーティングテーブル」の間の、ルート再配送の設定。
PE1(vtysh)PE1# conf PE1(config)# router bgp 65000 vrf CUSTA PE1(config-router)# address-family ipv4 unicast PE1(config-router-af)# redistribute static PE1(config-router-af)# label vpn export auto PE1(config-router-af)# rd vpn export 1:100 PE1(config-router-af)# rt vpn both 10:100 PE1(config-router-af)# export vpn PE1(config-router-af)# import vpn PE1(config-router-af)# exit-address-family PE1(config-router)# exit PE1(config)# router bgp 65000 vrf CUSTB PE1(config-router)# address-family ipv4 unicast PE1(config-router-af)# redistribute static PE1(config-router-af)# label vpn export auto PE1(config-router-af)# rd vpn export 2:100 PE1(config-router-af)# rt vpn both 20:100 PE1(config-router-af)# export vpn PE1(config-router-af)# import vpn PE1(config-router-af)# exit-address-family PE1(config-router)# endこの辺り、Ciscoと設定方法が若干違うようですが、やっていることとしては以下のように理解しています。
label vpn export auto
:VRFからグローバルルーティングテーブルに対してルートをexportする時に、MPLSのラベルを自動でつける
export|import vpn
:VRFとグローバルルーティングテーブル間でルートのimport/exportを可能にするVRF内のルート情報(address-family = ipv4 unicast)をグローバルルーティングテーブル側(address-family = VPNv4: RD/RT等の情報が付与されたアドレス情報)に配送する際の設定として、「MPLSのラベル付け」「RD/RT情報の付与」「そもそもVRF内のルート⇔グローバルルーティングテーブルの情報のやりとりをONにする」という設定を行っている。
また、今回CE-PE間はStaticルーティングでの設定としているため、
redistribute static
としています。PE2も同様に設定。
PE2(vtysh)PE2# conf PE2(config)# router bgp 65000 vrf CUSTA PE2(config-router)# address-family ipv4 unicast PE2(config-router-af)# redistribute static PE2(config-router-af)# label vpn export auto PE2(config-router-af)# rd vpn export 1:100 PE2(config-router-af)# rt vpn both 10:100 PE2(config-router-af)# export vpn PE2(config-router-af)# import vpn PE2(config-router-af)# exit-address-family PE2(config-router)# exit PE2(config)# router bgp 65000 vrf CUSTB PE2(config-router)# address-family ipv4 unicast PE2(config-router-af)# redistribute static PE2(config-router-af)# label vpn export auto PE2(config-router-af)# rd vpn export 2:100 PE2(config-router-af)# rt vpn both 20:100 PE2(config-router-af)# export vpn PE2(config-router-af)# import vpn PE2(config-router-af)# exit-address-family PE2(config-router)# endこれを設定すると、BGPでユーザルートが学習されます。
動作確認
PE1で確認。まずはBGPテーブル(VPN-IPv4ルート)を見てみます。
PE1PE1# show ip bgp ipv4 vpn BGP table version is 6, local router ID is 1.1.1.1, vrf id 0 Default local pref 100, local AS 65000 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path Route Distinguisher: 1:100 *> 192.168.1.0/24 172.16.1.2@2< 0 32768 ? UN=172.16.1.2 EC{10:100} label=146 type=bgp, subtype=5 *>i192.168.2.0/24 2.2.2.2 0 100 0 ? UN=2.2.2.2 EC{10:100} label=146 type=bgp, subtype=0 Route Distinguisher: 2:100 *> 192.168.3.0/24 172.16.3.2@3< 0 32768 ? UN=172.16.3.2 EC{20:100} label=147 type=bgp, subtype=5 *>i192.168.4.0/24 2.2.2.2 0 100 0 ? UN=2.2.2.2 EC{20:100} label=147 type=bgp, subtype=0 Displayed 4 routes and 4 total pathsユーザルートが載りました。PE2で設定した192.168.2.0/24と192.168.4.0/24もiBGPで学習されています。先ほど設定したRD/RT情報も載っています。
次に、VRFごとのBGPテーブル。
PE1# show ip bgp vrf CUSTA BGP table version is 2, local router ID is 172.16.1.254, vrf id 2 Default local pref 100, local AS 65000 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 192.168.1.0/24 172.16.1.2 0 32768 ? *> 192.168.2.0/24 2.2.2.2@0< 0 100 0 ? Displayed 2 routes and 2 total pathsPE1# show ip bgp vrf CUSTB BGP table version is 4, local router ID is 172.16.3.254, vrf id 3 Default local pref 100, local AS 65000 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 192.168.3.0/24 172.16.3.2 0 32768 ? *> 192.168.4.0/24 2.2.2.2@0< 0 100 0 ? Displayed 2 routes and 2 total pathsそれぞれユーザルートが正しく学習されています。
次に、VRFごとのルートテーブルを見てみます。PE1# show ip route vrf CUSTA Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTA: C>* 172.16.1.0/24 is directly connected, eth1, 05:29:08 S>* 192.168.1.0/24 [1/0] via 172.16.1.2, eth1, weight 1, 04:45:42 B> 192.168.2.0/24 [200/0] via 2.2.2.2 (vrf default) (recursive), label 146, weight 1, 00:04:28 * via 10.1.1.254, eth0 (vrf default), label 17/146, weight 1, 00:04:28PE1# show ip route vrf CUSTB Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, f - OpenFabric, > - selected route, * - FIB route, q - queued, r - rejected, b - backup VRF CUSTB: C>* 172.16.3.0/24 is directly connected, eth2, 05:29:07 S>* 192.168.3.0/24 [1/0] via 172.16.3.2, eth2, weight 1, 04:43:22 B> 192.168.4.0/24 [200/0] via 2.2.2.2 (vrf default) (recursive), label 147, weight 1, 00:16:20 * via 10.1.1.254, eth0 (vrf default), label 17/147, weight 1, 00:16:20それぞれ、BGPテーブルを介して、PE2から受信したユーザルートが載っていることがわかります。
8. CEルータの設定
最後に、CEの設定をしていきます。
ループバックアドレス、PE向かいのアドレス、デフォルトルートを設定します。CE1(vtysh)CE1# conf CE1(config)# interface lo CE1(config-if)# ip address 192.168.1.1/24 CE1(config-if)# exit CE1(config)# interface eth0 CE1(config-if)# ip address 172.16.1.2/24 CE1(config-if)# exit CE1(config)# ip route 0.0.0.0/0 172.16.1.254 CE1(config)# endCE2~4も同様。
CE2(vtysh)CE2# conf CE2(config)# interface lo CE2(config-if)# ip address 192.168.2.1/24 CE2(config-if)# exit CE2(config)# interface eth0 CE2(config-if)# ip address 172.16.2.2/24 CE2(config-if)# exit CE2(config)# ip route 0.0.0.0/0 172.16.2.254 CE2(config)# endCE3(vtysh)CE3# conf CE3(config)# interface lo CE3(config-if)# ip address 192.168.3.1/24 CE3(config-if)# exit CE3(config)# interface eth0 CE3(config-if)# ip address 172.16.3.2/24 CE3(config-if)# exit CE3(config)# ip route 0.0.0.0/0 172.16.3.254 CE3(config)# endCE4(vtysh)CE4# conf CE4(config)# interface lo CE4(config-if)# ip address 192.168.4.1/24 CE4(config-if)# exit CE4(config)# interface eth0 CE4(config-if)# ip address 172.16.4.2/24 CE4(config-if)# exit CE4(config)# ip route 0.0.0.0/0 172.16.4.254 CE4(config)# end動作確認
これですべて完成したはずです。
CE1→CE2にpingが通ることを確認します。-I
でSourceとしてループバックIFを指定。CE1/ # ping -I 192.168.1.1 192.168.2.1 PING 192.168.2.1 (192.168.2.1) from 192.168.1.1: 56 data bytes 64 bytes from 192.168.2.1: seq=0 ttl=62 time=0.650 ms 64 bytes from 192.168.2.1: seq=1 ttl=62 time=0.751 ms 64 bytes from 192.168.2.1: seq=2 ttl=62 time=0.675 ms ^C --- 192.168.2.1 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.650/0.692/0.751 ms通りました!
CE3→CE4にpingが通ることを確認します。
CE3/ # ping -I 192.168.3.1 192.168.4.1 PING 192.168.4.1 (192.168.4.1) from 192.168.3.1: 56 data bytes 64 bytes from 192.168.4.1: seq=0 ttl=62 time=0.470 ms 64 bytes from 192.168.4.1: seq=1 ttl=62 time=0.157 ms 64 bytes from 192.168.4.1: seq=2 ttl=62 time=0.777 ms ^C --- 192.168.4.1 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.157/0.468/0.777 ms通りました!
試しに、CE1→CE4には通らないことを確認します。
CE1/ # ping -I 192.168.1.1 192.168.4.1 PING 192.168.4.1 (192.168.4.1) from 192.168.1.1: 56 data bytes ^C --- 192.168.4.1 ping statistics --- 3 packets transmitted, 0 packets received, 100% packet loss通らないので成功です!
パケットキャプチャしてみる
上記CE1→CE2のpingの際、PE1のeth1,0, Pルータのeth0,1, PE2のeth0,1でパケットキャプチャすると、ラベルがついたり取られたりしながらパケットが転送される様子が見えます。
PE1/PR/PE2/ # tcpdump -n -i any -l | grep ICMPCE1/ # ping -c 1 -I 192.168.1.1 192.168.2.1 PING 192.168.2.1 (192.168.2.1) from 192.168.1.1: 56 data bytes 64 bytes from 192.168.2.1: seq=0 ttl=62 time=0.551 ms --- 192.168.2.1 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.551/0.551/0.551 ms結果を時系列で並べると以下のようになりました。
行き:
PE108:13:50.550878 eth1 In IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64 08:13:50.550900 eth0 Out MPLS (label 17, exp 0, ttl 63) (label 146, exp 0, [S], ttl 63) IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64PR08:13:50.550905 eth0 In MPLS (label 17, exp 0, ttl 63) (label 146, exp 0, [S], ttl 63) IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64 08:13:50.550909 eth1 Out MPLS (label 146, exp 0, [S], ttl 63) IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64PE208:13:50.550913 eth0 In MPLS (label 146, exp 0, [S], ttl 63) IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64 08:13:50.550916 CUSTA Out IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64 08:13:50.550926 eth1 Out IP 192.168.1.1 > 192.168.2.1: ICMP echo request, id 20992, seq 0, length 64PE1のeth0に届くのは生のIPパケットですが、そこで内側のラベル146(VPN識別用)と外側のラベル17(MPLS網内転送用)がつけられeth1から出ていきます。PRではLFIBテーブル(Label 17に対してはimplicit null)にしたがって外側のラベルが剥がされた状態でPE2に転送されています。PE2では内側のラベルも剥がされ、VRF CUSTAのルーティングテーブルに従って生のIPパケットとしてCE2に転送されています。 最後Outが2つあるのはVRF CUSTAとeth1の分ですね。3
帰り:
帰りも同様です。内側のVPN識別用ラベルとしては146が割り当てられています。PE208:13:50.550976 eth1 In IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64 08:13:50.550981 eth0 Out MPLS (label 16, exp 0, ttl 63) (label 146, exp 0, [S], ttl 63) IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64PR08:13:50.550984 eth1 In MPLS (label 16, exp 0, ttl 63) (label 146, exp 0, [S], ttl 63) IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64 08:13:50.550986 eth0 Out MPLS (label 146, exp 0, [S], ttl 63) IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64PE108:13:50.550988 eth0 In MPLS (label 146, exp 0, [S], ttl 63) IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64 08:13:50.550990 CUSTA Out IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64 08:13:50.550994 eth1 Out IP 192.168.2.1 > 192.168.1.1: ICMP echo reply, id 20992, seq 0, length 64参考
- MPLSをはじめから
- MPLS-VPN 検証構成とコンフィグ設定(PE-CE間でスタティックルートを使用)
- FRRoutingでMPLS L3-VPNのようなもの
- Use Linux as an MPLS Router
- Linux VRF with L3 Master Device
tcpdumpのIF指定を
-i any
にすると、VRF CUSTAへのINが表示されないようです。個別にIF指定するとどちらも表示されるのですが... なぜだろう... ↩
- 投稿日:2021-01-11T22:06:32+09:00
Ruby on Rails 初心者向け!!投稿一覧・詳細表示機能まとめ
はじめに
今は業務で主にphpを使っているのですが、今回自主学習でRailsを使用して何か成果物を作成したいと思い学習をはじめました。何かアドバイスや修正箇所があればコメントよろしくお願いします。
開発環境
- Docker
- ruby 2.3.7
- Rails 5.2.4.4
- MySQL 5.7.32
前提
Railsの開発環境の構築を行い、新規投稿機能の実装まで完了が終わっていることが前提です。
新規投稿機能は前回の記事を参考に実装してみてください。
・Ruby on Rails 初心者向け!!新規投稿機能まとめ投稿一覧表示機能実装
コントローラーにアクションを追加
まずは投稿一覧機能を実装していきます。一覧表示機能は基本的にはindexアクションを使います。
前回作成した、postコントローラーにindexアクションを追加していきます。post.controller.rbdef index endルーティング設定
次にルーティング設定です。
config/routes.rbに下記の記述を追加します。
routes.rbRails.application.routes.draw do get 'posts/new' => 'posts#new' # ここから get 'posts' => 'posts#index' # ここまで追加 post 'posts' => 'posts#create' endこれで「GETメソッドでpostsパスにアクセスするとpostsコントローラーのindexアクションにアクセスする」という設定ができます。
ターミナルからも設定を確かめてみましょう。
以下のコマンドでルーティングの設定を確認できます。# rails routes posts GET /posts(.:format) posts#indexこれでルーティング設定は完了です。
コントローラー設定
次はindexアクションの中身は書いていきます。
posts_controller.rbdef index @posts = Post.all end投稿一覧情報を取得するには、postモデルに対してallメソッドを使います。これでインスタンス変数@postsの中には、投稿されたデータ一覧が配列で格納されます。代入する変数名は複数形にしておきます。
ビュー設定
次はビューで先ほど取得した投稿データの表示を行います。
まずは、index.html.erbファイルを新規作成し、中身は書いていきます。index.html.erb<h1>投稿一覧</h1> <% @posts.each do |post| %> <p>タイトル</p> <span><%= post.title %></span> <% end %><% @posts.each do |post| %>は、繰り返し処理で、先ほどコントローラーで定義した投稿一覧が格納されたインスタンス変数@postsを一つずつ取り出して、ブロック変数のpostに格納しているという意味です。
これにより、each文の中で投稿の一つ一つが格納されたブロック変数postが使用できるようになります。<%= post.title %>の記述は、ブロック変数postのタイトルカラムを一つずつ表示しています。「変数名.カラム名」で表示するカラムが指定できます。
これで「/posts」のURLにアクセスすると投稿のタイトル一覧が表示されていると思います。
リンクの作成
次に新規投稿画面から、投稿一覧画面に遷移するリンクを設定していきます。
リンクの実装には、link_toメソッドを使用します。
新規投稿画面のビューに以下を記述していきます。# ここから <span> <%= link_to "投稿一覧", "/posts" %> </span> # ここまで追加 <h1>投稿フォーム</h1> <%= form_for(@post, url: '/posts') do |f| %> <h3>タイトル</h3> <%= f.text_field :title %> <h3>本文</h3> <%= f.text_area :body %> <%= f.submit '投稿' %> <% end %>linl_toメソッドは、
<%= link_to 表示させるテキスト , "リンク先URL" [,オプション] %>のように使う記述します。
これで投稿一覧ページへの遷移するテキストが投稿フォームの上に表示されていると思います。
これで投稿一覧表示機能の実装ができました。
投稿詳細表示機能実装
コントローラーにアクションを追加
次に投稿詳細機能の実装をしていきます。詳細表示機能にはshowアクションを使用します。
実装の流れは一覧表示機能と同じです。
ではpostsコントローラーにshowアクションを定義していきます。posts_controller.rbdef show endルーティング設定
次にルーティング設定です。
routes.rbRails.application.routes.draw do get 'posts/new' => 'posts#new' get 'posts' => 'posts#index' # ここから get 'posts/:id' => 'postss#show' # ここまで追加 post 'posts' => 'posts#create' end詳細表示のURLはどの詳細データか識別するために末尾にidがつきます。
IDが1の投稿の場合は、「posts/1」のようなURLになります。
コロン(:)idで設定することができます。コントローラー設定
showアクションの中身を記述していきます。
posts_controller.rbdef show @post = Post.find(params[:id]) endアクション内にparams[:id]と記述することで、先ほどルーティングで設定したURLの末尾のIDを取得することができます。findメソッドをしようすることで、idが1の場合、「IDが1のレコードを一件取得する」という意味になります。
ビュー設定
次に詳細表示画面のビューを作成します。
show.html.erbを作成し、中身を編集します。show.html.erb<h2>タイトル</h2> <p><%= @post.title %></p> <h2>本文</h2> <p><%= @post.body %></p>showアクションの中に定義したインスタンス変数.カラム名でそのカラムのデータを表示することができます。今回はtitleとbodyを表示します。
これでURLが「posts/1」にアクセスすると以下のようにid=1のデータが表示されます。
リンクの作成
最後に投稿一覧画面から、詳細画面へのリンクを設定していきます。
投稿一覧画面のviewを以下のうように書き換えます。index.html.erb<h1>投稿一覧</h1> <% @posts.each do |post| %> <p>タイトル</p> <span><%= link_to post.title, "/post/#{post.id}" %></span> <% end %>これで一つ一つの投稿のタイトルをクリックするとその投稿の詳細ページへ遷移することができるようになりました。
まとめ
- 投稿一覧表示機能はindexアクション、詳細表示機能はshowアクションを使用する。
- DBからデータ一覧を取得するにはモデルに対してallメソッドを使用する。特定のデータを取得するにはfindメソッドでidを指定して取得する。
- 画面遷移のリンクを作成するには、link_toメソッドを使用する。
- 投稿日:2021-01-11T21:44:23+09:00
備忘録:【Docker】起動&終了方法
備忘録φ(..)メモメモ
【起動方法】
アプリ起動
Dockerの置いてる場所で下記を入力
※私の場合”dev”というディレクトリ内に入って入力
terminallancai@oja dev % docker-compose up -d↓下記のように返ってきたらOK
terminalCreating network "proxy-net" with driver "bridge" Creating rootp-db ... done↓RUNNINGとなっていたらOK
終了方法
Dockerの置いてる場所で下記を入力
※私の場合”dev”というディレクトリ内に入って入力
terminal$ lancai@oja dev % docker-compose down↓下記のように返ってきたらOK
terminalStopping ※DBの名前 ... done Removing ※DBの名前 ... done Removing network proxy-net
- 投稿日:2021-01-11T21:41:23+09:00
Dockerでphpの設定
Dockerfile
Dockerfile.FROM php:x.x-fpm COPY ./php.ini /usr/local/etc/php/php.ini COPY ./php-fpm.d/www.conf /usr/local/etc/php-fpm.d/zzz-www.confまず
php.ini
とzzz-www.conf
をコピーする。php.iniの内容
の中でも意味のわかるものを載せます。(文字コードを省く)
php.ini;エラー時にブラウザにエラー内容を表示(開発環境でならon) desplay_errors = On ;エラーログを吐く設定を有効に log_errors = On ;phpのエラーログを /var/log/php_error.log に吐く設定 error_log = /var/log/php_error.log ;値は自由に ;メモリーの上限を256MBに memory_limit = 256M ;POSTリクエストの受付る最大値 post_max_size = 128M ;アップロードファイルの受付上限 upload_max_filesize = 64M ;レスポンスヘッダにPHPのバージョンを記載しない expose_php = Off ;セッションIDのハッシュアルゴリズムをSHA-1(160bit)に変更 session.hash_function = 1 ;強制終了までの許容時間 max_execution_time = 30 ;入力変数の最大許容数 max_input_vars = 1000 ; PHPファイルのタグを<?php ?>のみ利用可能と制限(<? ?>などを使用不可にする) short_open_tag = Off ;Time zone date.timezone = 設定したいTZ私はこの記事を参考にしました。参考記事
大体2,3個の記事を参考にしたら自力で書けそう。
zzz-www.conf
の内容ファイル名がこれなのは公式イメージの
zz-docker.conf
でlistenを上書きしてしまわないようにzz-docker.confの後に読ませたいので、後に読ませられればなんでもいい。zzz-www.conflisten = /var/run/php-fpm/php-fpm.sock listen.group = www-data listen.owner = www-data listen.mode = 06661行目はソケットの位置を指定。(nginxの設定と合わせる)
4行目listen.modeはデフォルトのlisten.mode = 0660
だとパーミッションエラーが起きるようで0666
にした方がいい。
4行目の参考Nginx+PHP-FPMでUNIXドメインソケットを使っていてハマる。
- 投稿日:2021-01-11T21:00:14+09:00
DockerでComposerをインストール
今後Dockerを触るときに役立つようにメモ用として。
DockerfileでRUNを使うかCOPYを使うか
Composerの公式ページからやっても良いけど、composer公式
Dockerfile.FROM php:x.xx-fpm RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \ php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \ php composer-setup.php php -r "unlink('composer-setup.php');"これは2行目のハッシュ値が原因でバージョンアップのたびにDockerfileを変更する...みたいな問題があるよう。
COPYを使う方がいい
Dockerfile.FROM php:x.xx-fpm COPY COPY --from=composer /usr/bin/composer /usr/bin/composerこれを記述するだけですむ。
composerのバージョンを指定したいときは
COPY --from=composer:xx.x /usr/bin/composer /usr/bin/composer
にすればいい。ついでに
ENV COMPOSER_ALLOW_SUPERUSER=1を指定するとrootでのインストールを許可する。
- 投稿日:2021-01-11T20:32:42+09:00
【Rails】DockerからRails newができない
【Rails】Rails 6.0 x Docker x MySQLで環境構築
こちらの記事を参考に、
Rails6でDocker環境を構築中、
下記のエラーが出ました。ターミナルBind for 0.0.0.0:3306 failed: port is already allocated直訳するとすでに3306のポートは割り当てられてますよとのこと。
ターミナル$ docker psターミナルCONTAINER ID IMAGE COMMAND CREATED fbfa25282c46 mysql:5.7 "docker-entrypoint.s…" 7 hours ago STATUS PORTS Up 7 hours 0.0.0.0:3306->3306/tcp, 33060/tcpターミナル$ docker stop fbfa25282c463306を発見!!
でコンテナをストップさせ、
無事にrails newができました。
- 投稿日:2021-01-11T19:55:11+09:00
Docker で Embulk を動かしてファイル変換
Docker コンテナで Embulk を動かせるようにし、テストとして csv ファイルを orc ファイルに変換してみる
Embulk ?
バッチ的にファイルやデータベースからデータを吸い出し、別のストレージやデータベースにロードできるツール
詳細は公式ドキュメントか、下記開発者の方のブログを参照ください環境情報
- Mac OS X Catalina 10.15.7
- Docker version: 20.10.0
- orc-tools version: ORC 1.6.6
- 最後に orc ファイルの中身を見る時に使用
- Homebrew でインストール可能
Docker コンテナ内で、手動で Embulk をインストール
とりあえずコンテナ立ち上げて、手動で入れてみる
docker run -it --rm java:8 bash公式ドキュメントにあるやり方で embulk をインストール
- 後々イメージ化することを考えると
$HOME
配下にパスを通すのが難しいので、実行ファイルのインストール場所は、/usr/local/bin
にする- なので、公式の手順内の
~/.embulk/bin/embulk
の箇所は、/usr/local/bin/embulk
に書き換える- 手順内の PATH の更新の箇所も行わない
curl --create-dirs -o /usr/local/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar" chmod +x /usr/local/bin/embulk公式ドキュメントにあるクイックスタートに沿って実際に動かしてみる
embulk example ./try1 embulk guess ./try1/seed.yml -o config.yml embulk run config.yml
embulk run
の結果、以下のような結果が標準出力されればOK1,32864,2015-01-27 19:23:49,20150127,embulk 2,14824,2015-01-27 19:01:23,20150127,embulk jruby 3,27559,2015-01-28 02:20:02,20150128,Embulk "csv" parser plugin 4,11270,2015-01-29 11:54:36,20150129,
↑ で何をやったのか
try1/csv/sample_01.csv.gz
の中身を、stdout (標準出力) に出力したconfig.yml の中身
root@7e9764e79b83:/# cat config.yml in: type: file path_prefix: /./try1/csv/sample_ decoders: - {type: gzip} parser: charset: UTF-8 newline: LF type: csv delimiter: ',' quote: '"' escape: '"' null_string: 'NULL' trim_if_not_quoted: false skip_header_lines: 1 allow_extra_columns: false allow_optional_columns: false columns: - {name: id, type: long} - {name: account, type: long} - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'} - {name: purchase, type: timestamp, format: '%Y%m%d'} - {name: comment, type: string} out: {type: stdout}
try1/csv/sample_01.csv.gz
の中身確認root@7e9764e79b83:/# zcat try1/csv/sample_* id,account,time,purchase,comment 1,32864,2015-01-27 19:23:49,20150127,embulk 2,14824,2015-01-27 19:01:23,20150127,embulk jruby 3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin" 4,11270,2015-01-29 11:54:36,20150129,NULLDockerfile作成 & コンテナ起動
動作確認が終わったので、上記手動手順を Dockerfile 化する
- ENTRYPOINT で、
/usr/local/vin/embulk
を指定したかったが、ENTRYPOINT では jar を直接的に起動できないので、java -jar
で起動DockerfileFROM java:8 # Install embulk RUN curl --create-dirs -o /usr/local/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar" &&\ chmod +x /usr/local/bin/embulk ENTRYPOINT ["java", "-jar", "/usr/local/bin/embulk"]build
docker build -t embulk .確認
docker run -it --rm embulk:latest embulk --version Embulk v0.9.23コンテナ内の embulk で csv ファイルを orc 変換
せっかくなので、実際に embulk を使用して csv ファイルを orc ファイルに変換してみる
Dockerファイルを修正
- 先程の Docker ファイルに以下を追加
- embulk-output-orc プラグイン のインストール
- プラグインは、
embulk gem install ${パッケージ名}
のようにしてインストールする- WORKDIR を /work に設定
DockerfileFROM java:8 # Install embulk RUN curl --create-dirs -o /usr/local/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar" &&\ chmod +x /usr/local/bin/embulk RUN embulk gem install embulk-output-orc WORKDIR /work ENTRYPOINT ["java", "-jar", "/usr/local/bin/embulk"]build
docker build -t embulk .作業ディレクトリの構成
. ├── Dockerfile └── work ├── config.yml ├── csv_inputs │ └── sample_01.csv.gz └── orc_outputs
動作イメージ
work/config.yml
に書いてある設定に沿って、./work/csv_inputs/sample_01.csv.gz
を orc 変換して、./work/orc_outputs/
配下に出力
work/config.yml
ファイル中身
- 先程のクイックスタートでできた
config.yml
内のout
をtype: orc
に書き換えている- 今回はデータ量が少なく、空ファイルが出来てしまうのを防ぐため、
exec
の内で、min_output_tasks
を1にしてファイルを分散させないようするconfig.ymlexec: min_output_tasks: 1 in: type: file path_prefix: /work/csv_inputs/sample_ decoders: - {type: gzip} parser: charset: UTF-8 newline: LF type: csv delimiter: ',' quote: '"' escape: '"' null_string: 'NULL' trim_if_not_quoted: false skip_header_lines: 1 allow_extra_columns: false allow_optional_columns: false columns: - {name: id, type: long} - {name: account, type: long} - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'} - {name: purchase, type: timestamp, format: '%Y%m%d'} - {name: comment, type: string} out: type: orc path_prefix: /work/orc_outputs/sample compression_kind: ZLIB overwrite: trueinput となる csv ファイルの中身も、クイックスタートの時と同じ
# Mac では、zcat は gzcat なので注意 gzcat work/csv_inputs/sample_01.csv.gz id,account,time,purchase,comment 1,32864,2015-01-27 19:23:49,20150127,embulk 2,14824,2015-01-27 19:01:23,20150127,embulk jruby 3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin" 4,11270,2015-01-29 11:54:36,20150129,NULL実行
- コンテナ内の
WORKDIR (/work)
を、./work
でマウントしているdocker run -it --rm -v $(pwd)/work:/work embulk:latest run config.yml確認
- orc ファイルができている
ls work/orc_outputs sample.000.orc
orc ファイルの中身確認
- orc-tools で確認可能
orc-tools data work/orc_outputs/sample.000.orc log4j:WARN No appenders could be found for logger (org.apache.hadoop.util.Shell). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.apache.hadoop.security.authentication.util.KerberosUtil (file:/usr/local/Cellar/orc-tools/1.6.6/libexec/orc-tools-1.6.6-uber.jar) to method sun.security.krb5.Config.getInstance() WARNING: Please consider reporting this to the maintainers of org.apache.hadoop.security.authentication.util.KerberosUtil WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Processing data file work/orc_outputs/sample.000.orc [length: 787] {"id":1,"account":32864,"time":"2015-01-27 19:23:49.0","purchase":"2015-01-27 00:00:00.0","comment":"embulk"} {"id":2,"account":14824,"time":"2015-01-27 19:01:23.0","purchase":"2015-01-27 00:00:00.0","comment":"embulk jruby"} {"id":3,"account":27559,"time":"2015-01-28 02:20:02.0","purchase":"2015-01-28 00:00:00.0","comment":"Embulk \"csv\" parser plugin"} {"id":4,"account":11270,"time":"2015-01-29 11:54:36.0","purchase":"2015-01-29 00:00:00.0","comment":null} ________________________________________________________________________________________________________________________変換できている!
参考文献
- 投稿日:2021-01-11T19:44:43+09:00
kubernetes + docker
! /bin/sh
Modify yum.conf
sed -i -e "/timeout=/d" /etc/yum.conf
sed -i -e "13s/^/timeout=300\n/g" /etc/yum.conf
sed -i -e "/ip_resolve=/d" /etc/yum.conf
sed -i -e "14s/^/ip_resolve=4\n/g" /etc/yum.confAdd .curlrc
cat <<-EOF > ~/.curlrc
ipv4
EOFInstall conntrack
yum install -y \
conntrack-tools-1.4.4Install "Docker"
yum install -y \
yum-utils-1.1.31 \
device-mapper-persistent-data-0.8.5 \
lvm2-2.02.185yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repoyum install -y \
docker-ce-19.03.8 \
docker-ce-cli-19.03.8 \
containerd.io-1.2.13mkdir -p /etc/docker
cat <<-EOF > /etc/docker/daemon.json
{
"dns": ["8.8.8.8"]
}
EOFsystemctl enable docker
systemctl start dockerInstall "kubectl"
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.2/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv -f ./kubectl /usr/local/binInstall "minikube"
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v1.9.2/minikube-linux-amd64
chmod +x minikube
install minikube /usr/local/bin
rm -f minikubestop firewall
systemctl disable firewalld
systemctl stop firewalldAdd addons
/usr/local/bin/minikube start --vm-driver=none
/usr/local/bin/minikube addons enable ingressDocker restart and update DNS settings
systemctl restart docker
- 投稿日:2021-01-11T19:36:36+09:00
AWSでGPU必須のバッチ処理を動かす
まとめ
- 使うべきサービスは AWS Batch
- GPUあり/なしで挙動が変わるライブラリに注意
- DockerHubにGPUあり版のイメージがある場合はそれをbaseにすると楽
- 例: PyTorch
背景
- 以下の要件を満たすシステムをAWS上に組みたい
- 毎日/毎週1回のみ動かし、他の時間は課金しないで欲しい
- スポットインスタンスが使えると嬉しい
- GPUは必須
- 例: https://zenn.dev/miyatsuki/articles/0d66daf6615962
- それができそうなサービスがいろいろあるがどれを使えばいいのかよくわからない
- Fargate
- ECS
- SageMaker
- AWS Batch (採用)
なぜAWS Batch?
- Fargate
- GPUが使えないのでNG
- CPUだけなら、Fargateでもいいと思います
- ECS
- GPUインスタンスを立ち上げ続ける必要があるのでNG
- SageMaker
- (サービスがありすぎてよくわからない。。。)
- AWS Batch
- 特定時間のみ起動して終わったらインスタンスを閉じてくれる
- スポットインスタンスも使える
- GPUインスタンスも使える
AWS Batchの使い方
- ECR (Elastic Container Registory) に動かしたいコンテナのイメージをpushする
- AWS Batchのコンピューティング環境を作る
- マネージド型を選択
- インスタンスの設定 -> スポット
- オンデマンド料金 -> 予算をみて適当に設定。50%だとそんなに待たされることはなかったです。
- 許可されたインスタンスタイプ -> GPUが使えるインスタンスを選択。g4dn.xlargeが最安なので、これから様子をみてみるのも良いかもしれません
- EC2設定のイメージタイプ -> Amazon Linux 2 (GPU)
- AWS Batchのジョブキューを作る
- コンピューティング環境は2.で作った物を選ぶ
- AWS Batchのジョブ定義を作る
- プラットフォーム -> EC2
- イメージ -> 1でpushしたもの
- コマンド -> バッチで実行したい物をCMDの引数として使えるように書く。元のイメージのCMDは上書きされるので、イメージ側に記載している場合でも改めて設定が必要
- メモリ -> 2GBで足りない場合は増やす
- GPUの数 -> 1
- AWS Batchのジョブを投げる
- ジョブ画面から新しいジョブを作成をクリック
- ジョブ定義とジョブキューは4と3で作った物を選択
- 最後の送信を押すと、ジョブがsubmitされる
- AWS Batchのジョブ実行を見守る
- ダッシュボード画面からジョブの実行状況が見られるので見守る
コンテナイメージについて
コンテナ側がGPU Readyになっていても、イメージファイル内のソフトウェアがGPU対応してないと、結局CPUで動作してしまう。個人的に注意すべきと思う点は下記。
- pip installした際に、PCの状況をみてGPUなし版を入れてくるライブラリがある
- PyTorchなど
- このようなライブラリのGPU版が必要な場合は、DockerHubからGPU版が入ったイメージをpullしてくると楽
- 投稿日:2021-01-11T18:47:25+09:00
Dockerコンテナ上でAnsibleを実行してみた
はじめに
現場でAnsibleを使う機会ができたので、勉強のためにDockerコンテナ上でAnsibleを動かしてみました。
対象
Ansibleを実際に動かしてみたい人
Ansibleとは?
Ansibleとは、システム構成、ソフトウェアの展開等、様々な設定作業を自動するツールである。
PlaybookというYAML形式のテキストファイルにタスクを記述し、それをAnsibleで実行させることで多様な処理を実現する。
メリットとして、下記2点が挙げられる。
- 設定ファイルがyamlでの記述になっておりシンプル
- 冪等性(何度同じ操作しても、同じ状態にする)を担保
試したこと
- Ansibleコンテナと、環境を適用したいターゲットコンテナを立ち上げる
- Ansibleコンテナからplaybookを実行して、ターゲットコンテナにgitをインストールする
ファイルの構成
. ├── ansible │ └── install_git.yml ├── docker │ ├── ansible │ │ └── Dockerfile │ └── target │ └── Dockerfile └── docker-compose.ymlファイルの説明
docker/ansible/Dockerfile
Ansibleとsshの設定
FROM centos:8 RUN yum update -y \ && yum install -y epel-release \ && yum install -y ansible \ && yum -y install openssh-clients \ && echo "target" >> /etc/ansible/hostsdocker/target/Dockerfile
Ansibleサーバーからsshできるように、sshの設定、sshdを起動
FROM centos:8 RUN yum -y update \ && yum -y install openssh-server \ && sed -ri 's/^#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config \ && sed -ri 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \ && ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa \ && ssh-keygen -f /etc/ssh/ssh_host_ecdsa_key -N '' -t ecdsa \ && sed -ri 's/^#PermitEmptyPasswords no/PermitEmptyPasswords yes/' /etc/ssh/sshd_config \ && echo "root:" | chpasswd # sshdを起動 CMD ["/usr/sbin/sshd", "-D"]docker-compose.yml
Ansibleコンテナと、ターゲットコンテナを起動させる
version: "3" services: ansible: tty: true working_dir: /opt/ansible build: context: . dockerfile: ./docker/ansible/Dockerfile volumes: - ./ansible:/opt/ansible target: tty: true build: context: . dockerfile: ./docker/target/Dockerfileansible/install_git.yml
Playbookファイル、gitをインストールさせている
- hosts: target tasks: - name: install git yum: name=git state=latest実行
- コンテナ起動
- ansibleサーバーにログインして、playbookを実行
- ターゲットコンテナにgitがインストールされているか確認
1. コンテナ起動
# コンテナ起動 ~ % docker-compose up -d Starting ansible_ansible_1 ... done Starting ansible_target_1 ... done2. ansibleサーバーにログインして、playbookを実行
# コンテナを表示 ~ % docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 28f39d3e82f0 ansible_ansible "/bin/bash" About an hour ago Up 13 seconds ansible_ansible_1 362d7471778f ansible_target "/usr/sbin/sshd -D" About an hour ago Up 13 seconds ansible_target_1 # Ansbleコンテナにログイン ~ % docker exec -it ansible_ansible_1 bash # playbook実行 [root@28f39d3e82f0 ansible]# ansible-playbook install_git.yml PLAY [target] ******************************************************************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************************************************** The authenticity of host 'target (172.22.0.2)' can't be established. ECDSA key fingerprint is SHA256:YJSVW2y2ryrRuU0rn3I8onXAPMwS/k03uj+MNd5JqP0. Are you sure you want to continue connecting (yes/no/[fingerprint])? y Please type 'yes', 'no' or the fingerprint: yes ok: [target] TASK [install git] *************************************************************************************************************************************************************************************** changed: [target] PLAY RECAP *********************************************************************************************************************************************************************************************** target : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=03. ターゲットコンテナにgitがインストールされているか確認
# ターゲットコンテナにログイン ~ % docker exec -it ansible_target_1 bash # gitがインストールされているか確認 [root@362d7471778f /]# git --version git version 2.27.0参考
https://tech-mmmm.blogspot.com/2018/08/ansible-ansibleplaybook.html
- 投稿日:2021-01-11T18:43:53+09:00
【Xdebugのバージョン変更に注意!】Xdebug3 + docker + VSCodeで開発環境を作る
はじめに
docker(windows) + VSCodeの開発環境で、Xdebugを使ってPHPのデバッグ環境も作ろうと思ったのですが
xdebugのバージョンが2から3に上がって、php.iniの記述方法がだいぶ変わっていたのでメモとして共有します。環境
Docker Desktop (OS:Windows 10 Home)
気づいたらwindows 10 Homeでも、Docker Desktopが使えるようになってました。
まだ試していない方がいたら、インストールすることをオススメします。
このおかげでMacの場合とほぼ同様に開発環境を作れます。Visual Studio Code
最近流行っているVSCodeです。拡張機能が多くて便利です。
Xdebug 3 (Dockerコンテナ内にインストール)
PHP+Apacheのコンテナを生成して、その中にXdebugをインストールします。
ローカル環境には、上2つ以外にはPHPも何もインストールする必要がないので便利です。特にバージョンを指定せずにXdebugをインストールすると、現在はバージョン3がインストールされます。
これに伴って、php.iniの書き方が変わっています。(詳しくは以降に説明)各種インストール
1. Docker Desktopのインストール
下記ページの手順通りにやれば問題ないと思います。(Windows 10 Home)
2. Visual Studio Codeのインストール
ここからダウンロード、インストールします。
3. VSCodeの拡張機能をインストール
VSCodeの拡張機能として「PHP Debug」をインストールする。
手順:サイドバー「拡張機能」-> 検索欄に「PHP Debug」-> 「PHP Debug」をインストールDockerコンテナにXdebugをインストール
0. ディレクトリ構成
1. DockerFile, docker-compose.ymlの記述
今回はより簡単にするように、PHP+ApecheのコンテナにXdebugをコマンドでインストールするようにDockerfileを作成します。
DockerFileFROM php:7.3-apache RUN apt-get update && apt-get install -y \ git \ unzip \ vim # xdebug インストール RUN pecl install xdebug \ && docker-php-ext-enable xdebugdocker-compose.ymlもディレクトリ構成に合わせて下記のように記述します。
docker-compose.ymlversion: '3' services: app: build: context: ./docker container_name: app stdin_open: true tty: true ports: - '5000:80' volumes: - ./src:/var/www/html - ./docker/php.ini:/usr/local/etc/php/php.ini2. launch.jsonの作成と記述
VSCodeのサイドバー「実行」-> 「launch.jsonファイルを作成します」をクリック-> 環境の選択から「PHP」を選択
この段階でlaunch.jsonが自動生成され、下画像のようなディレクトリ構成になると思います。
自動生成されたlaunch.jsonにpathMappingsを追加して、下記のようにしておきます。launch.json{ "version": "0.2.0", "configurations": [ { "name": "Listen for XDebug", "type": "php", "request": "launch", "port": 9000, "pathMappings": { "/var/www/html/": "${workspaceRoot}/src" } }, { "name": "Launch currently open script", "type": "php", "request": "launch", "program": "${file}", "cwd": "${fileDirname}", "port": 9000 } ] }3. php.iniの記述(本題)
今回の記事を書こうと思ったきっかけの部分です。
下記のように記述しました。php.ini[xdebug] ; リモートデバッグ有効化 xdebug.mode=debug ; リモートデバッグの自動開始 xdebug.start_with_request=yes ; ホスト指定 xdebug.client_host=host.docker.internal ; ホスト側のポート指定 xdebug.client_port=9000 ; VSCODEをIDEとして指定 xdebug.idekey="VSCODE"Xdebugのバージョンが2から3になるにあたって、書き方の変更が必要でした。
今回記述した設定だと、下記のような変更が必要です。
この他にも書き方が色々と変わっているみたいなので、詳しくは公式ドキュメントを参照してください。リモートデバッグの有効化
Xdebug 2: xdebug.remote_enable=1
Xdebug 3: xdebug.mode=debugリモートデバッグの自動開始
Xdebug 2: xdebug.remote_autostart=1
Xdebug 3: xdebug.start_with_request=yesホスト指定
Xdebug 2: xdebug.remote_host=host.docker.internal
Xdebug 3: xdebug.client_host=host.docker.internal
※以前は「host.docker.internal」はMac限定だったようですが、現在はWindowsでも使用可能です。ホスト側のポート指定
Xdebug 2: xdebug.remote_port=9000
Xdebug 3: xdebug.client_port=90004. index.phpの作成
サンプルレベルで試してみます。
index.php<?php echo 'Hello World';5. Dockerコンテナのビルドと起動
Docker Desktopを起動してから、Windows PowerShell または VSCodeの表示-> ターミナルから下記コマンドを実行します。
ターミナル$ docker-compose up -d --buildデバッグの実行
1. ブレークポイントの設置、デバッグ実行
設置したい行の左をクリックしてブレークポイントを設置します。
この状態でF5キーを押すか、緑三角マークの「デバッグの開始」を押すとデバッグが実行されます。2. ブラウザで接続
docker-composeでポート番号5000を設定したので、ブラウザから接続します。
3. VSCodeで確認
手順の1~2を実行すると、下記画像のようにブレークポイントで止まります。
これで成功!
おわりに
Xdebugのバージョン変更に伴った変化により、自分はデバッグ環境が動かない原因の特定に時間がかかりました。
もしも同じような人がいて、助けになれば幸いです。
- 投稿日:2021-01-11T18:10:23+09:00
X-Roadを手軽に試せるSecurity Server Docker Imageが出たので試してみる1
はじめに
X-Roadは、エストニアの政府機関や、政府機関と連携を行う企業(銀行など)の間で使われている情報連携を行うための技術です。
X-Roadはソースコードはgithub.com/nordic-institute/X-Roadにあるものの、Docker Imageやダウンロードしてすぐ動くパッケージがなかったので使ってみた系の記事があまりありませんでした。
最近、Planetway社でX-Roadを手軽に試せるDocker Imageを公開しました[hub.docker.com]。
この記事では、X-Roadを知らない方向けに、事前知識を端折りながらまずはX-Roadを使ってみることから始めます。# full disclosure 私はPlanetway社の中の人です
docker-compose upでX-Road Security Serverを立ち上げる
Docker Imageが公開されているのです。
何はともあれローカルで立ち上げてみましょう。作業用のディレクトリを作り、Docker Hubのドキュメントにある内容をコピーして
docker-compose.yml
ファイルを作成します。% cat docker-compose.yml version: '3.7' services: ss01: image: planetway/xroad-securityserver:6.24.1-1 command: bash -c "/files/initdb.sh && /files/cmd.sh" depends_on: - postgres environment: # JP-TEST or JP - PX_INSTANCE=JP-TEST - PX_MEMBER_CLASS=COM - PX_MEMBER_CODE=0170121212121 - PX_SS_CODE=qiita-demo-01 - PX_TSA_NAME=TEST of Planetway Timestamping Authority 2020 - PX_TSA_URL=https://tsa.test.planetcross.net - PX_TOKEN_PIN=jXq+rlg2VS - PX_ADMINUI_USER=admin - PX_ADMINUI_PASSWORD=Secret222 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password - PX_SERVERCONF_PASSWORD=serverconf - PX_MESSAGELOG_PASSWORD=messagelog - PX_OPMONITOR_PASSWORD=opmonitor - PX_POPULATE_DATABASE=true - PX_ENROLL=true ports: - "2080:2080" - "4000:4000" - "5500:5500" - "5577:5577" - "5588:5588" - "8000:80" - "8443:443" volumes: # .p12 files and keyconf.xml - "px-ss-signer:/etc/xroad/signer" # mlog.zip files are stored here, and ./backup contains backups - "px-ss-xroad:/var/lib/xroad" postgres: image: postgres:10 environment: POSTGRES_PASSWORD: password ports: - "5432:5432" volumes: - "px-ss-postgres:/var/lib/postgresql/data" volumes: px-ss-postgres: px-ss-signer: px-ss-xroad:Docker Hubのドキュメントでは環境変数を...と省略しているところはとりあえず適当に埋めます。
PX_SS_CODE
はX-Roadメンバー(X-Roadに参加する組織)の中のSecurity Serverを表すユニークな文字列です。ここからコピペする際には、ユニークな文字列に変更してください。そして
docker-compose up
してSecurity ServerとPostgreSQLをまとめて起動します。% docker-compose up Creating network "px-ss-docker_default" with the default driver Creating px-ss-docker_postgres_1 ... done Creating px-ss-docker_ss01_1 ... done Attaching to px-ss-docker_postgres_1, px-ss-docker_ss01_1 postgres_1 | The files belonging to this database system will be owned by user "postgres". postgres_1 | This user must also own the server process. postgres_1 | postgres_1 | The database cluster will be initialized with locale "en_US.utf8". postgres_1 | The default database encoding has accordingly been set to "UTF8". postgres_1 | The default text search configuration will be set to "english". postgres_1 | postgres_1 | Data page checksums are disabled. postgres_1 | postgres_1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok postgres_1 | creating subdirectories ... ok postgres_1 | selecting default max_connections ... 100 postgres_1 | selecting default shared_buffers ... 128MB postgres_1 | selecting default timezone ... Etc/UTC postgres_1 | selecting dynamic shared memory implementation ... posix postgres_1 | creating configuration files ... ok ss01_1 | 2021-01-11 09:00:06,566 Creating /var/lib/xroad/backup ss01_1 | 2021-01-11 09:00:06,655 Generating new internal.[crt|key|p12] files ss01_1 | /CN=0874c65254b7 -subj ss01_1 | Generating a RSA private key ss01_1 | ............................................................+++++ ss01_1 | ............+++++ ss01_1 | writing new private key to '/etc/xroad/ssl/internal.key' ss01_1 | ----- ss01_1 | 2021-01-11 09:00:07,004 Generating new proxy-ui-api.[crt|key|p12] files ... # しばらく待つと ss01_1 | {"timestamp":"2021-01-11T09:03:10.183Z","level":"INFO","thread":"main","logger":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","message":"Tomcat started on port(s): 4000 (https) with context path ''","context":"X-Road Proxy Admin REST API"}↑の最後の行が出てきたら、
https://localhost:4000/ をブラウザで開いてみしょう。
X-Road Security Serverの管理画面です。Safariでは"接続はプライベートではありません", Chromeでは"この接続ではプライバシーが保護されません"と表示されますが、理解しているので先に進みます。
ログイン画面では環境変数の
PX_ADMINUI_USER
とPX_ADMINUI_PASSWORD
でログインします。X-Roadとは
今一体何を立ち上げたのでしょうか。
Security Serverとは何でしょうか。
図1 Deployment view of X-Road (赤い線は筆者による強調)
docker-compose.yml
に書いたplanetway/xroad-securityserver
Docker Imageは、上図のClient Security Server, Service Security Serverの青い箱に当たるソフトウェアです。X-Roadの情報連携とは、Service Clientという組織内のClient Information Systemから、Service Providerという組織内のService Information Systemが提供する機能を使うことを表します。
Security Serverは、Client Information Systemから見るとForward Proxyの役割を果たし、Service Information Systemから見るとReverse Proxyの役割を果たします。Security ServerはClient Information SystemとService Information Systemをインターネットを通してつなげるセキュアなトンネルを構築します。
Client Information SystemとClient Security Serverの間、そしてService Information SystemとService Security Serverの間は、SOAPとRESTプロトコルを話します。
X-Roadの情報連携をやってみましょう。
認証用証明書のActivate、Security Serverの登録とSubsystemの登録
planetway/xroad-securityserver
Docker Imageは、Security Server立ち上げ時のセットアップ手順をいくつか自動的に実行しますが、情報連携を行う=HTTPリクエストをSecurity Serverに送る、までにはまだいくつかステップがあります。認証用証明書をActivateしましょう。
https://localhost:4000/ を開き、ログインします。
"KEYS AND CERTIFICATES" をクリック -> "Token: softToken-0"の左の ">" をクリック -> "TEST of Planetway Intermediate L1 Organizations CA 2020 ..." をクリック -> "ACTIVATE" をクリックします。認証用証明書をActivateしました。
Security Serverの登録リクエストを送りましょう。バツを押してその画面を閉じ、"KEYS AND CERTIFICATES" をクリック -> "Register" ボタンを押します。
"127.0.0.1"と入力し "ADD" ボタンを押します。
これでSecurity Serverの登録リクエストを送信したことになります。図1のCentral Serverでは、X-Roadに参加する組織と、それぞれの組織が運用するSecurity Serverのカタログを管理しています。Security Serverの登録リクエストは、Central ServerのカタログにこのSecurity Serverを登録してもらうためのリクエストです。
次にSubsystemの登録を行います。
"CLIENTS" をクリック -> "Add Subsystem" ボタンを押します。"Subsystem Code"には"democlient"と入力し、"ADD SUBSYSTEM"ボタンを押します。
"CLIENTS"を押し以下のように表示されていれば(Docker Demo Company (Owner)とdemoclientの行に緑の円と"REGISTERED"が表示されていれば)Subsystemの登録は完了です。
図1におけるService Client組織に所属するClient Information System情報システムをdemoclientと言う名前で登録しました。
Security ServerのConnection TypeをHTTPに変更する
もうそろそろです。
Client Information SystemとClient Security Serverの間は、デフォルトではHTTPSを使用します。この記事では簡略化するためHTTPに変更します。
同管理画面で、"CLIENTS" をクリック -> "democlient" の文字のところをクリック -> "INTERNAL SERVERS" をクリックします。下図のように、"CONNECTION TYPE"を"HTTP"に変更してください。
HTTPリクエストをSecurity Serverに送る
Service Provider側は、この記事では、予めPlanetway社が提供するものを利用しましょう。Planetway社では、現在時刻を返すtimeというX-Roadサービスをデモとして提供しています。
以下のようにcurlのコマンドを実行してください。
% curl -v "http://localhost:8000/r1/JP-TEST/COM/0170368015672/demoprovider/time" -H "X-Road-Client: JP-TEST/COM/0170121212121/democlient" * Connected to localhost (127.0.0.1) port 8000 (#0) > GET /r1/JP-TEST/COM/0170368015672/demoprovider/time HTTP/1.1 > Host: localhost:8000 > User-Agent: curl/7.64.1 > Accept: */* > X-Road-Client: JP-TEST/COM/0170121212121/democlient > < HTTP/1.1 200 OK < Date: Wed, 13 Jan 2021 12:33:54 GMT < Content-Type: text/plain;charset=utf-8 < x-road-id: JP-TEST-b3fcf843-4d50-4108-b25a-22b5993ad0c9 < x-road-client: JP-TEST/COM/0170121212121/democlient < x-road-service: JP-TEST/COM/0170368015672/demoprovider/time < x-road-request-id: f13d39d1-c5a7-4fc5-bd2f-ac002e2dc2e7 < x-road-request-hash: N02MYtDKDzpT1QN7uUQlgUa+I5Vu5ImpX1WKxj/fByjKCUITbWgAlySJwfSt0xQU1AzaPG0RiEqoONQBxXD0jQ== < Content-Length: 41 < {"now":"2021-01-13T12:33:54.692995982Z"}と表示されれば成功です!
このcurlコマンドを紐解いていきます。
localhost:8000
私の環境では、DockerはmacOS用のDocker Desktopで動作させています。この記事冒頭のdocker-compose.yml
ではports以下に- 8000:80
とありました。これはlocalhost:8000
をDocker containerの80番ポートに転送します。Docker container内のSecurity Serverはポート80番でlistenしています。
/r1/JP-TEST/COM/0170368015672/demoprovider/time
Information SystemとSecurity Serverの間のプロトコルは、X-Road: Message Protocol for RESTと言うプロトコルにしたがいます。URLのpath部分はMessage Protocol for REST文書の中でserviceId
として記載があります。
r1
はプロトコルのバージョン。
JP-TEST
はX-RoadインスタンスのIDです。X-Roadのインスタンスとは、図1に表される箱全部を含んだまとまりで、あるGoverning Authority/運営機関と、運営機関が提供する環境で情報連携を行う組織群を含みます。JP-TEST
はPlanetway社が運営機関を務めています。他にEE
(エストニア),FI
(フィンランド)などがあります。
COM
はX-Roadに参加する組織が法人であることを表します。他にGOV
などがあります。
0170368015672
はPlanetway社を表すX-Road Member IDです。0170121212121
はDocker Imageの使用者が使えるテスト用のX-Road Member IDです。
demoprovider
はPlanetway社の情報システムを表すSubsystem IDです。
time
はX-Road Serviceコードです。
X-Road-Client: JP-TEST/COM/0170121212121/democlient
というヘッダの値は、Client Information Systemを表しています。Security Serverはアクセスコントロールの機能も含みます。予めtimeサービスは、
JP-TEST/COM/0170121212121/democlient
から呼び出せるよう設定済みです。time X-Road Serviceの実体
timeサービスは以下のようなGolangのコードとして実装しています。
package main import ( "encoding/json" "net/http" "os" "time" ) func handler(w http.ResponseWriter, r *http.Request) { t := time.Now() enc := json.NewEncoder(w) err := enc.Encode(map[string]interface{}{ "now": t, }) if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } } func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/", handler) http.ListenAndServe(":"+port, nil) }普通のJSONを返すAPIサーバですね。
http.HandleFunc
の第一引数が/
であることに注意。これが図1のService Information Systemに当たります。いくつか私が面白いと思う点を書きます。
Security ServerがInformation Systemから見るとシンプルなトンネルであること
このGolangのサーバをローカルで実行し、立ち上がったサーバにcurlでHTTPリクエストを送る手順と、インターネットのどこかでPlanetway社が提供するtimeサービスを呼び出す手順の違いが小さいこと。
X-Road-Client
リクエストヘッダ、URLのpath部分だけです。X-Roadのセキュリティ面はInformation Systemには見えない
よくある外部APIと比較するとどうでしょう。Bearer tokenのようなものもクライアント証明書も何も見えません。認証や認可はSecurity Serverが隠蔽しています。
curlのリクエスト送り先はSecurity Server
知る必要があるのは、組織のID、その中のサービスIDからなる
serviceId
だけです。相手のURLは知る必要がありません。インターネットのレイヤの上に綺麗にRPCのレイヤをのっけています。まとめ
DockerでX-Road Security Serverを立ち上げ、それを通して時刻を返すデモサービスを呼び出すcurlコマンドを実行しました。
続く
- 投稿日:2021-01-11T18:02:31+09:00
(自分用)docker+code-server、cloud9でC#環境作ってみる
はじめに
この記事の続きみたいな感じです。
dockerでcode-serverを構築して、そこでC#環境作れるか試してみます。code-server_1
以下のようなディレクトリを作ります。
ls > Dockerfile code-server docker-compose.yml projectsDockerfileとdocker-compose.ymlはこんな感じです。
公式のdocker-imageを使ってそこに.net coreをinstallしています。
Dockerfile
DockerfileFROM codercom/code-server:3.8.0 USER root # Install wget and other module RUN apt-get update && apt-get install -y \ wget # Install code-server plugin # ※commandからのextension installは効かない? RUN code-server --install-extension ms-dotnettools.csharp # Install .NET5 ENV DOTNET_ROOT=/usr/share/dotnet ENV PATH=/usr/share/dotnet:/root/.dotnet/tools:$PATH # 以下の環境変数を変える必要あり # 詳細1: https://github.com/dotnet/core/issues/2186 # 詳細2: https://github.com/dotnet/core/blob/master/Documentation/build-and-install-rhel6-prerequisites.md ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true RUN wget -O dotnet.tar.gz https://download.visualstudio.microsoft.com/download/pr/a0487784-534a-4912-a4dd-017382083865/be16057043a8f7b6f08c902dc48dd677/dotnet-sdk-5.0.101-linux-x64.tar.gz \ && wget -O dotnet_runtime.tar.gz https://download.visualstudio.microsoft.com/download/pr/6bea1cea-89e8-4bf7-9fc1-f77380443db1/0fb741b7d587cce798ebee80732196ef/aspnetcore-runtime-5.0.1-linux-x64.tar.gz \ && dotnet_sha512='398d88099d765b8f5b920a3a2607c2d2d8a946786c1a3e51e73af1e663f0ee770b2b624a630b1bec1ceed43628ea8bc97963ba6c870d42bec064bde1cd1c9edb' \ && echo "$dotnet_sha512 dotnet.tar.gz" | sha512sum -c - \ && dotnet_runtime_sha512='fec655aed2e73288e84d940fd356b596e266a3e74c37d9006674c4f923fb7cde5eafe30b7dcb43251528166c02724df5856e7174f1a46fc33036b0f8db92688a' \ && echo "$dotnet_runtime_sha512 dotnet_runtime.tar.gz" | sha512sum -c - \ && mkdir -p "/usr/share/dotnet" \ && mkdir -p "/usr/bin/dotnet" \ && mkdir -p "/root/.dotnet/tools" \ && tar zxf dotnet.tar.gz -C "/usr/share/dotnet" \ && rm dotnet.tar.gz \ && tar zxf dotnet_runtime.tar.gz -C "/usr/share/dotnet" \ && rm dotnet_runtime.tar.gz \ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet \ && dotnet help USER coder
docker-compose.yml
docker-compose.ymlversion: "3" services: code: build: context: . dockerfile: Dockerfile restart: always environment: PUID: 1000 PGID: 1000 PASSWORD: password ports: - 20000:8080 volumes: - ./projects:/home/coder/project - ./code-server:/home/coder/.local/share/code-server起動します。
docker-compose up -d --buildDockerfileのこのコマンドでC#の拡張機能を入れたつもりなのですが
どうも入っていないみたい?です。
ターミナルから同じようにコマンドを叩いてもUIの方には反映されませんでした。RUN code-server --install-extensions ms-dotnettools.csharp仕方ないので拡張機能は手動で入れます。
主だった3つを入れてみました。
適当なプロジェクトを作ってみます。
dotnet new console -o tutorial ls > Program.cs tutorial.csprojtutorialフォルダ以下にファイルを追加します。
C# extensionsが使えそうな雰囲気があるのですがファイルの生成はしてくれませんでした。
仕方ないので通常のファイル作成で名前を
Calc.cs
とします。
Program.csとCalc.csを以下の内容にします。
Calc.cs
Calc.csusing System; namespace tutorial2 { class Calc { public static double Add(double a, double b) { return a + b; } } }
Program.cs
Program.csusing System; using tutorial2; namespace tutorial { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); var ret = Calc.Add(1, 3); Console.WriteLine($"Cal Result is {ret}"); } } }デバッグはどうでしょうか?
launch.jsonに.Net Core Launchを指定し、ブレークポイントを置いて実行してみます。???以下のようなエラーがDEBUG CONSOLEに表示されます。
このURLを見てみると、デバッガーはMicrosoftのIDEでないと動作しないライセンスになっているみたいです。
code-serverでのissueにも挙がっていて独自デバッガー?でやる方法しかないみたいです。。。
issueもライセンスの問題により標準デバッガーは使えないという事で閉じられていました。code-server_2
linuxserver/code-server
にDotNetCoreを入れて有志の方が作った
imageがあったのでそっちも乗っけておきます。git clone https://github.com/ptr727/VSCode-Server-DotNetCore.git cd VSCode-Server-DotnetCore docker-compose up -d # 起動cloud9
おまけでcloud9でも試してみます。
Dockerfileとdocker-compose.ymlはこんな感じです。
linuxserver/cloud9
にDotNetCoreを入れる形にしてみました。
Dockerfile
DockerfileFROM linuxserver/cloud9:version-1.27.4 RUN mkdir -p /code/projects # Install wget RUN apt-get update \ # Install wget && apt-get install -y wget # Install .NET5 ENV DOTNET_ROOT=/usr/share/dotnet ENV PATH=/usr/share/dotnet:/root/.dotnet/tools:$PATH ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true RUN wget -O dotnet.tar.gz https://download.visualstudio.microsoft.com/download/pr/a0487784-534a-4912-a4dd-017382083865/be16057043a8f7b6f08c902dc48dd677/dotnet-sdk-5.0.101-linux-x64.tar.gz \ && wget -O dotnet_runtime.tar.gz https://download.visualstudio.microsoft.com/download/pr/6bea1cea-89e8-4bf7-9fc1-f77380443db1/0fb741b7d587cce798ebee80732196ef/aspnetcore-runtime-5.0.1-linux-x64.tar.gz \ && dotnet_sha512='398d88099d765b8f5b920a3a2607c2d2d8a946786c1a3e51e73af1e663f0ee770b2b624a630b1bec1ceed43628ea8bc97963ba6c870d42bec064bde1cd1c9edb' \ && echo "$dotnet_sha512 dotnet.tar.gz" | sha512sum -c - \ && dotnet_runtime_sha512='fec655aed2e73288e84d940fd356b596e266a3e74c37d9006674c4f923fb7cde5eafe30b7dcb43251528166c02724df5856e7174f1a46fc33036b0f8db92688a' \ && echo "$dotnet_runtime_sha512 dotnet_runtime.tar.gz" | sha512sum -c - \ && mkdir -p "/usr/share/dotnet" \ && mkdir -p "/usr/bin/dotnet" \ && mkdir -p "/root/.dotnet/tools" \ && tar zxf dotnet.tar.gz -C "/usr/share/dotnet" \ && rm dotnet.tar.gz \ && tar zxf dotnet_runtime.tar.gz -C "/usr/share/dotnet" \ && rm dotnet_runtime.tar.gz \ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet \ && dotnet help
docker-compose.yml
docker-compose.ymlversion: "3" services: code: build: context: . dockerfile: Dockerfile restart: always environment: - PUID=1000 - PGID=1000 - TZ=Asia/Tokyo - GITURL=https://github.com/linuxserver/docker-cloud9.git #optional - USERNAME=user #optional - PASSWORD=password #optional ports: - 50000:8000 volumes: - ./projects:/code/projects - ./docker.sock:/var/run/docker.sock #optionalcode-server同様に適当なプロジェクトをターミナルから作って試します。
割愛しますが、code-server同様dotnet run
までちゃんとできました。
cloud9はインテリセンスやヒストリーがちゃんと効くのでいいですね。デバッグはどうでしょうか?
ブレークポイントは置けますがRunnerをどう作るのかわからず断念しました。。。
AWS Cloud9の方だとできるみたいですがこっちだとどうなのでしょうね?結論
web-ide自体は有用で便利だと思いますが
構築後にも周辺知識が必要だったり、拡張機能がうまく効かない等で本格的な開発はまだ難しそうという印象を受けました。
もっとレベルの高い人だと出来るのでしょうが私ではちょっと。。。
現状は大人しくwindows+visual studioでC#の開発を行うのがやはり無難でしょうか。
ただ、docker+code-server or cloud9でpythonとかの記事はちらほらあるのでそっちだと問題なく使えるのでしょうか。
気が向いたらpython+αで試してみたいと思いました。
- 投稿日:2021-01-11T17:21:55+09:00
緊急事態宣言下だし、人狼ゲームを実装してみた【Docker・JavaScript】
動機
春先の緊急事態宣言下ではZoom飲みが大流行したせいか、オンラインの人狼が重くなって困りました。また発令されたし、みんなが自分で人狼ゲームを起動できたら幸せなのでは?というノリで実装&公開したので紹介します。
紹介
以下のような簡単なUIのチャット人狼です。ホストの一人がDockerでゲームを立ち上げたら、ほかの人はブラウザ(スマホでもOK)からアクセスするだけで簡単に遊べます。
遊び方(ホスト)
Dockerコンテナの起動
まず以下のコマンドでDockerコンテナを起動します。初回はGitHub Container Registryからイメージがpullされます。
docker container run -it --rm -p 3000:3000 ghcr.io/dr666m1/werewolfポートの公開
3000番ポートでゲームが起動しているので、パブリックIPアドレスのある環境(GCEなど)ならみんなにIPアドレスを伝えるだけです。注意点としては、
http://...:3000
のようにポート番号を明示する必要があるかもしれないことと、ファイアウォールの設定を確認しておくことです。パブリックIPアドレスのない環境ではngrokを利用するのが便利です。初期設定が完了すると
ngrok http 3000
というコマンドで3000番ポートを公開できるようになります。コマンド後にURLが表示されるので、それをみんなに伝えてください。無料枠での制限はこちらご確認ください。遊び方(全員)
ホストから教えてもらったURLにブラウザでアクセスしましょう。以下のような画面が表示されたら名前を決めて入場してください。
その後は普通の人狼ゲームです。役職は現状「市民」「人狼」「占い師」「霊媒師」「狩人」のみ1と標準的なので、迷うことはないと思います。
実装
Node.jsで実装しています。GitHubに全てのコードが置いてあるので興味があればご覧ください。似たようなものを作る人の参考に、利用したパッケージを簡単に紹介します。全部
npm install
で使えるはずです。Next.js
Next.jsはReactでUIを作成するためのフレームワークです。SSG(static generation)やSSR(server-side rendering)を利用できるのが特徴です。今回は
next export
で静的なHTMLファイルを出力するところまでNext.jsで実装しました2。GitHubリポジトリのclientディレクトリ以下が関連ファイルです。bulma
bulmaはCSSフレームワークです。DOMのクラスを設定するだけで見た目をいい感じに整えてくれます(例えば以下は
notification
クラス)。bulmaのおかげで、今回CSSはほとんど書いていません3。
Next.jsの枠組みで利用するには、
_app.js
の冒頭に一行追記するだけです。_app.jsimport "bulma/css/bulma.css" // 追記 export default function MyApp({ Component, pageProps }) { return <Component {...pageProps} /> }socket.io
socket.ioはウェブソケットを扱うパッケージで、チャットの実装に利用しました。wsというパッケージもあるのですが、socket.ioの方が多機能なので今回はそちらを使っています(例:ウェブソケットが使えない状況でロングポーリングに切り替えられる、roomやnamespaceという概念でクライアントを整理できる)。ちょっと今回の実装では活かしきれなかった部分も多いのですが。
後書き
JavaScriptは全くの初心者なので、バグがあったらすみません。Zoom飲みとかにご活用ください。noteにも稀に投稿しているのでよければご覧ください(直近の記事)。
要望があれば「狂人」とかいろいろ追加するかもしれません。 ↩
custom serverを利用すればNext.jsの枠組み内で実装を完了できそうでしたが、UIに集中したくて分離しました。Dockerfileを見ての通り、多段階ビルドになっています ↩
JavaScriptの中で多少スタイルをいじった程度です。 ↩
- 投稿日:2021-01-11T14:59:22+09:00
【ギリ初心者向け】Laravel Docker AWS(EC2) Webアプリ(PHP)を0から簡単にデプロイする方法(無料)② ーDocker開発環境構築編(Laravel)ー
0.概要
何度もいいますが、知らない単語が出た瞬間ググってください!!!!!
①の全体像編がこちらにあるのでこちらを一読してからだと理解がスムーズかと!!!
https://qiita.com/SG_Sg/items/6b8ce48567b6b6602805
今回で作成するは具体的にいうと赤いとこ
Dokcerを利用してLaravel(PHP)のプロジェクトを作成(dockerの説明)
さて具体的にDockerをを利用して環境構築したいが、、、、
「Dockerってなんやねん」「Docker使うメリットなんやねん」「開発現場でどうやって使うねん」
疑問だらけのため、ざっっくり説明してからにしよう!(最初いくらググってもマジでちょっと何言ってるかわかんないっすねって感じでした)
Dockerとは??等細かいところはググってくださいな、、1.Dockerのメリット、なぜプロのエンジニアは使うのか
①MACを汚さずに環境とプロジェクト、プログラムを作れる!
どういうことかって???
Dockerを使わずにプロジェクトをつくるとどうなるかみてみよう!!
こんな風にバージョン違いだったり他のPCの環境に依存してしまう!!Dockerを使うプロジェクトをつくるとどうなるかみてみよう!!
Dockerを使えばDockerの中に環境をインストールしてプロジェクトごとgithub上にのっけるイメージ
Docker内に必要な環境をインストールするから
Macに必要な環境をインストールしなくて良い!!2.まずはいろいろ準備(GitとかDockerをインストールとか)
以下デフォルトのターミナル使ってるよ!
①githubアカウントの作成
https://github.com
②Gitの初期設定
すみません。。「Mac git初期設定」でググってください汗
最終的に下記のように表示されればokです。MacBook-Pro% git config --list | grep user user.name=[githubname] user.email=67626524+[githubname]@users.noreply.github.com③GithubSSH接続設定
これも「Mac Github SSH接続」とかでググってね!エラーとかがでたらまたそのエラー文をぐぐるんや!!!MacBook-Pro% ssh -T github.com Hi [githubの名前]! You've successfully authenticated, but GitHub does not provide shell access.こんなかんじに
successfully
の文字が出れば大体いける!④ docker, docker-compose(起動したり停止できたりするやつ)のインストール
Docker for Macをインストール
https://docs.docker.com/docker-for-mac/install
インストール確認(なにかインストールしたら必ずインストールされてるか確認!)MacBook-Pro% docker --version Docker version 20.10.0, build 7287ab3 MacBook-Pro% docker-compose --version docker-compose version 1.27.4, build 405241923.Dockerプロジェクトを作る!!
3-1.github動作確認まで
①プロジェクト(ディレクトリ)を作成する
私はホームディレクトリに「LaravelProjext」をつくってその中に「docker-test」ディレクトリを作成!!このへんはご自由に!!!MacBook-Pro % mkdir LaravelProject MacBook-Pro % cd LaravelProject MacBook-Pro LaravelProject % mkdir docker-test MacBook-Pro LaravelProject % cd docker-test MacBook-Pro docker-test %②リモートリポジトリを作る
作り方は「giuhubリモートリポジトリ 作成」でググろう!!
「DockerLaravelTestProject」を作成
②リモートリポジトリにテストプッシュ!Gitが機能しているかの確認
//README.mdファイルを作成 MacBook-Pro docker-test % echo "README import First" >> README.md //git管理できるようにする MacBook-Pro docker-test % git init //ステージングにaddする! MacBook-Pro docker-test % git add . //commitする!! MacBook-Pro docker-test % git commit -m "first commit README" //push先のリモートリポジトリをGithubに!!(SSHで接続 ※URLはSSH) MacBook-Pro docker-test % git remote add origin git@github.com:SugiKoki/DockerLaravelTestProject.git //リモートリポジトリ先を確認!しっかりgithubのプロジェクトになっている MacBook-Pro docker-test % git remote -v origin git@github.com:SugiKoki/DockerLaravelTestProject.git (fetch) origin git@github.com:SugiKoki/DockerLaravelTestProject.git (push) //gitのブランチを確認 MacBook-Pro docker-test % git branch * master //gitのブランチ(master)にプッシュ MacBook-Pro docker-test % git push -u origin master kokisugi@sugihirokinoMacBook-Pro docker-test %③VScodeで確認する
しっかりディレクトリの中に書かれていることを確認!!これで作業できる!!!!3-2.最終ゴールの確認
ファイル構成はこんな感じをめざすよ!!
backendの中が実際にプログラミングするところ!!3-3.アプリケーションサーバー(app)を作る(入れる)
①docker-compose.yml を作成する
MacBook-Pro docker-test % touch docker-compose.ymlVScodeでディレクトリを開いて以下のようにする
以下が内容version: "3.8" services: app: build: ./infra/php volumes: - ./backend:/work web: image: nginx:1.18-alpine ports: - 10080:80 volumes: - ./backend:/work - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf working_dir: /work db: build: ./infra/mysql volumes: - db-store:/var/lib/mysql volumes: db-store:上のappってとこがアプリケーションサーバー
真ん中のwebってとこがwebサーバー
下のdbがデータベースサーバー
作りたい環境をここで設定してこれに合わせてDockerにインストールしていく!!!
②./docker/php/Dockerfile を作成する
MacBook-Pro docker-test % mkdir -p infra/php MacBook-Pro docker-test % touch infra/php/DockerfileFROM php:7.4-fpm-buster SHELL ["/bin/bash", "-oeux", "pipefail", "-c"] ENV COMPOSER_ALLOW_SUPERUSER=1 \ COMPOSER_HOME=/composer COPY --from=composer:1.10 /usr/bin/composer /usr/bin/composer RUN apt-get update && \ apt-get -y install git unzip libzip-dev libicu-dev libonig-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ docker-php-ext-install intl pdo_mysql zip bcmath COPY ./php.ini /usr/local/etc/php/php.ini WORKDIR /workここで行っていること
Composerコマンドのインストール
Laravelで必要な
bcmath, pdo_mysql が不足しているのでインストール③./docker/php/Dockerfile を作成する
MacBook-Pro docker-test % touch infra/php/php.ini以下のコードをphp.iniへ
zend.exception_ignore_args = off expose_php = on max_execution_time = 30 max_input_vars = 1000 upload_max_filesize = 64M post_max_size = 128M memory_limit = 256M error_reporting = E_ALL display_errors = on display_startup_errors = on log_errors = on error_log = /dev/stderr default_charset = UTF-8 [Date] date.timezone = Asia/Tokyo [mysqlnd] mysqlnd.collect_memory_statistics = on [Assertion] zend.assertions = 1 [mbstring] mbstring.language = Japanese3-4.ウェブサーバー(web)を作る(入れる)
①docker/nginx/default.conf を作成する
MacBook-Pro docker-test % mkdir infra/nginx MacBook-Pro docker-test % touch infra/nginx/default.confserver { listen 80; server_name example.com; root /work/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass app:9000; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } }3-5.データベース(db)サーバーを作る(入れる)
①./docker/mysql/Dockerfile を作成する
MacBook-Pro docker-test % mkdir infra/mysql MacBook-Pro docker-test % touch infra/mysql/Dockerfile以下のコードを貼り付ける!
FROM mysql:8.0 ENV MYSQL_DATABASE=sg_db \ MYSQL_USER=sg \ MYSQL_PASSWORD=sg \ MYSQL_ROOT_PASSWORD=sg \ TZ=Asia/Tokyo COPY ./my.cnf /etc/mysql/conf.d/my.cnf RUN chmod 644 /etc/mysql/conf.d/my.cnfここは任意なので好きにしてもらって結構!
データベースを接続するときの名前とパスワードだから
忘れないようにおぼえておこう!MYSQL_USER=sg \ MYSQL_PASSWORD=sg \ MYSQL_ROOT_PASSWORD=sg \②docker/mysql/my.cnf を作成する
MacBook-Pro docker-test % touch infra/mysql/my.cnf以下のコードを貼り付ける
[mysqld] # character set / collation character_set_server = utf8mb4 collation_server = utf8mb4_0900_ai_ci # timezone default-time-zone = SYSTEM log_timestamps = SYSTEM # Error Log log-error = mysql-error.log # Slow Query Log slow_query_log = 1 slow_query_log_file = mysql-slow.log long_query_time = 1.0 log_queries_not_using_indexes = 0 # General Log general_log = 1 general_log_file = mysql-general.log [mysql] default-character-set = utf8mb4 [client] default-character-set = utf8mb4これで3つのコンテナが完成!!!!しっかり最終的なディレクトリ構成になりましたか???
3-6.Docker起動!(中身の確認)
①dockerを動かしたいときに使うよ!
MacBook-Pro docker-test % docker-compose up -d --build ・・・・ Successfully built 9813d5181de8 Successfully tagged docker-test_db:latest Creating docker-test_app_1 ... done Creating docker-test_db_1 ... done Creating docker-test_web_1 ... done MacBook-Pro docker-test %上の感じにdoneとでたらそれらはOKということ!
・動かした状態でどう動いてるのか確認!MacBook-Pro docker-test % docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------- docker-test_app_1 docker-php-entrypoint php-fpm Up 9000/tcp docker-test_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp docker-test_web_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:10080->80/tcpちなみにリスタートしたりしたかったら、一度止めたかったらdown!
MacBook-Pro docker-test % docker-compose down //一度止めたらまた起動しよう MacBook-Pro docker-test % docker-compose up -d --buildDockerに入れたそれぞれサーバー(コンテナ)内に入れたのバージョン確認する方法
・appサーバー
MacBook-Pro docker-test % docker-compose exec app bash //PHPのバージョン確認 root@5ce9c9fa1435:/work# php -V //composerのバージョン確認 root@5ce9c9fa1435:/work# composer -v //インストール済みの拡張機能一覧の確認 root@5ce9c9fa1435:/work# php -m //dockerから出る root@5ce9c9fa1435:/work# exit・webサーバー
MacBook-Pro docker-test % docker-compose exec web nginx -v・DBサーバー
MacBook-Pro docker-test % docker-compose exec db bash //mysqlのバージョン確認 root@6bcf6de7e31e:/# mysql -V //dockerから出る root@6bcf6de7e31e:/work# exitこれでDocker環境構築終了だ!!!さあLaravelを入れてプログラミングしていきます!!!
定期的にGitコミットはしていったほうがよいですよ!
MacBook-Pro docker-test % git add . MacBook-Pro docker-test % git commit -m "laravel commit" MacBook-Pro docker-test % git push3-7.Laravelをインストールする(appサーバー上でやります)
①appに入って、Laravelをインストール
MacBook-Pro docker-test % docker-compose exec app bash root@5ce9c9fa1435:/work# composer create-project --prefer-dist "laravel/laravel=8.*" . //laravelバージョン確認 root@5ce9c9fa1435:/work# php artisan -V Laravel Framework 8.21.0 root@5ce9c9fa1435:/work# exit②Laravel ウェルカム画面の表示
http://127.0.0.1:10080
にアクセス!!!
・VScode確認するとbackendこんな感じになっているはず!
3-8.プログラミングしてみる!!(html,blade.phpファイルを作って表示できるか確認!)
HTML(.blade.php)を表示してみよう!!MVCモデルで進めていきます!
①backend/resources/viewsのなかに
helloディレクトリを作成
helloディレクトリの中にhello.blade.phpを作成<html> <body> <h1>HELLO Larabel<h1> </body> </html>②URLから呼び出すコントローラーを設定!
・backend/routes/web.phpを修正
以下のコードをbackend/routes/web.phpに追加する!/// URL/helloのとき「HelloController」を呼び出す Route::get('hello', 'App\Http\Controllers\HelloController@index');③backend/app/http/Controllers/の中に
HelloController.phpを作成する
以下のコードをbackend/app/http/Controllers/の中に
HelloController.phpに追加する!<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\KrononUser; use Faker\Provider\ar_JO\Person; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; class HelloController extends Controller { public function index() { return view('hello.hello'); } }④URLにアクセスして表示!!!
http://127.0.0.1:10080/hello
3-9.データベースに接続してみる!!!!
ソースコード上で backend/.env のDB接続設定を修正する。
①以下のコードに変更!!DBサーバー作った時のに合わせながら!DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=sg_db DB_USERNAME=sg DB_PASSWORD=sg
②backend/.env.example も同様に変更するDB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=sg_db DB_USERNAME=sg DB_PASSWORD=sgちなみにgitcloneした際はここからやれば動きます
③Laravelインストール
app コンテナにはいってからいろいろ
MacBook-Pro docker-test % docker-compose exec app bash //コンポーザーをインストールする root@36ffabe3ffc9:/work# composer install //.env.exampleを.envファイルにコピーする root@36ffabe3ffc9:/work# cp .env.example .env //このコマンドでアプリケーションキーを生成できます。 root@36ffabe3ffc9:/work# php artisan key:generate Application key set successfully. //デフォルトで入っているマイグレーションを実行!!デフォルトのテーブルがDBに反映される root@36ffabe3ffc9:/work# php artisan migrate Migration table created successfully. Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (40.88ms) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (37.06ms) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (35.00ms)これでデフォルトですが、DBにテーブルなどが入りました!!
④データベースの確認(デフォルト)
MacBook-Pro docker-test % docker-compose exec db bash //設定したUSERでmysqlにログイン root@d94d20dd2212:/# mysql -u sg -p //設定したPASSWORDを入力.envに書いた!! Enter password: mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | sg_db | +--------------------+ 2 rows in set (0.01 sec) mysql> use sg_db Database changed mysql> show tables; +-----------------+ | Tables_in_sg_db | +-----------------+ | failed_jobs | | migrations | | password_resets | | users | +-----------------+⑤migrationをつくってアプリに反映する!!
/backend/database/migration/2021_01_03_090902_create_people_table.php
を作成
※/backend/database/migration/の中にデフォルトでいろいろ入っているからそれをコピーすればいいかも!!
以下のコードを貼り付け!<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreatePeopleTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('people', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('mail'); $table->integer('age'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('people'); } }⑥migrationを実行(appコンテナ)の中に入って実行!
appのなかじゃないとdockerにあるDBコンテナに届かないMacBook-Pro docker-test % docker-compose exec app bash root@36ffabe3ffc9:/work# php artisan migrate Migrating: 2021_01_03_090902_create_people_table Migrated: 2021_01_03_090902_create_people_table (49.03ms)⑦Seederを作成する!!まずはデフォルトにあるDatabaseSeeder.phpから
"Seederとは??"
ダミーデータ。データベースにコマンドを実行するだけでデータを入れられる!!
DatabaseSeeder.phpに以下のソースを貼り付け$this->call(PeopleTableSeeder::class);呼び出される側のPeopleTableSeeder.phpを作成
PeopleTableSeeder.phpに以下のソースを貼り付け<?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; class PeopleTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $param = [ 'id' => 1, 'name' => 'test', 'mail' => 'test', 'age' => 20, ]; DB::table('people')->insert($param); } }⑧Seederを実行する!
MacBook-Pro docker-test % docker-compose exec app bash root@36ffabe3ffc9:/work# php artisan db:seed Seeding: Database\Seeders\PeopleTableSeeder Seeded: Database\Seeders\PeopleTableSeeder (29.08ms) Database seeding completed successfully.これでテーブルはできたし、ダミーデータもできました!あとはweb上で表示すれば完璧ですね!!
データベースに登録されているデータを表示する
①views/hello.blade.phpを作成
以下のソースhello.blade.phpを変更<html> <body> <h1>HELLO Larabel<h1> <h1>DBから表示しているよ<h1> <tr><th>Name</th><th>Mail</th><th>Age</th></tr> <br> @foreach ($items as $item) <tr> <td>{{$item -> name}}</td> <td>{{$item -> mail}}</td> <td>{{$item -> age}}</td> </tr> @endforeach </body> </html>②Controllers/HelloController.phpを変更
以下のソースに変更する<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\KrononUser; use Faker\Provider\ar_JO\Person; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; class HelloController extends Controller { public function index() { $items = DB::table('people')->get(); return view('hello.hello',['items' => $items]); } }③作成したアプリにアクセス!!
http://127.0.0.1:10080/hello
これでDBさきほどSeederでいれたダミーデータが表示されていたら完璧ですね!!!
最後にcommmitして終了!!!MacBook-Pro docker-test % git add . MacBook-Pro docker-test % git commit -m "db complete" MacBook-Pro docker-test % git pushあとはこれを世の中に出すためAWSを使えればOK!!!
次回にご期待!!お疲れ様でした
こういった環境構築かなり疲れますよねーもうへとへとです
全体像を確認したければこちら
【ギリ初心者向け】Laravel Docker AWS(EC2) Webアプリ(PHP)を0から簡単にデプロイする方法(無料)① ー全体像編ー
https://qiita.com/SG_Sg/items/6b8ce48567b6b6602805
次回は③
【ギリ初心者向け】Laravel Docker AWS(EC2) Webアプリ(PHP)を0から簡単にデプロイする方法(無料)③ ーEC2にデプロイ編ー
を予定してます。参考文献
【超入門】20分でLaravel開発環境を爆速構築するDockerハンズオン
https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4
↑の方の記事めちゃくちゃわかりやすいし、細かく書いてあるのでこちらも参考にしていただければ
特に最初の初期設定の情報のまとまりがすばらしいです。この記事の上位互換。
- 投稿日:2021-01-11T14:36:43+09:00
Laravelで 【composer install 】した時に 【command not found: composer】と表示された時
composer install時の、エラー処理方法
【状態】
Laravelをdockerで環境構築し、下記コマンドでコンテナを立ち上げた状態docker-compose up -d --build〜補足説明〜
-d
→デタッチド・モード: バックグラウンドでコンテナを実行するということ。
--build
→Dockerfileの再読み込みをしてくれて、更新した情報を反映してくれる。【問題】
コンテナが立ち上がったので、 http://localhost/にアクセスすると、下記のようなエラー文が表示された!
【原因】
composer が install できていなかった、、、【解決策】
1.Laravelが入っているディレクトリに移動(
cd
でディレクトリを変更しながらapp
やbootstrap
が入っているフォルダに移ってください)2.インストールを実行
composer installor
composer updateで実行できます。
※上記で指定したディレクトリでないと、
command not found: composer
と表示されてしまうので、注意してください!!【感想】
最近は調べる力ばかり、伸びている気がしますね、、、There is no shame in not knowing; the shame lies in not finding out
知らないことは恥ではない。知ろうとしないことこそ恥である
と言い聞かせて、
- 投稿日:2021-01-11T13:40:58+09:00
crontabでdocker-compose execを実行すると"the input device is not a TTY"が出る
解決策
-Tのオプションを使う
問題があった時の設定
0 4 * * * docker-compose exec {container_name} {some_command}解決後の設定
0 4 * * * docker-compose exec -T {container_name} {some_command}原因
よくはわかっていないが、docker-compose execはデフォルトで擬似ttyが割り当てられてしまう。
それを解除するオプションが-T
とのこと。-T
Disable pseudo-tty allocation. By defaultdocker-compose exec
allocates a TTY.参考
- 投稿日:2021-01-11T09:04:03+09:00
【これを知りたかった】Docker+RailsでRSpec導入〜トップページ表示確認テストの書き方まで
背景
- Railsのポートフォリオ作成で、RSpecの導入を検討
- 導入から、トップページの表示を確認するテストの書き方までをまとめました
1. Gemのインストール
GemfileにRails用のrspecとfactory_botのgemを加える
Gemfilegroup :development, :test do gem "rspec-rails" gem "factory_bot_rails" endDockerでbuildし直す
docker-compose build2. rspecの導入
以下のコマンドでRailsアプリに、rspecを導入
$ bundle exec rails generate rspec:install create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb3. rspecの生成ファイルの定義
- 設定ファイルはconfig/application.rb
- falseをつけると不要なテストファイルは作成されなくなる
config/application.rbconfig.generators do |g| g.test_framework :rspec, # 不要なテストファイルは以下のようにfalseをつけて書く view_specs: false, helper_specs: false, controller_specs: false, routing_specs: false end4. Viewをテストしてみる
Viewテスト用のrspec作成
rails g rspec:view Homesただ、これだけだと
/spec/views/homes/
というフォルダしか作成されないテスト用のファイル作成
/spec/views/homes/
以下にindex.html.erb_spec.rb
を作成し、以下を記述/spec/views/homes/index.html.erb_spec.rbrequire 'rails_helper' RSpec.describe "homes/index", type: :view do it 'should display top page' do visit "/" expect(page).to have_content 'こされ' end end以下補足
*visit "/"
: ルートに遷移
*expect(page).to have_content '文字列'
: 現在の表示ページ上に"文字列"があることを確認テスト実行
$ rspec homes/index should display top page Finished in 24.64 seconds (files took 7.02 seconds to load) 1 example, 0 failures
0 failures
なので、テストが成功RSpecで「NoMethodError: undefined method `visit' for ~ 」と怒られた時
visit
が使えないと言われているエラー- 以下ファイルに追記する。
- 詳しい理由は以下で記載してあるので、参考にする
spec/spec_helper.rb...略 require 'capybara/rspec' RSpec.configure do |config| config.include Capybara::DSL # 追記 ...略参考
- 投稿日:2021-01-11T06:25:19+09:00
Railsデプロイ with Docker
参考サイト
参照
Rails環境構築 with Docker
こちらでDockerを使用したRailsの環境構築までを行っております。Docker 用語とコマンド
Dockerについての用語やコマンドについてはこちらをご覧ください環境
Mac OS
docker-compose 1.27.4
heroku/7.47.7
Mysql 8.0
ruby 2.7
rails 6.1.0heroku実装
herokuログイン
terminal.rails_on_docker % heroku login heroku: Press any key to open up the browser to login or q to exit: //Enterキーでログイン rails_on_docker % heroku container:loginherokuアプリ作成
terminal.rails_on_docker % heroku create <rails-koumori> // < >内は任意の名前を指定データベース追加・設定
データベースの追加
terminal.rails_on_docker % heroku addons:create cleardb:ignite -a rails-koumori本番環境の接続先情報を環境変数に修正
database.ymlproduction: <<: *default database: <%= ENV['APP_DATABASE_DATABASE'] %> username: <%= ENV['APP_DATABASE_USERNAME'] %> password: <%= ENV['APP_DATABASE_PASSWORD'] %> host: <%= ENV['APP_DATABASE_HOST'] %>接続先情報を環境変数に設定
terminal.rails_on_docker % heroku config -a rails-koumori CLEARDB_DATABASE_URL: mysql://ユーザー名:パスワード@ホスト名/データベース名?reconnect=true rails_on_docker % heroku config:add APP_DATABASE='データベス名'-a rails-koumori rails_on_docker % heroku config:add APP_USERNAME='ユーザー名' -a rails-koumori rails_on_docker % heroku config:add APP_PASSWORD='パスワード' -a rails-koumori rails_on_docker % heroku config:add APP_HOST='ホスト名' -a rails-koumori rails_on_docker % heroku config -a rails-koumori //登録の確認本番環境用の記述
空のファイル作成
terminal.rails_on_docker % touch start.shstart.sh#!/bin/sh # 本番環境 if [ "${RAILS_ENV}" ="production" ] then bundle exec rails assets:precompile fi bundle exec rails s -p ${PORT:-3000} -b 0.0.0.0Dockerfileの追記
Dockerfile# ベースイメージの指定 FROM ruby:2.7 #追記 ENV RAILS_ENV=production . . . . #dockerにコピー COPY start.sh /start.sh #実行権限を付与 RUN shmod 744 /start.sh #起動時に実行 CMD ["sh","/start.sh"]本番環境に適用
terminal.rails_on_docker % heroku config:add RAILS_SERVE_STATIC_FILES="true" -a r ails-koumori //本番環境にassets:precompileを適用rails view画面実装
コントローラー作成
terminal.rails_on_docker % docker-compose exec web bundle exec rails g controller usersトップページにusers/indexを指定
routes.rbRails.application.routes.draw do get '/',to: "users#index" endコントローラーの記述
users.controller.rbclass UsersController < ApplicationController def index end endindex.html.erbファイルを作成し記述
src>app>views>users>index.html.erb<h1>Hello world!</h1>Dockerコンテナのプッシュとherokuへのリリース
Dockerイメージをビルドしコンテナにプッシュ
terminal.rails_on_docker % heroku container:push web -a rails-koumoriherokuにコンテナをリリース
terminal.rails_on_docker % heroku container:release web -a rials-koumoriherokuを起動しブラウザで確認
terminal.rails_on_docker % heroku open -a rails-koumoriまとめ
前回のRails構築から、今回でデプロイまで完了できました。
- 投稿日:2021-01-11T02:52:17+09:00
Dockerを用いて掲示板を作った1
これは何
DockerとWebアプリ作成の勉強のため,この本の第3章をDockerコンテナの上で実装してみた際のメモ.
ファイル構成
$ tree . . ├── Dockerfile └── testbbs └── WEB-INF ├── classes ├── src │ ├── Message.java │ ├── PostBBS.java │ └── ShowBBS.java └── web.xml 4 directories, 5 filesDockerfile
DockerfileFROM tomcat:8.5.54-jdk11-adoptopenjdk-hotspot WORKDIR /usr/local/tomcat/webapps/ RUN mkdir -p ./testbbs COPY ./testbbs ./testbbs/ RUN javac -classpath $CATALINA_HOME/lib/servlet-api.jar -d ./testbbs/WEB-INF/classes ./testbbs/WEB-INF/src/*.javaJavaファイル
参考にしてる本と同じ.
Message.javaimport java.util.*; public class Message { public static ArrayList<Message> messageList = new ArrayList<Message>(); String title; String handle; String message; Date date; Message (String title, String handle, String message) { this.title = title; this.handle = handle; this.message = message; this.date = new Date(); } }PostBBS.javaimport java.io.*; import javax.servlet.http.*; public class PostBBS extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, IOException { request.setCharacterEncoding("UTF-8"); Message newMessage = new Message(request.getParameter("title"), request.getParameter("handle"), request.getParameter("message")); Message.messageList.add(0, newMessage); response.sendRedirect("/testbbs/ShowBBS"); } }ShowBBS.javaimport java.io.*; import javax.servlet.http.*; public class ShowBBS extends HttpServlet { private String espaceHTML (String src) { return src.replace ("&", "&").replace("<", "<") .replace (">", ">").replace ("\"", """) .replace ("'", "'"); } @Override public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>テスト掲示板</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>テスト掲示板</h1>"); out.println("<form action='/testbbs/PostBBS' method='post'>"); out.println("タイトル:<input type='text' name='title' size='60'>"); out.println("<br />"); out.println("ハンドル名:<input type='text' name='handle'>"); out.println("<br />"); out.println("<textarea name='message' rows='4' cols='60'></textarea>"); out.println("<br />"); out.println("<input type='submit' />"); out.println("</form>"); out.println("<hr />"); for (Message message: Message.messageList) { out.println("<p> 『" + espaceHTML(message.title) + "』 "); out.println(espaceHTML(message.handle) + " さん "); out.println(espaceHTML(message.date.toString()) + "</p>"); out.println("<p>"); out.println(espaceHTML(message.message).replace("\r\n", "<br />")); out.println("</p><hr />"); } out.println("</body>"); out.println("</html>"); } }web.xmlファイル
これも本と同じ.
web.xml<web-app xmlns="http://xmlns.jcp.org/xml/nx/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <servlet> <servlet-name>ShowBBS</servlet-name> <servlet-class>ShowBBS</servlet-class> </servlet> <servlet> <servlet-name>PostBBS</servlet-name> <servlet-class>PostBBS</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowBBS</servlet-name> <url-pattern>/ShowBBS</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>PostBBS</servlet-name> <url-pattern>/PostBBS</url-pattern> </servlet-mapping> </web-app>ビルドして実行
$ docker build -t henacat . Sending build context to Docker daemon 11.78kB Step 1/6 : FROM tomcat:8.5.54-jdk11-adoptopenjdk-hotspot ---> 66317f378ae0 Step 2/6 : RUN apt-get update && apt-get install -y wget ---> Using cache ---> 871dd39a71cc Step 3/6 : WORKDIR /usr/local/tomcat/webapps/ ---> Using cache ---> 19d29e246ff6 Step 4/6 : RUN mkdir -p ./testbbs ---> Using cache ---> c2765cdc59e3 Step 5/6 : COPY ./testbbs ./testbbs/ ---> Using cache ---> dbd09272e03b Step 6/6 : RUN javac -classpath $CATALINA_HOME/lib/servlet-api.jar -d ./testbbs/WEB-INF/classes ./testbbs/WEB-INF/src/*.java ---> Using cache ---> 41e02fb5b101 Successfully built 41e02fb5b101 Successfully tagged henacat:latest $ docker run -d -p 8080:8080 -it henacat $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 249799090cb1 henacat "catalina.sh run" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp elegant_ishizakahttp://localhost:8080/testbbs/ShowBBS にアクセスすると,ちゃんと掲示板が表示される.
ハマったこと
最初に使ったDockerイメージはtomcat:10.0.0-jdk11-adoptopenjdk-hotspot だったが,これだとコンパイルが通らなかった.
どうもサーブレットのためのパッケージが見つからないらしい.
クラスパスを間違えたかなと思い色々変えてみたがコンパイルエラーは直らず,tomcatの問題かと思いドキュメントを見にいくと,tomcat-10からどうもパッケージ名が変わったらしい.
tomcat-8 では,javax.servlet.httpだったのが,tomcat-10では,jakarta.servlet.httpとなっており,そりゃパッケージ見つからんってエラー吐かれるよなと.
と言うわけで,本と同じtomcat-8のDockerイメージを用いることで無事解決.参考文献
- 投稿日:2021-01-11T00:11:48+09:00
Docker(docker-compose)で、Laravelの環境を作成
初めに
もともと作られた方のものを参考(パクって)展開
※こちらの方のページを参考(パク…)こんな感じで作成
・php7.4 / mysql8 / nginx1.19 のイメージで作成
・sampleprojectというプロジェクト名で作成
・確認はDocker Desktop for Windows で確認フォルダ構成
laravel ├ docker-compose.yml ├ docker │ ├ php │ │ ├ php.ini │ │ └ Dockerfile │ └ nginx │ └ default.conf └ server各ファイル内容
docker-compose.ymlversion: '3' services: laravel_php: container_name: laravel_php build: ./docker/php volumes: - ./server:/var/www laravel_nginx: image: nginx:1.19 container_name: laravel_nginx ports: - 80:80 volumes: - ./server:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - laravel_php laravel_db: image: mysql:8.0 container_name: laravel_db environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: sampleproject MYSQL_USER: dbuser MYSQL_PASSWORD: dbpass TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306./docker/nginx/default.conf[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese"./docker/php/DockerfileFROM php:7.4-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update && apt-get -y upgrade RUN apt-get install -y zlib1g-dev && apt-get install -y libzip-dev RUN docker-php-ext-install pdo_mysql zip COPY --from=composer /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"./docker/nginx/default.confserver { index index.php index.html; server_name localhost; root /var/www/sampleproject/public; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass laravel_php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }実行コマンド
1.コンテナ構築
docker-compose up -d
2.Laravelプロジェクト作成
docker exec -ti laravel_php bashコンテナ内(バージョン6の作成コマンド)
composer create-project "laravel/laravel=6.*" sampleproject
プロジェクト作成後(コンテナ内)
cd sampleproject chmod -R 777 storage chmod -R 777 bootstrap/cache php artisan serve※localhostのみで接続できるはず
3.DB関連
.env の編集(プロジェクトフォルダ以下)
.envDB_CONNECTION=mysql DB_HOST=laravel_db DB_PORT=3306 DB_DATABASE=sampleproject DB_USERNAME=dbuser DB_PASSWORD=dbpass※composeのymlで記述した参考に
接続確認
php argisan migrate