GCE に Gitea の環境を小さく運用するために作る

小さく運用するために

とにかく、省コストでありながらも、極力マネージド環境を使い、かつ壊れてしまってもいいという状態を作ることを目指します。

  • GCE (Comupute Engine) Container-Optimized OS イメージを使ってのコンテナ運用を行います
    • Gitea はほとんどインストール作業が不要ですが、それでも Linux の systemd の設定なども含めると不慣れなメンバーがいる場合に避けておきたいです
    • Installation from binary - Docs
  • Gitea のデータ保存用の RDB は Cloud SQL を利用します
    • 簡易という意味では SQLite でも良かったのですが、Cloud SQL も最も小さいインスタンスを選べばコストはそれほどでもないためです
  • Git で管理するコードは Cloud Source Repositories に mirroring する
    • もちろん永続ディスクでのバックアップはしますが、Gitea は多機能ではないため、CI 関係の処理を Cloud Build 等に任せたい場合、Cloud Source Repositories にコードがある方が都合もよく Gitea のリソースも圧迫しないと考えたためです

事前準備

有効化する API

上記より以下の API を有効化します

  • Cloud SQL API
  • Cloud Source Repositories API

構築者に必要な役割

必要なサービスアカウント

Gitea から Cloud Source Repositories に mirroring するためには、Cloud Source Repositories 編集者が必要です。

Cloud Shell を起動し、以下のようにすれば作成できます。

$ export PROJECT_ID=`gcloud config list core/project --format='value(core.project)'`

# サービスアカウント gitea-compute の追加
$ gcloud beta iam service-accounts create gitea-compute \
  --description "Gitea サーバー用" \
  --display-name "gitea"

# gitea-compute に Cloud Source Repositories への push 権限を付与
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member serviceAccount:gitea-compute@$PROJECT_ID.iam.gserviceaccount.com \
  --role roles/source.writer

# key を作成しておく
$ gcloud iam service-accounts keys create ~/gitea-key.json \
  --iam-account "gitea-compute@$PROJECT_ID.iam.gserviceaccount.com"

サービス アカウント キーの作成と管理 - Google Cloud

Gitea 用の Docker Image の作成

Cloud Sourece Repositories の mirroring は上記で作成したサービスアカウントをコンテナで activate して、その権限で普通に git push --mirror するという形にします。

そのため、サービスアカウントの activate のために gcloud が必要です。また、Git に gcloud の helper を使わせないと Cloud Source Repositories に push ができません。

よって、以下のように gcloud を追加でインストールした Gitea のイメージを用意します。

Dockerfile

Gitea の公式イメージが alpine を利用するため google-cloud-sdk の alpine の内容をそのまま追加した内容です。

cloud-sdk-docker/Dockerfile at master · GoogleCloudPlatform/cloud-sdk-docker · GitHub

FROM docker:17.12.0-ce as static-docker-source

FROM gitea/gitea:1.10.3

# install cloud-sdk
ARG CLOUD_SDK_VERSION=279.0.0
ENV CLOUD_SDK_VERSION=$CLOUD_SDK_VERSION
ENV CLOUDSDK_PYTHON=python3

ENV PATH /google-cloud-sdk/bin:$PATH
COPY --from=static-docker-source /usr/local/bin/docker /usr/local/bin/docker
RUN apk --no-cache add \
        curl \
        python3 \
        py3-crcmod \
        bash \
        libc6-compat \
        openssh-client \
        git \
        gnupg \
    && curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
    tar xzf google-cloud-sdk-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
    rm google-cloud-sdk-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
    gcloud config set core/disable_usage_reporting true && \
    gcloud config set component_manager/disable_update_check true && \
    gcloud config set metrics/environment github_docker_image && \
    gcloud --version

RUN git config --system credential.'https://source.developers.google.com'.helper gcloud.sh
RUN ln -s /google-cloud-sdk/bin/gcloud /usr/local/bin/gcloud && ln -s /google-cloud-sdk/bin/git-credential-gcloud.sh /usr/local/bin/git-credential-gcloud.sh

VOLUME ["/root/.config"]

Container Registry に登録

$ cd (Dockerfile のあるディレクトリ)
$ docker build -t gitea-with-cloud-sdk .
$ docker tag gitea-with-cloud-sdk gcr.io/$PROJECT_ID/gitea-with-cloud-sdk
$ docker push gcr.io/$PROJECT_ID/gitea-with-cloud-sdk

