GeekFactory

int128.hatenablog.com

NGINX Ingressで複数ドメインを1つのALBに集約する

AWSKubernetesを利用する場合、Ingress Controllerの選択肢にはaws-alb-ingress-controllerkube-ingress-aws-controllernginx-ingressなどがあります。

aws-alb-ingress-controllerやkube-ingress-aws-controllerではKubernetesのレイヤでALBを管理できる反面、シンプルな構成しかサポートされていません。例えば、aws-alb-ingress-controllerでは複数のIngressを1つにALBに集約することができません。また、両者ともインターネットとVPC内部に同一のFQDNでサービスを提供する構成を実現できません*1

本稿では、nginx-ingressを利用して複数ドメインを1つのALBに集約する構成を説明します。ここでは簡単のためワイルドカードドメインで説明しますが、同じ方法で複数のドメインを集約することも可能です。

設計

具体的には、以下のようにKubernetesリソースとAWSリソースを構成します。

上記にInternal ALBやRoute53 Private Hosted Zoneを追加するとインターネットとVPC内部に同一のFQDNでサービスを提供する構成を実現できます。

kopsでKubernetesを管理する場合の構成を下図に示します。EKSの場合もおおよそ同じになるはずです。

f:id:int128:20180718102825p:plain

例えば、Route53やALBのワイルドカードドメイン*.dev.example.com とした場合、www.dev.example.com に対するトラフィックは以下の流れで転送されます。

  1. Route53が www.dev.example.com に対応するALBのAレコードを返す。
  2. ALB Listenerは *.dev.example.comSSL証明書を利用してネゴシエーションを行う。
  3. ALB Target GroupはKubernetes WorkerのNodePortにトラフィックを転送する。
  4. nginx-ingressはHostヘッダとパスでトラフィックの転送先を決定する。例の場合は www.dev.example.com に対応するServiceにトラフィックを転送する。
  5. アプリケーションのPodにトラフィックが到達する。

もし、Hostヘッダとパスに対応するServiceが見つからない場合、nginx-ingressはDefault Backendにトラフィックを転送します。

Helmfile, kops, Terraformによる構成管理

nginx-ingressHelm chartを利用すると簡単に導入できます。Helmの構成管理にHelmfileを利用する場合は以下のようになります。メモリサイズやタイムアウトなどはアプリケーションの特性に合わせて修正してください。

releases:
  - name: nginx-ingress
    namespace: kube-system
    chart: stable/nginx-ingress
    values:
      - rbac:
          create: true
        controller:
          replicaCount: 2
          resources:
            limits:
              memory: 128Mi
            requests:
              memory: 128Mi
          service:
            type: NodePort
            nodePorts:
              http: 30080
          config:
            proxy-read-timeout: "180"
            proxy-send-timeout: "180"
            # Large request header (e.g. OIDC proxy)
            proxy-buffer-size: "64k"
            # Large request body (e.g. file upload)
            proxy-body-size: "512m"
            server-tokens: "false"
        defaultBackend:
          replicaCount: 2
          resources:
            limits:
              memory: 16Mi
            requests:
              memory: 16Mi

kopsでKubernetesを管理する場合、kopsとTerraformが管理するリソースはそれぞれ下表のようになります。

  • kopsが管理するリソース
    • VPC, Subnet, Route Table, Internet Gateway
    • Auto Scaling Group (master), Security Group (API), Security Group (SSH)
    • Auto Scaling Group (node), Security Group (SSH)
  • Terraformが管理するリソース
    • ALB, Listener, Target Group, Security Group (HTTPS)
    • Route53 Hosted Zone, Route53 RecordSet
    • ACM Certificate

Terraformからkopsのリソースを参照するにはNameタグ、もしくはKubernetesクラスタのタグ(kubernetes.io/cluster/name=owned)を利用できます。例えば、Instance Group nodes-ap-northeast-1a に対応するAuto Scaling Groupを参照するには以下のようにNameタグを利用します。

