ブログのバックエンドをKubernetesにしてみた

 去年のいつだったか、会社のエンジニアではない人に「なんでうちのエンジニアたちはKubernetesを使いたがっているの?」と質問された。エンジニアではない人もPaaSなどがわかるように教育されていたおかげでわりと簡単に答えられた。「PaaSはサーバ管理を任せられるし、スケーリングやローリングアップデートなんかもワンクリックで済むぐらいの簡単さがある。だけどそれは各クラウドベンダがそれぞれのやり方で実装しているものだから、ベンダロックインを受けてしまう。k8sは前に挙げた便利機能を持っている。そしてどこで動かしたっていいからベンダロックインを回避できる」と答えた。

 去年の年末、このブログを動かしていたコンテナホスティングサービスからサービス終了の告知が来た。コストなどを少し考えた上でAzureのマネージドのk8s、つまりAKSを使うことにした。
 ぼくの説明は本当に正しかったのか試す機会を得た。この、Dockerイメージ化されてコンテナホスティングサービスで動いていたブログをAKSに移行するのに、どの程度Azure独自のことをしなければならず、どの程度k8sの設定で済むのか。そんなところをやってみた。Dockerイメージ化されたブログを、Let's Encryptで証明書を取得、自動更新しつつHTTPSで配信するという構成。


 k8sに配置するリソースは下記のものを用意した。YAMLの詳細は後に回す。
