2024/12/22 Webサービスをデプロイできるアプリケーションの開発
システムの要件
アプリ作成フォーム
GitのURL
アプリケーション名
アプリを作成するボタン
押下すると、アプリ詳細画面に遷移し、POST /apps/createリクエストが発行される
アプリ管理画面(GET /apps)
アプリ作成ボタン(アプリ作成フォームに遷移)
アプリ一覧
イベントログ
アプリ詳細画面(GET /apps/{id})
アプリ作成の実装
1. GitHubのリポジトリURLからclone
2. Docker Engine APIを利用し、イメージをビルドする
3. Deployment、Serviceのファイルをテンプレートから作成し、applyする
ServiceはClusterIP型である。
このとき、アプリケーションの設定情報データベースに、ClusterIPの値を書き込んでおく
4. hostsボリュームを書き換える。
hostsボリュームは、CoreDNSのhostsプラグインによって5秒おきに参照される。
hostsボリュームについて
冗長化などは(いまのところ)しない。
そのため、local型のPersistentVolumeとして定義する。
https://kubernetes.io/ja/docs/concepts/storage/volumes/#local
アプリケーションの設定情報データベースの値から計算される。
アプリケーションに与えられるURL
appName.userId.deployable.com
アプリの閲覧方法
一般的なPaaSでは、各アプリケーションにグローバルIPが割り当てられ、恒常的に、グローバルにアクセス可能である
今回は、アプリケーションにグローバルIPを割り当てたくない。
各アプリケーションは、仮想ネットワーク上で何らかのIPアドレスを持てればそれでよいとする。
ユーザは、事前にWindowsやcurlにプロキシを設定しておくことで、仮想ネットワークにアクセスできる。
プロキシサーバを設定しておく
デプロイの方法を検討する
各アプリのデプロイ時には、DeploymentによりPodを1つ生成する。
また、同時にClusterIP型のServiceもapplyする。
Podを直接
これは、Cluster内部でPodに接続する
アクセスのために、Squidコンテナを含むPodをNodePort型のServiceで外部公開する。
app: squidラベルのついたPodはすべて3128ポートでプロキシを提供するものとする。
ゆえに、Serviceのport、targetPortはともに3128とする。
Kubernetes上のSquid用Podをプロキシとしてnginx用Podにアクセスしたい
Dockerイメージをビルドする
与えられるGitリポジトリの構造は、次のとおりである。
go.mod
go.sum
main.go
新しいアプリを作成する
アプリ名
「...にデプロイされます」
GitHubのURL
言語(Go言語の場合はgo run)
デプロイボタン
ドメイン名について
CoreDNSもetcdでゾーン情報を保存していそう。etcdctlでセットできる
https://qiita.com/kanga/items/e74038f25d1f53ca6ade
Squidサーバのみ、デフォルトのKubernetes用DNSではなく、このアプリケーション用に立てたCoreDNS Podを使うようにすると良いかもしれない。
dnsConfigを設定しておく
https://kubernetes.io/ja/docs/concepts/services-networking/dns-pod-service/#pod-dns-config
ユーザーはアプリ名を使ってアクセスしてくるので、それをappIdを使ったドメインに書き替えれば後はrewriteプラグインで..?
少なくともClusterIPはこちらで振りたくないので、Serviceの本来のドメインに書き換える方式を採りたい
1. DockerイメージのビルドログをWebSocketで出力する
ひとまず、ローカルに用意しておいたDockerfileを使ってビルドするページを作る
なぜDocker CLIは、ビルドログを標準出力できるのか?
https://pkg.go.dev/github.com/docker/docker@v27.4.1+incompatible/api/types#ImageBuildResponse
ImageBuildResponse.Bodyを使っているのかもしれない
https://github.com/docker/cli/blob/45648e8e0e699296da3fc1fc60b2490a9a180e76/cli/command/image/build.go#L364
メモ
Docker CLIでは、Gitをコンテキストとしてイメージをビルドすることも可能。
Contextの取得
https://github.com/docker/cli/blob/45648e8e0e699296da3fc1fc60b2490a9a180e76/cli/command/image/build.go#L234
Contextの取得処理の実装
https://github.com/docker/cli/blob/45648e8e0e699296da3fc1fc60b2490a9a180e76/cli/command/image/build/context.go#L196
https://github.com/moby/moby/blob/b5d5fef7aa68f160b817edef186c9b18ab996f4f/builder/remotecontext/git/gitutils.go#L49
ビルド時にDockerfileはContextDirから取り除かれるようなので、Dockerfileだけこちらで用意することは難しくないかもしれない!
やるべきことは、CMD "go run main.go"だけ?
と思ったが、docker buildにURLを指定した場合、Dockerfileを参照することはできないかも..
code:build.txt
#1 internal load git source https://github.com/golang/example.git
#1 0.078 Initialized empty Git repository in /var/lib/docker/overlay2/phxi00roojjzqj2lwkuxxn81y/diff
...
#1 1.515 From https://github.com/golang/example
#1 1.515 * new branch master -> master
#1 1.518 * new branch master -> origin/master
#1 DONE 3.1s
ERROR: failed to solve: failed to read dockerfile: open ./build/Dockerfile: no such file or directory
https://docs.docker.jp/engine/reference/commandline/build.html#url
ここの動作が求めるものとは異なっているので、ImageBuildは頑張る方向で...
$ docker build
Gateway APIの作成
WebSocketを介して、フロントエンドにビルドログの発生を通知する。
Socket.IOのroom機能が今必要かもしれない
https://socket.io/docs/v4/rooms/
roomの命名規則: app: {applicationId}
os.Execの標準出力をWebSocketに出力する方法は?
参考になりそうな記事
https://zenn.dev/kasa/articles/golang-realtime-cmd-logger#改善後のコード%EF%BC%9Aリアルタイムログ出力とタイムアウト機能
https://gist.github.com/rochacon/52420a3ab36b131e1437
Golangのbufioやpipe、channelの使い方に習熟する必要がある