# Auto Scaling Group for the Kubernetes nodes
data "aws_autoscaling_groups" "kops_nodes" {
  filter {
    name   = "key"
    values = ["Name"]
  }

  filter {
    name   = "value"
    values = ["${formatlist("nodes-%s.%s", data.aws_availability_zones.available.names, var.kubernetes_cluster_name)}"]
  }
}

Helmfile, kops, Terraformによる実装をGitHubint128/kops-terraform-starter に置いているので参考にしてください。

評価

この構成は小規模で中央集権的な管理を行うクラスタに向いています。多数のチームが1つのクラスタを共用する場合は、Kubernetesのレイヤで各チームが自律的にALBを管理する方がスムーズに運用できるでしょう。

この構成にはいくつかの課題があります。

まず、すべてのトラフィックがNodePortのNGINXを経由してアプリケーションのPodに到達するため、レイテンシが大きくなります。ALBからアプリケーションのNodePortに直接転送する方式(aws-alb-ingress-controller)の方がレイテンシは小さくなると考えられます。

また、高負荷やメモリリークなどでNGINXに障害が発生するとすべてのトラフィックに影響します。トラフィックが増えた場合やWebSocketを扱う場合の知見はPain(less) NGINX Ingressが非常に参考になります。

複数のInstance Groupや複数のALBを扱いたい場合はTerraformの記述が複雑になります。その場合はkube-ingress-aws-controllerを使うとよいでしょう。EC2とALBの対応を自動的に管理してくれます。また、ALBとSecurity Groupの対応はタグで管理できます。

See Also

*1:kube-ingress-aws-controllerでは同じルールのIngressをinternet-facing/internalに対して重複定義することで可能です。 https://github.com/zalando-incubator/kube-ingress-aws-controller/issues/114

HackMDでGitLab認証を利用する

HackMDは同時編集が便利なコラボレーションツールです。HackMDは認証なしでも十分に使えますが、外部認証を利用するとさらに便利に使えます。公式リポジトリのドキュメントによると、HackMDは以下の認証方式に対応しています。

本稿ではGitLab認証を利用する方法を説明します。

HackMDのデプロイ

HackMDをKubernetesクラスタにデプロイします。公式の stable/hackmd Helm chart を利用すると簡単にデプロイできます。

ここでは構成管理にHelmfileを利用します。

# helmfile.yaml
releases:
  - name: hackmd
    namespace: devops
    chart: stable/hackmd
    values:
      - ingress:
          enabled: true
          hosts:
            - hackmd.{{ requiredEnv "kubernetes_ingress_domain" }}
        resources:
          limits:
            memory: 256Mi
          requests:
            memory: 256Mi
        persistence:
          size: 50Gi
        postgresql:
          install: false
          postgresHost: {{ requiredEnv "database_host" }}
          postgresDatabase: hackmd
          postgresUser: hackmd
          postgresPassword: hackmd

環境変数kubernetes_ingress_domaindatabase_host は環境に合わせて設定してください。

export kubernetes_ingress_domain=dev.example.com
export database_host=xxx.xxx..ap-northeast-1.rds.amazonaws.com
helmfile sync

https://hackmd.dev.example.com を開いてHackMDの画面が表示されたら成功です。

これでKubernetesクラスタにHackMDがデプロイされました。

GitLabの設定

GitLabの管理画面で Applications を開き、New application ボタンをクリックします。以下の項目を入力します。

  • Name: hackmd
  • Redirect URI: https://hackmd.dev.example.com/auth/gitlab/callback
  • Trusted: YES
  • Scopes: api

System OAuth applicationsに hackmd が追加されたことを確認します。

HackMDの設定

HackMDでGitLab認証を設定するには以下の環境変数を設定します。

名前 設定値
HMD_DOMAIN HackMDのドメイン hackmd.dev.example.com
HMD_URL_ADDPORT HackMDのポート 443
HMD_PROTOCOL_USESSL HackMDでHTTPSを利用している場合はtrue true
HMD_GITLAB_BASEURL GitLabのURL https://gitlab.dev.example.com
HMD_GITLAB_CLIENTID 前項で追加したOAuth ClientのApplication ID
HMD_GITLAB_CLIENTSECRET 前項で追加したOAuth ClientのSecret

