AWS EKSのproduction運用を見据えたベストプラクティス:ロギング、セキュリティグループ、IAMの設定

GA technologies, Blockchain Strategy Centerの中村です。 3回目の投稿ですが、またBlockchainから外れて今度はインフラ周りの記事です。

弊社で現在開発中の新規プロダクトではECS上でコンテナを稼働させており、公式クライアントツールの ecs-cli を利用してCI/CD pipelineからデプロイを行うような構成をとっております。 しかしながらデプロイ後の不測の事態に伴うrollbackなど実運用を想定した際、ECS本体だけでは若干の機能不足が否めないのも事実です。 一方、比較対象として挙げられるkubernetesは本体がもはやオーケストレーションツールにとどまらないほど多機能で、周辺のエコシステムも豊富なツールを提供しています。 昨年末に丁度 EKSがtokyo regionでサポートされたというニュースもあり、本番環境での稼働を見据えた検証を行なったため備忘までに記事を書きます。

TL;DR

  • EKSは現状、ほぼプレーンなk8sのmaster nodeのマネージドサービス
  • CloudWatch Logsとの連携は、fluentdを介して行う
  • SecurityGroupはannotationで操作する
  • Podに対するIAM Roleの割り当ては、3rd Party Toolで対応

ログの集約

fluentd as DaemonSet

現状のEKSはほぼkubernetesのmaster nodeのマネージドサービスといった趣が強く、 annotation一行でCloudWatch Logsと連携してくれるような機能は提供されておりません。 そのため、fluentd等を経由し何らかのログ収集基盤に転送する必要があります。

fluentd => CloudWatch Logsの連携を行う場合方法はいくつか考えられますが、

最もお手軽なのはfluentdをkubernetesのDaemonSetとして稼働させるための公式イメージの利用です。

仕組みとしては、kubernetesがコンテナごとのログファイルを出力する WorkerNodeのディレクトリ /var/log/containers に対して、 fluentd containerをvolumeMountして稼働させることでログを拾っています。 fluentdがtailしたログはコンテナごとにlog streamに分割されて集積されます。

用意されているmanifestファイルをほぼそのまま転用する事が可能ですが、下記のfluentdの環境変数のみ自身の環境に合わせて 設定してください。 尚、 FLUENT_UID はmountしたvolumeのread/writeするために必要なものです。

        env:
          - name: LOG_GROUP_NAME
            value: "any_log_group_name"
          - name: AWS_REGION
            value: "ap-northeast-1"
          - name: FLUENT_UID
            value: "0"

fluentd as Sidecar

その他、より細かな設定を行いたい場合はvolume containerをapplicationおよび、sidecarとして起動するfluentd containerと共有することで、 独自の fluent.conf を利用したログ収集が可能です。 その際も公式で配布されている docker imageを利用すると良いでしょう。 下記は、fluent-plugin-cloudwatch-logs pluginを導入する場合の最小限の設定になります。

FROM fluent/fluentd:v1.3.3-onbuild-1.0

USER root

RUN apk add --no-cache --update --virtual .build-deps \
    sudo build-base ruby-dev \
  && sudo gem install \
    fluent-plugin-cloudwatch-logs \
  && sudo gem sources --clear-all \
  && apk del .build-deps \
  && rm -rf /home/fluent/.gem/ruby/2.5.0/cache/*.gem

COPY fluent.conf /fluentd/etc/

ELBとの連携

EKSでは、kubernetesのServiceResouceのtype = LoadBalancer 経由でCLBと経由させる事が可能です。 (ALBやNLBを利用する事も可能ですが割愛します) 一方、EKSから起動するとdefaultで80 portが公開されたSecurityGroupが作成されてしまいます。 これは annotationによって internal LBとして作成した場合も同様の挙動になってしまいます。 対処方法としては、 spec.loadBalancerSourceRanges によってSourceIPを絞ることが挙げられます。

Restrict Access For LoadBalancer Service

実はkubernetesのソースコードを読むと, まさにSecurityGroupを指定する service.beta.kubernetes.io/aws-load-balancer-security-groups というannotationが用意されているのですが、これは v1.13 からの機能で、EKSの最新版である v1.11 では残念ながら利用できません。

そのため、社内からのアクセスに限定したLBを設置したい場合は現状下記のようになります。

apiVersion: v1
kind: Service
metadata:
  labels: 
    task: web
  name: http-server
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "{extraSG1},{extraSG2}"
  namespace: default
spec:
  type: LoadBalancer
  loadBalancerSourceRanges:
  - {社内IP}/32
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  selector:
    app: {metadata.labels.app of pod}

IAM Roleとの連携

これも現状ではPod単位でのIAM Roleの指定はできず、WorkerのRoleがそのまま引き継がれますので、細かい制御をしたい場合はkiamやkube2iamなどの利用や、kubernetesのSecret Resourceを利用して管理するのが良いと思われます。

おわりに

AWSでのcontainer周りの開発に関しては、GitHub上で ロードマップが公開されています。 ウォッチしつつ、実運用を想定して検証を進めていく所存です。

最後に、GA technologiesでは一緒に働く開発者を募集しています。(Blockchain Strategy Centerでも絶賛エンジニア募集中です!) ご興味を持たれた方はぜひ下記からご応募ください!

GA technologies 新卒・中途採用サイト