Help us understand the problem. What is going on with this article?

Dockerでポートフォワーディング解説

More than 1 year has passed since last update.

ポートフォワーディングとは

ポートフォワーディング:
インターネットから特定のポート番号宛にパケットが届いたときに、あらかじめ 設定しておいたLAN側の機器にパケットを転送する機能です。

※引用元:https://www.itbook.info/study/nat6.html

  • ポートの紐付けというイメージ

  • 仮想環境で開発をする場合、このポートフォワーディングが必須となると思いますが、今回はDockerを例に少し解説します。
    ※今回はポートフォワーディングについてDockerをもとに話すため、Dockerについては解説しません。

Dockerイメージ

  • 概要
    • スクリプト
      • Go言語で作成
    • Dockerfile
      • golangのベースイメージを使用
  • 挙動
    • コンテナを実行したら「start server」と出力
    • HTTPリクエストに対し、リクエスト側に「Hello Docker!!」と出力、リクエストを受けた側には「received request」と出力
    • 「8080」のポートを解放
sample.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // クライアントからリクエストを受けた場合
        log.Println("received request")
        // HTTPリクエストを受けた場合
        fmt.Fprintf(w, "Hello Docker!!")
    })

    log.Println("start server")
    server := &http.Server{Addr: ":8080"}
    if err := server.ListenAndServe(); err != nil {
        log.Println(err)
    }
}
Dockerfile
FROM golang:1.9
RUN mkdir /echo
COPY main.go /echo
CMD ["go", "run", "/echo/main.go"]

Dockerイメージのビルド

  • イメージをビルドする
$docker image build -t sample:latest .
Sending build context to Docker daemon   5.12kB
Step 1/4 : FROM golang:1.9
1.9: Pulling from library/golang
55cbf04beb70: Pull complete 
1607093a898c: Pull complete 
9a8ea045c926: Pull complete 
d4eee24d4dac: Pull complete 
9c35c9787a2f: Pull complete 
8b376bbb244f: Pull complete 
0d4eafcc732a: Pull complete 
186b06a99029: Pull complete 
Digest: sha256:8b5968585131604a92af02f5690713efadf029cc8dad53f79280b87a80eb1354
Status: Downloaded newer image for golang:1.9
 ---> ef89ef5c42a9
Step 2/4 : RUN mkdir /echo
 ---> Running in 99e306a53ced
Removing intermediate container 99e306a53ced
 ---> f9b0ec578390
Step 3/4 : COPY main.go /echo
 ---> b71ab1e040bd
Step 4/4 : CMD ["go", "run", "/echo/main.go"]
 ---> Running in fff606860921
Removing intermediate container fff606860921
 ---> 2c9096d1911b
Successfully built 2c9096d1911b
Successfully tagged sample:latest
$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
sample               latest              2c9096d1911b        16 seconds ago      750MB

Dockerコンテナの実行

  • バックグラウンドでコンテナを実行
  • -pオプション
    • ポートフォワーディングの設定
      • 左側(9000)がホストのポートで、右側(8080)がコンテナのポート
        • 上記でGo言語で書かれたスクリプトを説明しましたが、8080のみ解放されている為、必然的にコンテナ側のポートは8080になります。

※ホスト側とコンテナ側のポートを分けたのは、アクセス時にどちらからアクセスしたのか、を分かりやすくする為です。

$ docker run -d -p 9000:8080 2c9096d1911b
5e3f8c5181b99c72002fe1917044c38426132c863350c47db828909294823b0b
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
5e3f8c5181b9        2c9096d1911b        "go run /echo/main.go"   4 seconds ago       Up 3 seconds        0.0.0.0:9000->8080/tcp   objective_leavitt 

HTTPアクセス

  • コンテナに対してcurlでアクセス
$ curl http://localhost:9000
Hello Docker!!

ここまでを図解

  • Dockerfileを元にbuildしてイメージを作成
  • イメージをrunしてコンテナを立ち上げる
    • コンテナのステータスは実行中

スクリーンショット 2019-02-16 13.22.42.png

  • コンテナ実行時(run)、-pオプションでポートフォワーディングの設定をする
    • イメージは下図のように、コンテナに穴を開けるイメージ
      • 8080のポートを解放し、9000ポートを紐づける事で、アクセスが可能な状態した

スクリーンショット 2019-02-16 13.40.58.png

  • curlで9000ポートでHTTPリクエストを送る
    • 「Hello Docker!!」とレスポンスが返ってくる

スクリーンショット 2019-02-16 14.00.10.png

まとめ

こんな感じでポートフォワーディングでポートの紐付けを行ってあげる事で、仮想環境に対してもアクセスできるようになるわけです。

余談ですが、-pオプションでポートフォワーディングで設定をしましたが、もしホスト側の設定をしない場合どうなると思いますか?

// こんな感じでコンテナ側のポートしか設定しない場合です
$ docker run -d -p 8080 abcdefg

まぁ知ってる方多いと思いますが、よしなに空いているポート番号を割り振って、そのポート番号と紐付けを行ってくれます。

上記を実行した後にdocker psをして、PORTSを確認すると、どのポートと紐づけられているか、が分かりますので、試したことの無い方はぜひお試し下さい。

おまけ

Twitterやってます!外部のエンジニアの方ともどんどん繋がりたいと考えていますので、是非フォローして頂ければと思います!@Tatsuo96
ブログ始めました!
https://note.mu/tatsuo_iriyama

tatsuo-iriyama
Web Engineer|96'|高卒|前職:溶接工|2019-01〜ユアマイスター株式会社|
yourmystar
サービス産業のIT化プラットフォーム「ユアマイスター」と大切なものをもっと大切にするメディア「ユアマイスター スタイル」を運営するスタートアップです。
http://corp.yourmystar.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした