takaya030の備忘録

PHP、Laravel、Docker などの話がメインです

gcloud で minikube をインストールする

ubuntu に gcloud で minikube をインストールする手順メモ
gcloud SDK と docker はインストール済みの想定

検証環境

Windows11 Home Edition (version 22H2)
VirtualBox 7.0.6
vagrant 2.3.4

# Docker Host OS
ubuntu 22.04.1 LTS

Docker version 20.10.21, build baeda1f
Google Cloud SDK 425.0.0

kubectl , minikube のインストール

$ gcloud components install kubectl
$ gcloud components install minikube

minikube の config 設定

$ minikube config set driver docker
$ minikube config set memory 2500

minikube の起動

$ minikube start

クラスターが作成された後、ノード確認

$ kubectl get nodes

NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   80s   v1.26.1

minikube の動作確認

テスト用のマニュフェストを作成

k8s-nginx-deployment.yaml

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

k8s-nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  name: my-lb
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
status:
  loadBalancer: {}

リソースを作成

$ kubectl apply -f k8s-nginx-deployment.yaml
$ kubectl apply -f k8s-nginx-service.yaml

リソースの確認

$ kubectl get pods

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-85996f8dbd-hmznb   1/1     Running   0          11m
nginx-deployment-85996f8dbd-zwbnh   1/1     Running   0          11m

$ kubectl get deployments

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           11m

$ kubectl get services

NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP          1h50m
my-lb        LoadBalancer   10.105.114.49   <pending>     8080:31196/TCP   11m

ブラウザでのアクセス

Windows からアクセスできるようにポートフォワードする

$ kubectl port-forward service/my-lb 8888:8080 --address=0.0.0.0
Forwarding from 0.0.0.0:8888 -> 80

ブラウザで http://192.168.33.10:8888 を開いて以下の画面が表示されるか確認
( 192.168.33.10minikube が動作している ubuntu の IP アドレス)

リソースの削除

$ kubectl delete -f k8s-nginx-service.yaml
$ kubectl delete -f k8s-nginx-deployment.yaml

minikube の終了

$ minikube stop

VirtualBox + Vagrant で構築した Docker 環境で動作している Laravel Sail の Xdebug の設定について

vagrant を使って VirtualBox に構築した Linux VM 上の Docker で Laravel Sail を動作させているときの Xdebug 設定の備忘録

検証環境

Windows10 Home Edition (version 22H2)
VirtualBox 6.1.40
vagrant 2.3.4

# Docker Host OS
ubuntu 22.04.1 LTS

Docker version 20.10.21, build baeda1f

発生した問題について

上記 Docker 環境で動作している Laravel Sail に WindowsVSCode から Dev Container でアタッチしてデバッグしようとしたところ、ブレークポイントを設定しても停止しなかった
調査したところ xdebug.client_host が不正だったため VSCodeXdebug からの通知が届いていなかったことが原因と判明した

xdebug.client_host の設定値ついて

xdebug.client_host には Xdebug クライアント (今回は WindowsVSCode) の IP アドレスを設定する必要がある
WSL2 では自動的に host-gateway に設定されるが VirtualBox ではそのような変数はないため明示的に指定する

コンテナから Windows へのアクセス

コンテナから Windows へのアクセスはデフォルトルートを通じて行うことが可能
デフォルトルートは ubuntu 上で ip r と入力することで確認できる

$ ip r
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15 metric 100
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100
10.0.2.3 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-3c28ac761546 proto kernel scope link src 172.18.0.1 linkdown
172.19.0.0/16 dev br-95a8cdd8ea38 proto kernel scope link src 172.19.0.1
192.168.33.0/24 dev enp0s8 proto kernel scope link src 192.168.33.10

1行目の default がデフォルトルートで、この場合 IP アドレス 10.0.2.2 を使って Windows へアクセス可能となる

Laravel Sail の Xdebug 設定

.env に下記内容を追加する
.env

SAIL_XDEBUG_MODE=develop,debug
SAIL_XDEBUG_CONFIG="client_host=10.0.2.2"

devcontainer.json に下記内容を追加する
.devcontainer/devcontainer.json

         "forwardPorts": [
                9003
         ]

.vscode フォルダに launch.json を作成する
.vscode/launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "stopOnEntry": true,
            "pathMappings": {
                "/var/www/html": "${workspaceFolder}"
            }
        }
    ]
}

コンテナイメージを再構築する

$ ./vendor/bin/sail build --no-cache

動作確認

コンテナを起動する

$ ./vendor/bin/sail up -d

