NGINX Ingressで複数ドメインを1つのALBに集約する
AWSでKubernetesを利用する場合、Ingress Controllerの選択肢にはaws-alb-ingress-controllerやkube-ingress-aws-controller、nginx-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リソースを構成します。
- nginx-ingressのServiceをNodePortで公開する。
- ALB Target GroupにKubernetes WorkerのAuto Scaling Groupをアタッチし、転送先をNodePortに設定する。
- ALB ListenerにワイルドカードドメインのSSL証明書をアタッチする。
- ALBにSecurity Groupをアタッチする。
- Route53 Hosted ZoneにワイルドカードドメインのAレコードを作成する。
上記にInternal ALBやRoute53 Private Hosted Zoneを追加するとインターネットとVPC内部に同一のFQDNでサービスを提供する構成を実現できます。
kopsでKubernetesを管理する場合の構成を下図に示します。EKSの場合もおおよそ同じになるはずです。
例えば、Route53やALBのワイルドカードドメインを *.dev.example.com
とした場合、www.dev.example.com
に対するトラフィックは以下の流れで転送されます。
- Route53が
www.dev.example.com
に対応するALBのAレコードを返す。 - ALB Listenerは
*.dev.example.com
のSSL証明書を利用してネゴシエーションを行う。 - ALB Target GroupはKubernetes WorkerのNodePortにトラフィックを転送する。
- nginx-ingressはHostヘッダとパスでトラフィックの転送先を決定する。例の場合は
www.dev.example.com
に対応するServiceにトラフィックを転送する。 - アプリケーションのPodにトラフィックが到達する。
もし、Hostヘッダとパスに対応するServiceが見つからない場合、nginx-ingressはDefault Backendにトラフィックを転送します。
Helmfile, kops, Terraformによる構成管理
nginx-ingressはHelm 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が管理するリソース
- Terraformが管理するリソース
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による実装をGitHubの int128/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
- aws-alb-ingress-controller: https://qiita.com/koudaiii/items/2031d67c715b5bb50357
- kube-ingress-aws-controller: https://qiita.com/mumoshu/items/a3e1e0f808a7109e5212
*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_domain
や database_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のアップロードを実行できるタイミングが来ます。
- USBコネクタのLEDが光る(2〜3秒)
- USBコネクタのLEDが消える
- EthernetポートすべてのLEDが光る(2〜3秒)
- EthernetポートすべてのLEDが消える
- MacBookと接続しているポートのLEDが光る
- TFTPのアップロードを実行できる(4秒間)
下記の記事が分かりやすいので参照してみてください。
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 を開くと見慣れた設定画面が表示されるはずです。