Helmfileを利用している場合は以下のように環境変数を追加します。

# helmfile.yaml
releases:
  - name: hackmd
    namespace: devops
    chart: stable/hackmd
    values:
      - ingress:
          enabled: true
          hosts:
            - hackmd.{{ requiredEnv "kubernetes_ingress_domain" }}
        resources:
          limits:
            memory: 256Mi
          requests:
            memory: 256Mi
        persistence:
          size: 50Gi
        postgresql:
          install: false
          postgresHost: {{ requiredEnv "database_host" }}
          postgresDatabase: hackmd
          postgresUser: hackmd
          postgresPassword: hackmd
        extraVars:
          - name: HMD_DOMAIN
            value: hackmd.{{ requiredEnv "kubernetes_ingress_domain" }}
          - name: HMD_URL_ADDPORT
            value: "443"
          - name: HMD_PROTOCOL_USESSL
            value: "true"
          - name: HMD_GITLAB_BASEURL
            value: https://gitlab.{{ requiredEnv "kubernetes_ingress_domain" }}
          - name: HMD_GITLAB_CLIENTID
            value: xxx
          - name: HMD_GITLAB_CLIENTSECRET
            value: xxx

HackMDのトップページでサインインをクリックした時にGitLabでサインインというボタンが表示されたら成功です。

See Also

WZR-HP-AG300Hのファームウェアを書き換える (macOS)

macOSでWZR-HP-AG300Hのファームウェアを書き換える方法を説明します。DD-WRTの書き込みや純正ファームへの書き戻しに使えます。

まず、WZR-HP-AG300HのLAN側ポートを有線LANでMacBookに接続します。IPアドレスは以下を設定します。

WZR-HP-AG300Hは電源を入れておきます。

NICのインタフェース名を確認します。ここでは en2 とします。

$ ifconfig
en2: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500

APRテーブルを手動で設定します。

sudo arp -s 192.168.11.1 02:AA:BB:CC:DD:20 en2
$ arp -a
? (192.168.11.1) at 2:aa:bb:cc:dd:20 on en2 permanent [ethernet]

ここで、WZR-HP-AG300Hの電源を入れ直します。すると、数秒後にTFTPのアップロードを実行できるタイミングが来ます。

  1. USBコネクタのLEDが光る(2〜3秒)
  2. USBコネクタのLEDが消える
  3. EthernetポートすべてのLEDが光る(2〜3秒)
  4. EthernetポートすべてのLEDが消える
  5. MacBookと接続しているポートのLEDが光る
  6. TFTPのアップロードを実行できる(4秒間)

下記の記事が分かりやすいので参照してみてください。

koyama4284.blogspot.com

TFTPのアップロードを実行できるタイミングがきたら以下を実行します。

echo -e "verbose\nbinary\nput wzr_hp_ag300h_jp_175" | tftp 192.168.11.1

MacBookと接続しているポートのLEDが光ったら何回か実行してみてください。以下のように、最初の数回はエラーが出ると思います。

% echo -e "verbose\nbinary\nput wzr_hp_ag300h_jp_175" | tftp 192.168.11.1
Verbose mode on.
mode set to octet
putting wzr_hp_ag300h_jp_175 to 192.168.11.1:wzr_hp_ag300h_jp_175 [octet]
tftp: sendto: Can't assign requested address

% echo -e "verbose\nbinary\nput wzr_hp_ag300h_jp_175" | tftp 192.168.11.1
Verbose mode on.
mode set to octet
putting wzr_hp_ag300h_jp_175 to 192.168.11.1:wzr_hp_ag300h_jp_175 [octet]
Sent 20472060 bytes in 9.4 seconds [17423030 bits/sec]

TFTPのアップロードが完了したら、正面のLEDが赤色になってファームウェアの焼き込みが始まります。数分後に正面のLEDが緑色になれば成功です。

先ほど設定したARPテーブルのエントリを削除します。

sudo arp -d 192.168.11.1

ブラウザで http://192.168.11.1 を開くと見慣れた設定画面が表示されるはずです。