VSCodeRemote SSHubuntu に接続した後、 Dev Container でコンテナにアタッチする

PHP Debug拡張機能をインストールする

Chrome でテストする場合は Xdebug helper エクステンションをインストールする

停止させたい箇所にブレイクポインタを設定する

デバッグ実行開始

Chromeデバッグ対象の URL を開く

Xdebug helper エクステンションのアイコンをクリックして Debug を選択

再度 URL を開くとブレイクポインタで停止することを確認する

参考サイト

readouble.com

xdebug.org

chrome.google.com

Vagrant で ubuntu 22.04 + Docker 開発環境

基本的に下記記事の手順で作成可能です

takaya030.hatenablog.com

Vagrantfile の内容が一部異なるので Vagrantfile のみ記載します
docker compose v1 は開発が停止しているためインストールしないようにしました
最新の docker では docker compose v2 がデフォルトで組み込まれています

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

  config.vm.box = "ubuntu/jammy64"

  config.vm.box_check_update = false

  config.vm.network "private_network", ip: "192.168.33.11"

  config.vm.provider "virtualbox" do |vb|
    # Display the VirtualBox GUI when booting the machine
    vb.gui = true
  
    # Customize the amount of memory on the VM:
    vb.memory = "2048"
  end

  config.vm.provision :docker

  config.vm.provision "shell", inline: <<-SHELL
    apt-get update -y

    gpasswd -a vagrant docker

    mkdir -p /etc/systemd/system/docker.service.d
    touch /etc/systemd/system/docker.service.d/options.conf
    echo '[Service]' > /etc/systemd/system/docker.service.d/options.conf
    echo 'ExecStart=' >> /etc/systemd/system/docker.service.d/options.conf
    echo 'ExecStart=/usr/bin/dockerd -H unix://' >> /etc/systemd/system/docker.service.d/options.conf

    touch /etc/docker/daemon.json
    echo '{"log-driver":"json-file","log-opts":{"max-size":"10m","max-file":"3"}}' > /etc/docker/daemon.json
    chmod 600 /etc/docker/daemon.json

    systemctl daemon-reload
    systemctl restart docker

    if [ ! -d "/home/vagrant/google-cloud-sdk" ]; then
      curl https://sdk.cloud.google.com > /tmp/install.sh
      sudo -u vagrant -i bash /tmp/install.sh --disable-prompts --install-dir=/home/vagrant
      sudo -u vagrant -i echo '# The next line updates PATH for the Google Cloud SDK.' >> /home/vagrant/.bashrc
      sudo -u vagrant -i echo 'if [ -f '\\''/home/vagrant/google-cloud-sdk/path.bash.inc'\\'' ]; then . '\\''/home/vagrant/google-cloud-sdk/path.bash.inc'\\''; fi' >> /home/vagrant/.bashrc
      sudo -u vagrant -i echo '# The next line enables shell command completion for gcloud.' >> /home/vagrant/.bashrc
      sudo -u vagrant -i echo 'if [ -f '\\''/home/vagrant/google-cloud-sdk/completion.bash.inc'\\'' ]; then . '\\''/home/vagrant/google-cloud-sdk/completion.bash.inc'\\''; fi' >> /home/vagrant/.bashrc
      rm -vf /tmp/install.sh
    fi
  SHELL
end

参考サイト

cloud.google.com

変更履歴

Laravel Sail インストール時に発生したエラーと解決方法

Laravel 公式サイトで紹介されていた方法で Laravel Sail をインストールしようとしたところ、エラーが発生して処理が中断したのでその解決方法の備忘録

検証環境

Windows10 Home Edition (version 21H2)
VirtualBox 6.1.32
vagrant 2.2.19

# Docker Host OS
ubuntu 20.04.3 LTS (Focal Fossa)

Docker version 20.10.8, build 3967b7d
docker-compose version 1.29.2, build 5becea4c

インストール

発生したエラーについて

下記コマンドでインストールしようとしたところ途中でエラーが発生して中断した

$ curl -s https://laravel.build/example-app | bash

エラーメッセージ

  [ErrorException]
  file_get_contents(/opt/example-app/vendor/symfony/error-handler/Resources/bin/patch-type-declarations): Failed to open stream: No such file or directory

インストールスクリプトの中で laravel new が使われていて、そこでエラーが発生していた

解決方法

composer を使ってインストールすることで解決した