Cloud Shell でもローカルでも実行環境は問いませんが、もし初めて Container Registry に入れる場合には以下を実行しておきます。

$ gcloud auth configure-docker

オプション: Docker イメージを実行する - Google Cloud

Cloud SQL の作成

f:id:dany1468:20200229090410p:plain

初回はプライベート接続のための IP アドレス範囲の作成が必要になります。

プライベート IP 接続の構成 - Google Cloud

以下のような感じで VPC ネットワークピアリングとルートに追加されていれば構成が完了しています。

VPC ネットワーク ピアリング に追加される
f:id:dany1468:20200229090736p:plain

ルートに追加される
f:id:dany1468:20200229090640p:plain

その他の設定

ユーザーや Gitea で利用するデータベースは適宜作成しておいてください。特に規約はありません。

Gitea サーバーの構築

永続ディスク付きで Container-Optimized OS のインスタンスを作る

まずは、コンテナイメージのデプロイにチェックをし、先程 Container Registry に登録した Image を指定します。
f:id:dany1468:20200229091036p:plain

続いて永続ディスクを作成し、 /data をマウントします。
f:id:dany1468:20200229091553p:plain

永続ディスクはスナップショットをとるように設定しておきます。

以下にあるように Gitea のデータは /data を永続化しておけば問題ありません。 Installation with Docker - Gitea

永続ディスクのフォーマット

ゾーン永続ディスクの追加またはサイズ変更

永続ディスクはフォーマットする必要があるため、上述の通りまずは作成したインスタンスssh で入り設定します。一度設定すれば、以降は自動でマウントされます。

Gitea コンテナ内の gcloud / Git の設定を行う

以下では、作成した Compute のインスタン名を gitea としたとします。

まずは SCP でインスタンスにサービスアカウントの key を送ります。

$ gcloud compute scp gitea-key.json gitea:~

続いて、インスタンスに入り、Gitea のコンテナが参照出来る場所に key をコピーします。

$ sudo cp -p gitea-key.json /mnt/disks/gce-containers-mounts/gce-persistent-disks/gitea-data/

Gitea のコンテナに入り key を activate します。git ユーザーに登録することになります。git ユーザーは Gitea のコンテナ内に存在します。

$ docker exec -it $(docker ps -aqf "name=gitea") /bin/bash
# 以降はコンテナ内
$ su - git
$ cd ../
$ gcloud auth activate-service-account --key-file gitea-key.json
$ gcloud config configurations list

activate したサービスアカウントの情報が出てくれば OK です。

activate の情報は /data/git/.config/gcloud に保存されるため、一度 activate すれば、インスタンスを再起動したとしても永続ディスクに activate 情報があるため再 activate は不要です。

最後に Git helper に gcloud を登録します。

$ git config --global credential.'https://source.developers.google.com'.helper gcloud.sh

リポジトリをリモートとして追加する - Google Cloud

Gitea の初期化を行う

$ gcloud compute start-iap-tunnel arch-gitea 3000 --local-host-port=localhost:3000

上記のように TCP portforwarding をして port 3000 で見れるようにします。

Gitea は初期化画面で連携するデータベースの情報を求めてくるので、Cloud SQL の情報を入力します。Cloud SQL は private IP が割り当てられているので、それで接続できます。

続いて、Gitea にリポジトリを一つ作っておきましょう。

Cloud Source Repositories に mirroring する

まずは mirroring 先となる Cloud Source Repositories にリポジトリを作成します。

作成できたら、Gitea の作成したリポジトリの Settings -> Git Hooks に以下のように post-receive を追加します。

f:id:dany1468:20200229095201p:plain

上記のままだと、Gitea に git push した際に mirroring のログも出るため、/dev/null に捨てる等適当にアレンジしてください。

最後に

Github 等を利用できれば、Cloud Source Repositories への mirroring すら手間いらずなので、あまり自前で Git のサーバーを構築するメリットは感じないのですが、現場の制約で今回このような構成を試してみました。

現状は Cloud IAP での TCP portforwarding での接続に絞っていたりで、多少不便な点もあり、今後改善していくべき部分も多いですが、構築にあたり GCP のいくつかのサービスの知見も得られたので良い経験でした。