かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

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 まで使えないのでしょうか? LinuxMac では使えるが Windows では使えないというのがよく見かけるパターンだと思っていたので、正直これは以外でした。

参照したサイト・書籍

  1. DockerのHost networking機能
    https://deeeet.com/writing/2014/05/11/docker-host-networking/

  2. Docker compose, running containers in net:host
    https://stackoverflow.com/questions/35960452/docker-compose-running-containers-in-nethost

  3. Compose file version 3 reference
    https://docs.docker.com/compose/compose-file/

  4. Amazon ECS における Docker の基本
    https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html

  5. Use host networking
    https://docs.docker.com/network/host/

目次

  1. Docker for Windows で host networking driver を試してみる
  2. AWS で EC2 インスタンスを立ち上げて試してみる
  3. そして、最後に。。。

手順

Docker for Windows で host networking driver を試してみる

docker network ls コマンドを実行すると DRIVER が bridge, host, null の3つのネットワークが表示されますが、host のネットワークを使えばホストのネットワークインターフェースをそのまま使うと聞いて、もしかするとこれを使えば POP over SSL のサーバの件も解決するかな?と思い試してみることにしました。

f:id:ksby:20181216145816p:plain

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 コマンドを実行すると、エラーは出ずにコンテナが作成されます。

f:id:ksby:20181216151947p:plain f:id:ksby:20181216152124p:plain

ただし netstat -an コマンドを実行して LISTEN 状態にあるポート番号を見てみると 80番が表示されません。127.0.0.1 や別の IP アドレスで表示されているのを見落としている訳でもありません。

f:id:ksby:20181216152308p:plain

EXPOSE で書かれていたものが自動で使用可能になるのではないのかな?と思い、今度は docker run -d --name nginx --net host nginx コマンドで試してみることにしました。

f:id:ksby:20181216153727p:plain

再度 netstat -an コマンドを実行してみましたが、やっぱり 80番が表示されません。

f:id:ksby:20181216153854p:plain

docker ps コマンドを実行してみると PORTS には何も表示されておらず、

f:id:ksby:20181216154321p:plain

docker inspect nginx コマンドを実行して NetworkSettings の設定を見ても Ports には何も表示されませんでした。

f:id:ksby:20181216154505p:plain

ちなみに docker run -d -p 80:80 --name nginx nginx コマンドでコンテナを作成すると、docker psdocker inspect nginx コマンドは以下のように表示されて、ホストの 80番へのアクセスがコンテナの 80番にフォワードされていることが分かります。

f:id:ksby:20181216154849p:plain f:id:ksby:20181216154957p:plain

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 がインストールされていました。

f:id:ksby:20181216161602p:plain

docker コマンドは問題なく使えることが確認できたので、最初に netstat -an コマンドで 80番ポートで LISTEN されていないことを確認してから、

f:id:ksby:20181216161820p:plain

docker run -d --name nginx --net host nginx コマンドを実行します。

f:id:ksby:20181216162014p:plain

再度 netstat -an コマンドを実行すると、今度は 80番ポートで LISTEN されていることが確認できました。

f:id:ksby:20181216162130p:plain

以下のコマンドを実行して起動した EC2 インスタンスを削除します。

> aws cloudformation delete-stack --stack-name <stack名>

そして、最後に。。。

Linux 上だと host networking driver は問題なく使えて Docker for Windows だと使えないらしいというのは何となく分かったのですが、再度 Web で検索してみたら Docker の Document の Use host networking を見つけて、やっぱり使えないことが分かったという次第です。

エラーメッセージが出て欲しい。。。

履歴

2018/12/16
初版発行。