$ docker pull composer
$ docker run --rm -it --volume $PWD:/app composer create-project laravel/laravel example-app
$ cd example-app
$ docker run --rm -it --volume $PWD:/app composer require laravel/sail --dev
$ docker run --rm -it --volume $PWD:/app composer php artisan sail:install --devcontainer

 Which services would you like to install? [mysql]:
  [0] mysql
  [1] pgsql
  [2] mariadb
  [3] redis
  [4] memcached
  [5] meilisearch
  [6] minio
  [7] mailhog
  [8] selenium
 > 0

docker build

発生したエラーについて

インストール完了後、 ./vendor/bin/sail up でコンテナを起動しようとしたところ下記エラーが発生

E: Problem executing scripts APT::Update::Post-Invoke 'rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true'
E: Sub-process returned an error code

Docker イメージのビルド中にエラーが発生していた

解決方法

デフォルトは context./vendor/laravel/sail/runtimes/8.1 が指定されていた
./vendor/laravel/sail/runtimes/8.0 に変更したところ正常にビルドされた

docker-compose.yml を変更

--- a/docker-compose.yml  Sat May 14 18:28:33 2022
+++ b/docker-compose.yml  Sat May 14 16:36:36 2022
@@ -3,11 +3,11 @@
 services:
     laravel.test:
         build:
-            context: ./vendor/laravel/sail/runtimes/8.1
+            context: ./vendor/laravel/sail/runtimes/8.0
             dockerfile: Dockerfile
             args:
                 WWWGROUP: '${WWWGROUP}'
-        image: sail-8.1/app
+        image: sail-8.0/app
         extra_hosts:
             - 'host.docker.internal:host-gateway'
         ports:

sail build で再ビルド

$ ./vendor/bin/sail build --no-cache

動作確認

sail up で起動

$ ./vendor/bin/sail up -d

http://<docker-host-ip>/ を web ブラウザでアクセスして以下の画面が表示されたら成功

参考サイト

laravel.com

zenn.dev

hub.docker.com

Python から MySQL に接続するサンプルプログラムを Docker で動かす

Python の mysqlclient を使ったサンプルプログラムを Docker で動かしたときの手順メモ

検証環境

Windows10 Home Edition (version 21H2)
VirtualBox 6.1.32
vagrant 2.2.19

# Docker Host OS
ubuntu 20.04.3 LTS (Focal Fossa)

Docker version 20.10.8, build 3967b7d
docker-compose version 1.29.2, build 5becea4c

ファイル構成

test
  │  Dockerfile
  │  docker-compose.yml
  │  example.py

Dockerfile

FROM python:3.9.10-slim-buster

RUN apt-get update && \
    apt-get -y install gcc libmariadb-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install mysqlclient

COPY ./example.py /app/example.py

WORKDIR /app

CMD python ./example.py

docker-compose.yml

version: "3.4"
services:
  app: 
    build:
      context: .
      dockerfile: ./Dockerfile
    image: "takaya030/pymysql"
    container_name: pymysqlclient
  db:
    image: mysql:5.7.37
    container_name: mysql_host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test_database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306

example.py

import MySQLdb
import time

# MySQLの起動を待つため
time.sleep(5)

connection = MySQLdb.connect(
    host='db',
    user='docker',
    passwd='docker',
    db='test_database')
cursor = connection.cursor()
 
cursor.execute("""SHOW CREATE DATABASE test_database;
""")

myresult = cursor.fetchall()

for row in myresult:
    print(row)

connection.close()

イメージのビルド

$ cd test

$ docker-compose build app

動作確認

Docker コンテナの起動

$ cd test

$ docker-compose up

正常動作していれば 5 秒後に下記のログが出力される

pymysqlclient | ('test_database', 'CREATE DATABASE `test_database` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */')

Ctrl + C でコンテナを終了させる

参考サイト

zenn.dev

qiita.com

www.geeksforgeeks.org

Laravel の artisan コマンドの引数バリデーションを行う

artisan コマンドの引数バリデーションを行うパッケージ cerbero/command-validator についてのメモ

検証環境

Windows10 Home Edition (version 21H1)

$ php --version
PHP 7.4.9 (cli) (built: Aug  4 2020 11:52:41) ( ZTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
    with Xdebug v2.8.1, Copyright (c) 2002-2019, by Derick Rethans

$ php artisan --version
Laravel Framework 8.73.0

cerbero/command-validator パッケージについて

リクエストに適用するバリデーションルールと同じ記述方法で artisan コマンドの引数のバリデーションが出来るパッケージ

github.com

インストール方法

$ composer require cerbero/command-validator

検証用 artisan コマンド

検証用として 2 つの数値を引数に与えるとその和を表示する artisan コマンドを作成する

$ php artisan make:command Addition

app/Console/Commands/Addition.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Addition extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'addition {num1} {num2}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Addition of two numbers';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info($this->argument('num1') + $this->argument('num2'));
        return Command::SUCCESS;
    }
}

動作確認

$ php artisan addition 1 2
3

$ php artisan addition 1 2.5
3.5

$ php artisan addition 1.25 2.17
3.42

# 引数に数値以外を与えるとエラーになるためバリデーションで防止したい
$ php artisan addition 1 abc

   ErrorException

  A non-numeric value encountered

検証用 artisan コマンド (バリデーションあり)

cerbero/command-validator を使って引数をバリデーションするように変更

app/Console/Commands/Addition.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Cerbero\CommandValidator\ValidatesInput;

class Addition extends Command
{
    use ValidatesInput;

    protected function rules()
    {
        return [
            'num1' => 'numeric',
            'num2' => 'numeric',
        ];
    }

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'addition {num1} {num2}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Addition of two numbers';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info($this->argument('num1') + $this->argument('num2'));
        return Command::SUCCESS;
    }
}

動作確認

$ php artisan addition 1 2
3

$ php artisan addition 1 2.5
3.5

$ php artisan addition 1.25 2.17
3.42

$ php artisan addition 1 abc


  The num2 must be a number.

バリデーションによって数値以外を受け付けないことを確認

Lumen8 で環境変数 APP_ENV に応じて .env ファイルを切り替える

検証環境

Windows10 Home Edition (version 21H1)

$ php --version
PHP 7.4.9 (cli) (built: Aug  4 2020 11:52:41) ( ZTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
    with Xdebug v2.8.1, Copyright (c) 2002-2019, by Derick Rethans

$ php artisan --version
Laravel Framework Lumen (8.2.4) (Laravel Components ^8.0)

Lumen8 の .env ファイルの読み込みについて

Lumen8 では bootstrap/app.php の先頭にある下記の部分で読み込んでいます

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__)
))->bootstrap();

Laravel\Lumen\Bootstrap\LoadEnvironmentVariables クラスのソースを確認するとコンストラクタで .envディレクトリだけでなくファイル名も指定可能になっていました

vendor/laravel/lumen-framework/src/Bootstrap/LoadEnvironmentVariables.php

<?php

namespace Laravel\Lumen\Bootstrap;

use Dotenv\Dotenv;
use Dotenv\Exception\InvalidFileException;
use Illuminate\Support\Env;
use Symfony\Component\Console\Output\ConsoleOutput;

class LoadEnvironmentVariables
{
    /**
     * The directory containing the environment file.
     *
     * @var string
     */
    protected $filePath;

    /**
     * The name of the environment file.
     *
     * @var string|null
     */
    protected $fileName;

    /**
     * Create a new loads environment variables instance.
     *
     * @param  string  $path
     * @param  string|null  $name
     * @return void
     */
    public function __construct($path, $name = null)
    {
        $this->filePath = $path;
        $this->fileName = $name;
    }

    /**
     * Setup the environment variables.
     *
     * If no environment file exists, we continue silently.
     *
     * @return void
     */
    public function bootstrap()
    {
        try {
            $this->createDotenv()->safeLoad();
        } catch (InvalidFileException $e) {
            $this->writeErrorAndDie([
                'The environment file is invalid!',
                $e->getMessage(),
            ]);
        }
    }

    /**
     * Create a Dotenv instance.
     *
     * @return \Dotenv\Dotenv
     */
    protected function createDotenv()
    {
        return Dotenv::create(
            Env::getRepository(),
            $this->filePath,
            $this->fileName
        );
    }

    /**
     * Write the error information to the screen and exit.
     *
     * @param  string[]  $errors
     * @return void
     */
    protected function writeErrorAndDie(array $errors)
    {
        $output = (new ConsoleOutput)->getErrorOutput();

        foreach ($errors as $error) {
            $output->writeln($error);
        }

        exit(1);
    }
}

環境変数 APP_ENV に応じて .env を切り替える変更

bootstrap/app.php を下記のように変更することで APP_ENV の値に応じて読み込む .env が切り替わります
例えば APP_ENV=prd のときは .env.prd が読み込まれます

bootstrap/app.php

$env = env('APP_ENV');
$env_file = '.env.'.$env;

if (!file_exists(dirname(__DIR__).'/'.$env_file)) {
    $env_file = null;
}

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__),
    $env_file
))->bootstrap();