見出し画像

EC2 + SSH + dockerでvimのxdebug(vdebug)

さて、前回より内容が濃くなってくぞ。

前回使ったサーバーの掃除

apacheとかが起動しているので掃除する。新たに起動する人はここは見る必要はない

sudo apt purge libapache2-mod-php

まあ簡単に作ったり壊したりできるのがEC2のいいところではある。

dockerとdocker-composeを入れる

まあ正確にはdocker-composeは入れなくてもいいかもしれないけどまあなんとなくこれを入れれば一式入るので。

$ sudo apt install docker-compose

作業準備

で、今sshログインしてhomeにいるとする。debianのEC2のAMIはadminになっているから、そのユーザーがそうなってるのかしら?

admin@ip-172-31-46-247:~$ pwd
/home/admin

dockerを使う場合はこのユーザーをdocker groupに入れる

$ sudo adduser admin docker
Adding user `admin' to group `docker' ...
Done.

簡単なのは一度ログアウトしてsshを繋ぎ直す事だ

$ id
uid=1000(admin) gid=1000(admin) groups=1000(admin),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),110(docker)

見切れてるけど、ここでdockerグループに入ってるのを確認する必要がある。

workingディレクトリの作成

まあ、正直何でもいい

$ mkdir vdebug-test
$ cd vdebug-test/

とした

とりあえず簡単なDockerfileの用意

apache2でもいいんだけど、まあせっかくだしnginxにします?今回は

Dockerfile を作成する

FROM php:8-fpm

# Nginxのインストール
RUN apt-get update && apt-get install -y nginx 

# ワークディレクトリの設定
WORKDIR /var/www/html

# PHP-FPMとNginxを前面で実行
CMD php-fpm -D && nginx -g "daemon off;"

とまあこんな感じにしよう。そしたら

docker build -t vdebug-test .

とかやるとvdebug-test とかいう名前でイメージができる。

シンプルにこれを起動してみよう。

docker run -d -p 80:80 -v $(pwd):/var/www/html vdebug-test

するとこんな感じになるはずだ

$ docker run -d -p 80:80 -v $(pwd):/var/www/html vdebug-test
f386acab14859ebe0e1d75189607655af8db2749c7711f338a3f97441495470d

こんな感じでそれぞれプロセスidを出しながら起動しているはず。当該ホストにhttpで接続してみよう。

未設定なので、まあこんなもんだろう。

nginx.confをキめる

まずさっきのdockerを止める。idを指定するといい

$ docker stop f38

3文字くらいでいい。コピペしてももちろんよいが。

最低限のnginx.confを作る

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    server {
        listen 80 default_server;
        root /var/www/html/public;

        index index.php;
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }

        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
}

これをDockerに食わせる設定をする

更新されたDockerfile 

FROM php:8-fpm

# Nginxのインストール
RUN apt-get update && apt-get install -y nginx
COPY nginx.conf /etc/nginx/nginx.conf

# ワークディレクトリの設定
WORKDIR /var/www/html

# PHP-FPMとNginxを前面で実行
CMD php-fpm -D && nginx -g "daemon off;"

再構築している。

docker build -t vdebug-test . --no-cache

再度run

$ docker run -d -p 80:80 -v $(pwd):/var/www/html vdebug-test
711894d328cccfe9597e2b54abf824618c719156dc4e3778ea037718a565eee7

すると今度は


404

404 not foundになったことで設定が変更されているのがわかる。これはnginx.conf

root /var/www/html/public;

この設定がキいていて、かつDockerfile の

WORKDIR /var/www/html

これが設定されているので、host側にpublicディレクトリを作ればいいという事が何となくわかる。というのも

docker run -d -p 80:80 -v $(pwd):/var/www/html vdebug-test

このコマンドでPWD を /var/www/html にマウントしてるからね、というわけで

$ mkdir public
$ echo "<?php phpinfo();" > public/index.php

などというワンライナーを書いてみれば


こうなる。ちなみに

FROM php:8-fpm

とか適当な指定をしたので8.3が勝手に入ってるけど、バージョンをちゃんと書いたらそれが入るので8.2の方がよければphp:8.2-fpmになる。まあいいや。新しいのが使える分には困らんのだがねえ…(切実)

xdebugの設定

xdebugの設定はまだなされていない。ここではどういう風に行ったらいいのかを確認するためにまずdocker containerに入ってみよう。

docker exec -it 711894d328cc bash

こんな感じで入る。psのidがわからんくなったらdocker psしてね

そうすると

root@711894d328cc:/var/www/html#

みたいなdockerの中で起動されたbashが使えるようになる。

xdebugを手動で設定してみよう

php系のdockerイメージはかなりカスタムされておりosのパッケージを使う事ができないので用意されてるpeclを使う

# type pecl
pecl is /usr/local/bin/pecl

というわけでこれを使ってinstallする

# pecl install xdebug

するとビルドがはじまりこんな風味で終わるだろう

Installing '/usr/local/lib/php/extensions/no-debug-non-zts-20230831/xdebug.so'
install ok: channel://pecl.php.net/xdebug-3.3.2
configuration option "php_ini" is not set to php.ini location
You should add "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20230831/xdebug.so" to php.ini

ここで警告されているようにphp.iniに設定していないから

zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20230831/xdebug.so

php.iniに書けよといっている。ただまあこれはもうちょっと横着ができてdockerのphpの設定で

Scan this dir for additional .ini files	/usr/local/etc/php/conf.d

とあるので、ここにxdebugの設定を置けばよさそうだ。しかし実際にはモジュールを読みこむためにnginxに再起動をかけるとdockerが終わっちゃうので、これらの流れを踏まえてDockerfileで行う必要がある。ではDockerfileを改善する前にxdebug.ini を作る

xdebug.ini

まあ実際にはもっと単純に書ける

zend_extension=xdebug.so

この一行だけ書いとけばいい

そしてDockerfileを更新する

FROM php:8-fpm

# Nginxのインストール
RUN apt-get update && apt-get install -y nginx && pecl install xdebug
COPY nginx.conf /etc/nginx/nginx.conf

COPY xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini

# ワークディレクトリの設定
WORKDIR /var/www/html

# PHP-FPMとNginxを前面で実行
CMD php-fpm -D && nginx -g "daemon off;"

として、先程のbuild、docker停止、開始とかやって何とかこれをloadすると


が出てくるだろう。前回は3.2だったけどこっちは3.3.2だね

xdebugの設定微調整

これはxdebug.iniに書いたらいい。

zend_extension=xdebug.so

[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
;xdebug.client_host=
xdebug.client_port=9003

client_hostは設定しない。ここでもbuildからの再起動が必要だ。もういちいちコマンドは書きませんよ。

起動すれば

まあちゃんとこの辺が切り替わることでしょう。

さて、xdebugの仕様を再度確認する

xdebugつのは

  • ブラウザーのリクエストがきたら(start_with_request = yesの場合)

  • 裏で指定されたclientのhostとportにデバッグ情報をぶん投げる

という動きをする。従ってdocker containerの中でコード書いてりゃワケないんだけど今回のような構成の場合はdockerのhostからコード書いてコンテナは単に動かすだけにしたいやんか。そういう場合はcontainerからhostと通信しないといけない。

まずcontainerからhostに通信できるようにする

これに関してはdocker.host.internal ってのがwindowsとかのdocker desktopでは使えるんだけど素のlinux dockerだとうまいこといかなかったりするのではあるが、とりあえず一度dockerをstopして、いちいち見ていこう

$ docker ps
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                                                                                    NAMES
bc4d062148d7   vdebug-test   "docker-php-entrypoi…"   6 minutes ago   Up 6 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:9003->9003/tcp, :::9003->9003/tcp, 9000/tcp   goofy_aryabhata
$ docker stop bc4

さて、ここで今までは

$ docker run -d -p 80:80 -v $(pwd):/var/www/html vdebug-test

なるコマンドを使っていたが、これをちょっと拡張して

docker run -d -p 80:80 -p 9003:9003 --add-host=host.docker.internal:host-gateway -v $(pwd):/var/www/html vdebug-test

で起動する。ここで一応確認のために中に入る

$ docker exec -it 062 bash
root@062abc93277a:/var/www/html#

そしたら/etc/hosts を確認しよう、すると

# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.1      host.docker.internal
172.17.0.2      062abc93277a

このようにhost.docker.internal の値が書き込まれているので、これで解決できるってわけだ。iputils-ping とか入れて確認してみてもいい

# apt install iputils-ping
# ping host.docker.internal
PING host.docker.internal (172.17.0.1) 56(84) bytes of data.
64 bytes from host.docker.internal (172.17.0.1): icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from host.docker.internal (172.17.0.1):

この段階でcontainerを抜けてstopする

root@062abc93277a:/var/www/html# exit
exit
$ docker stop 062

そしてxdebug.ini に設定値を書き込もう

[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

そしてビルドして起動して値を見る

vimで待ち受ける前にnetcatとかで待ち受けてみる

これはhost側、つまりvimを起動する側でやる。

sudo apt install netcat-openbsd

そうしたら9003番で待ち受けてみる

nc -l -p 9003

そうしたら、こんな具合でxmlが飛んでくるのが見えるかと思う

こうなってれば通信できており、xdebugを使う準備は完成しているから。あとはvdebugを起動するだけだ。逆にこれが見えない場合は通信できてないので一生成功しない。

vdebugしてみる

ではpublic/test.php にこんな感じで書いてみよう。

<?php
$a = 1;
$b = 2;
echo $a + $b. "\n";

基本的にxdebugとhostが通信できているので成功するはずだ。echoの所にbreakpointを追いてF5を押したよ

ではブラウザーでtest.phpにアクセスしてみよう。すると…

このような形で微妙に動きがあやしくなるはずだ。これはpath_mappingがちゃんとおこなえていない時になる。

ここでvimrcにこの設定を足す

let g:vdebug_options['path_maps'] = { '/var/www/html': '/home/admin/vdebug-test' }

すると

このようにちゃんとつかまえられるであろう。

しかし固有の設定をいちいち.vimrcに書いて切り換えるのが面倒くさい

これに関しては後日考えてみるとして今回はここまで。


この記事が気に入ったらサポートをしてみませんか?