2022/12/05

From Docker Virtual Network Connect To Solid MySQL Server

假設我們的 server 只有一台,PHP 環境為 docker container,而資料庫為實體機安裝,資料庫 3306 防火牆防堵不對外,但要允許從 Docker 環境內的服務存取,最簡單的方式就是防火牆讓 Docker 產生的 network interface 通過,下面我們來實做這件事。

今天示範環境為使用 Vagrant 起一台 Ubuntu jammy64,然後在裡面進行防火牆的測試。

sudo service ufw start
sudo ufw enable
sudo ufw allow ssh

記得開啟防火牆要先把 ssh 打開,不然就悲劇了,接著安裝 MySQL,docker 以及 docker compose 部分就麻煩自行安裝。

sudo apt install -y mariadb-server mariadb-client

安裝完畢後,我們來建立測試用資料庫以及帳號。

sudo mysql
create database laravel;
GRANT ALL PRIVILEGES ON `laravel`.* TO 'homestead'@'%' IDENTIFIED BY 'secret' WITH GRANT OPTION;

這邊權限開 % 沒關係,因為我們只會允許 docker network 指定的 network interface 進入而已。

docker-compose.yml
version: "3.9"

services:
  fpm:
    container_name: fpm
    build: .
    restart: always
    working_dir: /www
    extra_hosts:
      - "host.docker.internal:host-gateway"
    networks:
      - front_end
    volumes:
      - ./www/:/www

networks:
  front_end:
    driver_opts:
      com.docker.network.bridge.name: br-fpm
Dockerfile
FROM php:8.1-fpm

RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions @composer pdo_mysql mbstring exif pcntl bcmath gd

WORKDIR /www

這是要安裝 Laravel 的最小環境,我們今天只是要測試連線所以其他的設定就先不理會了。

sudo docker compose up -d

等 image build 完以及 service 起來以後,我們來利用指令安裝一個 Laravel 的環境。

sudo docker compose exec fpm composer create-project laravel/laravel .

接著我們打開 .env 檔案設定資料庫連線內容。

DB_CONNECTION=mysql
DB_HOST=host.docker.internal
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=homestead
DB_PASSWORD=secret

這時來測試一下連線。

sudo docker compose exec fpm php artisan migrate

因為防火牆擋住了,所以 connection 會 hang 住,最終失敗,接著來開始防火牆設定。

sudo ufw allow in on br-fpm to any port 3306

接著再執行一次 migrate 的指令。

sudo docker compose exec fpm php artisan migrate

   INFO  Preparing database.

  Creating migration table ............................................................................................................... 10ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table .................................................................................................... 9ms DONE
  2014_10_12_100000_create_password_resets_table .......................................................................................... 2ms DONE
  2019_08_19_000000_create_failed_jobs_table .............................................................................................. 3ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ................................................................................... 4ms DONE

可以看到 migration 順利成功了,如果發生 connection refuse 的錯誤的話,記得把 MySQL 的 bind-address 設定為 0.0.0.0

iptable 的話用下方的指令應可達到一樣的效果。

iptables -A INPUT -i br-fpm -p tcp --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP