LoginSignup
1
1

dockerのポート設定は必要なものだけにする

Last updated at Posted at 2023-12-23

はじめに

上の記事を読んでいて(実はしっかり読んでないけど)、疑問に思ったことがあります。ファイヤーウォール以前に、

そもそも本番サーバーでデータベースをホストから使える設定にしてるのがおかしくない?
ってことです。

docker hubの公式イメージだと...

例えばpostgresの公式イメージでは

docker-compose.yml
version: '3.1'
services:
  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: example

こんな感じのdocker-compose.ymlが公開されています。ポートの公開してませんよね?

公式にあるyamlにサービスを追加する

dockerのデフォルトのネットワークはbridgeという名のnat(IPマスカレードがnatです)なので、公開しない限りホストからもアクセスできませんが、bridgeなので他のサービスからは普通に開いています。例えば上のdocker-compose.ymlをこちらの記事を参考に編集して以下のように変えたとしましょう。

docker-compose.yml
version: '3.7'
services:
  db:
    image: postgres
    restart: always
    volumes:
      - ./data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: example
  app:
    image: node:lts
    working_dir: /home/app
    tty: true
    ports: 
    - '3000:3000'
    volumes:
      - ./:/home/app
    depends_on:
      - db
    command: >
      bash -c "npm install &&
      npm install nodemon -g &&
      nodemon index.js"

これもnode用のポート3000しか公開しておらず、postgresは公開していません。

細かいところを言うと少しだけいじっています。

  • 不要ボリュームを消すのが面倒なのでpostgres側volume設定を追加
  • app側にdepends_onを追加して、初回起動時コケにくくした

アプリを適当に用意する

先の記事を丸パクリ参考にして作成します。

$ docker compose run --rm app bash -c 'npm init -y;npm install express pg'
$ docker compose down
index.js
'use strict';

const express = require('express');
const PORT = 3000;
const HOST = '0.0.0.0';
const app = express();

const {Pool} = require('pg');
const pool = new Pool({
  user: 'postgres',
  host: 'db',
  database: 'postgres',
  password: 'example',
  port: 5432,
});

app.get('/', async(req, res) => {
  const {rows} = await pool.query('select version()');
  res.send(rows);
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

postgresに接続してバージョンだけ表示するアプリです。

確認してみる

まずは起動してみます。

$ docker compose up -d

(初回はdatabase作成などの都合によりnodeの方が先に起動してしまうと失敗します)

次にホスト(dockerの外)からアクセスしてみます。

$ wget -O - 'http://localhost:3000' | cat
--2023-12-23 22:49:41--  http://localhost:3000/
localhost (localhost) をDNSに問いあわせています... ::1, 127.0.0.1
localhost (localhost)|::1|:3000 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 131 [application/json]
‘STDOUT’ に保存中

-                                               100%[====================================================================================================>]     131  --.-KB/s    in 0s      
[{"version":"PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit"}]
2023-12-23 22:49:41 (21.3 MB/s) - stdout へ出力完了 [131/131]

$ 

後ろにパイプを噛ませているのはapplication/jsonというContent-Typeが指定されているからです。ないとwgetがバイナリと判断して端末上に出力してくれません。普通にブラウザで見ても大丈夫です。

見れば分かるとおり、ちゃんとpostgresのバージョン情報をnodeアプリ側で表示出来ています。

結論

postgresのポート設定は公開しなくていいのです。

ポートの公開はあくまで開発時ツールなどを使ってホストから直接見たいときに行うサポート的なものなんです。なので…

本番サーバーで不要なポートをdockerコンテナの外に公開しちゃいけません

dockerがiptablesをいじることを知らなくても初心者ならそこまで怒られないかもしれませんが、不要なポートを公開してればあなたの評価は確実に下がると思います。逆に言えば不要なポートの公開さえしていなければ、何も問題など起きなかったわけです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1