##ポートフォワーディングとは
ポートフォワーディング:
インターネットから特定のポート番号宛にパケットが届いたときに、あらかじめ 設定しておいたLAN側の機器にパケットを転送する機能です。
※引用元:https://www.itbook.info/study/nat6.html
-
ポートの紐付けというイメージ
-
仮想環境で開発をする場合、このポートフォワーディングが必須となると思いますが、今回はDockerを例に少し解説します。
※今回はポートフォワーディングについてDockerをもとに話すため、Dockerについては解説しません。
##Dockerイメージ
- 概要
-
スクリプト
- Go言語で作成
-
Dockerfile
- golangのベースイメージを使用
-
スクリプト
- 挙動
- コンテナを実行したら「start server」と出力
- HTTPリクエストに対し、リクエスト側に「Hello Docker!!」と出力、リクエストを受けた側には「received request」と出力
- 「8080」のポートを解放
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)
}
}
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になります。
- 左側(9000)がホストのポートで、右側(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してコンテナを立ち上げる
- コンテナのステータスは実行中
- コンテナ実行時(run)、-pオプションでポートフォワーディングの設定をする
- イメージは下図のように、コンテナに穴を開けるイメージ
- 8080のポートを解放し、9000ポートを紐づける事で、アクセスが可能な状態した
- イメージは下図のように、コンテナに穴を開けるイメージ
- curlで9000ポートでHTTPリクエストを送る
- 「Hello Docker!!」とレスポンスが返ってくる
##まとめ
こんな感じでポートフォワーディングでポートの紐付けを行ってあげる事で、仮想環境に対してもアクセスできるようになるわけです。
余談ですが、-pオプションでポートフォワーディングで設定をしましたが、もしホスト側の設定をしない場合どうなると思いますか?
// こんな感じでコンテナ側のポートしか設定しない場合です
$ docker run -d -p 8080 abcdefg
まぁ知ってる方多いと思いますが、よしなに空いているポート番号を割り振って、そのポート番号と紐付けを行ってくれます。
上記を実行した後にdocker psをして、PORTSを確認すると、どのポートと紐づけられているか、が分かりますので、試したことの無い方はぜひお試し下さい。