- Deployment: アプリのPodをコントロール
- Ingress: http & httpsアクセス
- Service: Ingress - Pod間のネットワーキング
- Certificate: 証明書情報(Let's Encryptで取得)
- Secret: 外部データベース、クラウドストレージなどの接続情報
これらはもちろんk8sの標準的なリソースなのでAzureだから特別な書き方をしなければというのはない。標準的なYAMLだ。

 AKSでk8sを立ち上げてCLIで接続後、唯一Azure上の独自のやり方でやらなければならなかったのはIPの発行。まあここはさすがに仕方がないことだし、コマンドですぐに発行できるし。
az network public-ip create --resource-group [resource name] --name [ip name] --allocation-method static


IPを取得したらもちろん、DNS設定は忘れずに行う。

 デフォルト構成にHelmを加え、CertManagerを入れたが、これはk8s側に用意されたもので、WindowsでもCLIが動くので簡単にAKSのk8sへ入れることができた。
Azure Kubernetes Service (AKS) での Helm を使用したアプリケーションのインストール
helm install stable/nginx-ingress --namespace kube-system --set controller.service.loadBalancerIP="[ip]" --set controller.replicaCount=2 --set rbac.create=false --set rbac.createRole=false --set rbac.createClusterRole=false

helm install stable/cert-manager --namespace kube-system --set ingressShim.defaultIssuerName=letsencrypt-prod --set ingressShim.defaultIssuerKind=ClusterIssuer --set rbac.create=false --set serviceAccount.create=false


 IP取得&それのDNS設定、Helmが準備できれば、あとはk8s上にリソースを配置していくだけだ、YAMLを読み込ませることによって。あとドメインとIPが結びついてなけりゃ証明書取得はできるはずもないので忘れないこと。
apiVersion: apps/v1

kind: Deployment
metadata:
name: app-deployment
namespace: tetsujin
labels:
app: tetsujin
spec:
replicas: 1
selector:
matchLabels:
app: tetsujin
template:
metadata:
labels:
app: tetsujin
spec:
containers:
- name: tetsujin
image: matoba/tetsujin:414
ports:
- containerPort: 80
env:
- name: HASHKEY
valueFrom:
secretKeyRef:
name: tetsujin-secret
key: HASHKEY
- name: MONGO_CONNECTION
valueFrom:
secretKeyRef:
name: tetsujin-secret
key: MONGO_CONNECTION
- name: STORAGE_ACCOUNT
valueFrom:
secretKeyRef:
name: tetsujin-secret
key: STORAGE_ACCOUNT
- name: STORAGE_KEY
valueFrom:
secretKeyRef:
name: tetsujin-secret
key: STORAGE_KEY
- name: STORAGE_URL
valueFrom:
secretKeyRef:
name: tetsujin-secret
key: STORAGE_URL

↑のYAMLはCPUやメモリのリソース制限をかけていないのでよろしくない。自分の環境に合わせて適当に適切な設定をすること

apiVersion: v1

kind: Service
metadata:
name: tetsujin-service
namespace: tetsujin
labels:
network: tetsujin
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: tetsujin


apiVersion: extensions/v1beta1

kind: Ingress
metadata:
name: ingress-tetsujin
namespace: tetsujin
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
ingress.appscode.com/hsts: "true"
ingress.appscode.com/hsts-preload: "true"
ingress.appscode.com/hsts-include-subdomains: "true"
ingress.appscode.com/hsts-max-age: "100000"
spec:
tls:
- hosts:
- blog.hmatoba.net
secretName: tls-secret
rules:
- host: blog.hmatoba.net
http:
paths:
- path: /
backend:
serviceName: tetsujin-service
servicePort: 80

↑もHSTS有効化はしたけどもう少しセキュアなものにしたい

apiVersion: certmanager.k8s.io/v1alpha1

kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: foo@example.com
privateKeySecretRef:
name: letsencrypt-prod
http01: {}


apiVersion: certmanager.k8s.io/v1alpha1

kind: Certificate
metadata:
name: tls-secret
spec:
secretName: tls-secret
dnsNames:
- blog.hmatoba.net
acme:
config:
- http01:
ingressClass: nginx
domains:
- blog.hmatoba.net
- http01:
ingress: ingress-tetsujin
domains:
- blog.hmatoba.net
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer




 上記のYAMLに加え、Secretを用意してしかるべき順でリソースをk8s上に加えていった結果このブログが動作した。Let's Encryptで取得した証明書でhttps化も問題ない。結局Azureのマネージドk8sサービスであるAKSを使ってWebアプリを公開するにあたってAzure独自でやらなければならないのは、Azureのコンパネに従ってk8sを用意することと、IPの発行だけであった。それらは簡単だったし一度で終わることなので、それ以外のことやこれからの運用はk8sのお作法に従うだけだろう。こりゃロックインは回避できてるなというところ。


 余談。AKSの料金は開始時に設定した仮想マシンリソースの設定に従う。仮想マシンリソース。CPUが何コアのメモリが何コアという、仮想マシンにありがちなアレ。アレはリザーブドインスタンスというものがあり、長期で先に金を払ってリソースを買っておくことで使用料が安くなる。一年分を先買いで40%OFF。断然お得。
comment: 0

Azure PipelinesでGithubプッシュによる自動ビルドを行うブランチを追加する

 AzureでCI/CDができるAzure Pipelinesが、OSS向けはけっこうよさげなリソースで無料利用可能との発表があったので早速触ってみた。既存のプロジェクトに、紹介ビデオを見ながら導入。
https://docs.microsoft.com/ja-jp/azure/devops/pipelines/index?view=vsts

 やってみたのはいいんだけど、master以外のブランチでもGithubへのプッシュによる自動ビルド起動に手間がかかったのでメモ。

 ドキュメントに、「YAMLにtriggerを書かなければすべてのブランチで自動ビルド実行されるよ」と。されんかったぞ。triggerで対象ブランチを書いてもだめ。設定ページで「YAMLの設定をここでオーバーライドする」とあったのでそれを切ってもだめ。結局、設定ページで一つずつ対象ブランチを追加するしかなかった。


 そういうわけで設定ページまでの行き方を残す。とりあえずmasterブランチのビルドパイプラインは、ビデオに従った手順でできているとする。

 ”Edit”を選択


 ”Trigger”を選択し、branchフィルターでビルドを行いたいブランチを追加。


 以上で任意のブランチのGithubへのプッシュで、自動ビルドが走るようになる。

2018/11/21追記
branchフィルターにワイルドカードを入れれば、それで全ブランチ対応できることを確認。
comment: 0

VisualStudioで作ったDockerイメージでWebアプリってほんとに動かせるのか試す

前回

 VisualStudioでWebアプリを、Dockerサポートを有効にして作り始めた。ローカルでのデバッグ実行は、ブラウザにサイトが表示されたので成功。ではコンテナを実際Webサーバにのっけるとどうなるだろう。それをAzure Container Instanceで試す。
 DockerでWebアプリを走らせる方法はいくらかある。VPSを用意してそこにDockerを入れるとか。だけどコンテナホスティングサービスを使うのがかなり楽。いろいろ楽。

 まずDockerイメージをビルドしてDocker Hubへプッシュする。Docker Hubをググって探して、アカウントを取得しておく。
 プロジェクト内にdocker-compose.ymlがあるので、imageというキーに対応する値に自分のDockerHubアカウント名を入れる。これで作成されたイメージはDockerHubへプッシュできる。
    image: tetsujin

   ↓
    image: [account name]/tetsujin

 dokcer-compose.ymlの編集が済んだらDockerイメージをビルドする。VisualStudioでソリューション構成をReleaseにして、ソリューションをビルドする。PowerShellを開いて"docker images"を実行し、dokcer-compose.ymlでimageに設定した通りの名前のDockerイメージができているのを確認する。
 確認できたらプッシュ。
docker push matoba/tetsujin




 Dockerイメージをパブリックな場所に用意できた。つぎはAzure Container InstanceでこのDockerイメージを使ってWebアプリとして実行する。Azure Portalで指示に従ってもろもろ埋めて立ち上げる。


 作成されたリソースをのぞいてIPを確認する。

 ブラウザでIPへアクセスしてみる。

動作が確認できた。

 VisualStudioで作ったDockerイメージからWebアプリを動かせるのを確認した。引き続きASP.NET Core MVCでのブログの開発を続けていく。
comment: 0

Azure Web App on LinuxでDockerコンテナによるデプロイをしてみる

 前回でTravisCIからDocker hubへ、テストにとおったDockerイメージをプッシュした。これのデプロイ先としてAzure Web App on Linuxを選んだ場合をちょっとやってみる。

 AzureポータルでWeb App on Linuxを選び、イメージのソースをDocker hubに上げてあるイメージを指定。そして進む。


 デプロイが済むまでちょい待ってからアクセスしてみると、しっかりアプリが起動している。あれ?デプロイこんだけで済んじゃう?という感想。



 ところで、遊びに使うにはちょい高い。まあアプリケーションに注力するために、OSなどをよしなにやってくれるマネージドだからこんなところか。



 Docker hubとAzureの連携で継続的デプロイも可能。
Azure Web App on Linux での Docker Hub の継続的なデプロイ





comment: 0

遠隔でMongoDBサーバのバックアップを取る2

 前回に構築したMongoDBサーバの自動遠隔バックアップシステムを削除し、新しくバックアップシステムを組んだ。今回はMongoDBサーバでバックアップコマンドを実行し、それをAzure Blob StorageにPythonでアップするという流れ。

backup.sh

#!/bin/sh
cd /home/h/backup
mongodump --host foo -u bar -p boo
tar zcvf dump.tar.gz dump
python3.5 /home/h/up.py
rm -rf *


up.py

from azure.storage.blob import BlockBlobService
import datetime

account = "xxx"
key = "yyy"
block_blob_service = BlockBlobService(account_name=account, account_key=key)
filename = datetime.datetime.now().strftime("%Y%m%d")
block_blob_service.create_blob_from_path("mongo", filename, "dump.tar.gz")



comment: 0