Spring Boot + Spring Integration でいろいろ試してみる ( 番外編 )( Docker for Windows では host networking driver は使えない )
概要
記事一覧はこちらです。
Spring Boot + Spring Integration でいろいろ試してみる ( その30 )( Docker Compose でサーバを構築する、SMTP over SSL+POP over SSLサーバ編 ) において、おそらく Docker のネットワークかポートフォワードあたりが原因で POP over SSL のサーバを Docker で構築できなかったのですが、Docker の network には bridge 以外に host と呼ばれるものがあったことを思い出して試してみたが結論としては使えないことが分かった、という記事です。
Docker の Document の Use host networking を見れば The host networking driver only works on Linux hosts, and is not supported on Docker for Mac, Docker for Windows, or Docker EE for Windows Server.
と書いてあるので Docker for Windows で使えないことがすぐに分かるのですが、そんなことが最初から分かる訳もなく使えると思って頑張って調べたんですよね。。。
あとなぜ同じ Unix 系の OS のはずなのに Docker for Mac まで使えないのでしょうか? Linux、Mac では使えるが Windows では使えないというのがよく見かけるパターンだと思っていたので、正直これは以外でした。
参照したサイト・書籍
DockerのHost networking機能
https://deeeet.com/writing/2014/05/11/docker-host-networking/Docker compose, running containers in net:host
https://stackoverflow.com/questions/35960452/docker-compose-running-containers-in-nethostCompose file version 3 reference
https://docs.docker.com/compose/compose-file/Amazon ECS における Docker の基本
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.htmlUse host networking
https://docs.docker.com/network/host/
目次
手順
Docker for Windows で host networking driver を試してみる
docker network ls
コマンドを実行すると DRIVER が bridge, host, null の3つのネットワークが表示されますが、host のネットワークを使えばホストのネットワークインターフェースをそのまま使うと聞いて、もしかするとこれを使えば POP over SSL のサーバの件も解決するかな?と思い試してみることにしました。
ksbysample-eipapp-dockerserver プロジェクトの docker-compose.yml ではなく、D:\tmp ディレクトリを作成してその下に docker-compose.yml を新規作成し、以下の内容を記述します。
version: '3' services: nginx: image: nginx:latest container_name: nginx network_mode: host
- Docker Compose で host netwoking driver のネットワークを使用したい場合には
network_mode: host
を記述します。 - port は Docker Image 作成時に Dockerfile に EXPOSE で記述されたものが設定されます(docker-compose.yml で別のポート番号には変更できません)。
docker-compose up -d
コマンドを実行すると、エラーは出ずにコンテナが作成されます。
ただし netstat -an
コマンドを実行して LISTEN 状態にあるポート番号を見てみると 80番が表示されません。127.0.0.1 や別の IP アドレスで表示されているのを見落としている訳でもありません。
EXPOSE で書かれていたものが自動で使用可能になるのではないのかな?と思い、今度は docker run -d --name nginx --net host nginx
コマンドで試してみることにしました。
再度 netstat -an
コマンドを実行してみましたが、やっぱり 80番が表示されません。
docker ps
コマンドを実行してみると PORTS には何も表示されておらず、
docker inspect nginx
コマンドを実行して NetworkSettings の設定を見ても Ports には何も表示されませんでした。
ちなみに docker run -d -p 80:80 --name nginx nginx
コマンドでコンテナを作成すると、docker ps
、docker inspect nginx
コマンドは以下のように表示されて、ホストの 80番へのアクセスがコンテナの 80番にフォワードされていることが分かります。
AWS で EC2 インスタンスを立ち上げて試してみる
他の環境でどうなるのかを知りたかったので、AWS で EC2 インタンスを立ち上げて docker をインストールして host networking driver を試してみることにします。
EC2 インタンスは CloudFormation の YAML ファイルを作成して立ち上げることにします。D:\tmp の下に sample.yaml を作成して以下の内容を記述します。EC2 起動時に amazon-linux-extras install -y docker
で docker をインストールします。
AWSTemplateFormatVersion: 2010-09-09 Description: Single EC2 for docker host network test Parameters: ServiceName: Type: String Default: ksby Description: Service Name KeyPair: Type: AWS::EC2::KeyPair::KeyName Description: KeyPair Name Mappings: StackConfig: VPC: CIDR: 10.0.0.0/16 PublicSubnetA: CIDR: 10.0.0.0/24 AvailabilityZoneIndex: 1 # 東京リージョンでは ap-northeast-1b EC2: InstanceType: t3.nano ImageId: ami-0a2de1c3b415889d2 # Amazon Linux 2 AMI (HVM), SSD Volume Type Resources: ######################### # VPC ######################### VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !FindInMap [ StackConfig, VPC, CIDR ] EnableDnsHostnames: true Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "vpc" ] ] ######################### # Subnet ######################### PublicSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select - Fn::FindInMap: [ StackConfig, PublicSubnetA, AvailabilityZoneIndex ] - Fn::GetAZs: !Ref "AWS::Region" CidrBlock: !FindInMap [ StackConfig, PublicSubnetA, CIDR ] Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "a-subnet-public" ] ] ######################### # InternetGateway ######################### InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "inetgw" ] ] AttatchGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC ######################### # RouteTable ######################### PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "routetable-public" ] ] PublicRoute: Type: AWS::EC2::Route DependsOn: AttatchGateway Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway AssociatePublicRouteTableToPublicSubnetA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnetA ######################### # EC2 Web ######################### WebSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Join [ "-", [ !Ref ServiceName, "sg-web" ] ] GroupDescription: Web EC2 Security Group VpcId: !Ref VPC SecurityGroupIngress: - Description: ssh IpProtocol: tcp CidrIp: 0.0.0.0/0 FromPort: 22 ToPort: 22 - Description: http IpProtocol: tcp CidrIp: 0.0.0.0/0 FromPort: 80 ToPort: 80 Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "sg-web" ] ] EC2WebA: Type: AWS::EC2::Instance Properties: InstanceType: !FindInMap [ StackConfig, EC2, InstanceType ] KeyName: !Ref KeyPair ImageId: !FindInMap [ StackConfig, EC2, ImageId ] NetworkInterfaces: - AssociatePublicIpAddress: true DeviceIndex: 0 GroupSet: - !Ref WebSecurityGroup SubnetId: !Ref PublicSubnetA UserData: Fn::Base64: !Sub | #!/bin/bash yum update -y timedatectl status timedatectl set-timezone Asia/Tokyo localectl status localectl set-locale LANG=ja_JP.UTF-8 localectl set-keymap jp106 amazon-linux-extras install -y docker systemctl start docker systemctl enable docker usermod -a -G docker ec2-user Tags: - Key: Name Value: !Join [ "-", [ !Ref ServiceName, "a-web-ec2" ] ]
以下のコマンドを実行して、S3 へのアップロード ~ Stack 作成まで行います。
> aws s3 cp sample.yaml s3://<S3バケット名> > aws cloudformation validate-template \ --template-url https://s3-ap-northeast-1.amazonaws.com/<S3バケット名>/sample.yaml > aws cloudformation create-stack \ --stack-name <stack名> \ --template-url https://s3-ap-northeast-1.amazonaws.com/<S3バケット名>/sample.yaml \ --parameters ParameterKey=KeyPair,ParameterValue=<作成済のKeyPair名>
この後、以下のコマンドを何度も実行し、"StackStatus": "CREATE_COMPLETE"
が出力されるまで待ちます。
> aws cloudformation describe-stacks --stack-name <stack名>
AWS のコンソールから起動した EC2 インスタンスのパブリックDNSを確認した後、RLogin を使用して ssh でログインします。
docker version
コマンドを実行すると 18.06.1-ce
がインストールされていました。
docker コマンドは問題なく使えることが確認できたので、最初に netstat -an
コマンドで 80番ポートで LISTEN されていないことを確認してから、
docker run -d --name nginx --net host nginx
コマンドを実行します。
再度 netstat -an
コマンドを実行すると、今度は 80番ポートで LISTEN されていることが確認できました。
以下のコマンドを実行して起動した EC2 インスタンスを削除します。
> aws cloudformation delete-stack --stack-name <stack名>
そして、最後に。。。
Linux 上だと host networking driver は問題なく使えて Docker for Windows だと使えないらしいというのは何となく分かったのですが、再度 Web で検索してみたら Docker の Document の Use host networking を見つけて、やっぱり使えないことが分かったという次第です。
エラーメッセージが出て欲しい。。。
履歴
2018/12/16
初版発行。