GitLab CIでデプロイするためのDockerイメージをつくってみた話

[Increments × cyma (Ateam Inc.) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/increments-cyma)の6日目はIncrements株式会社の @okoshi が担当します！

GitLab CI で Firebase にデプロイしたいと思っていたら、気がついたら DockerHub に Docker イメージを登録していた話をさせていただきます。

## 経緯

GitLab CI で Firebase プロジェクトをデプロイするようにしようと思って、`rambabusaravanan/firebase`を使おうとおもったわけですが、いざデプロイを試みると、Cloud Functions for Firebaseの関数のデプロイ時に、使用している functions の npm ライブラリーが Node12 専用で、Nodeのバージョンが 14 だからと互換性がなく処理が中断してしまいました。

## 代わりのベースイメージを探すのを諦める

これは使用しているライブラリーに互換性のないものを使用しているのが原因なので、それを修正するか代替品を使うという手もありましたが、CIを使いたいという理由だけでそんな変更をしたくないのでどうせなら自分で Docker イメージを作って DockerHub に登録しようと思いました。

DockerHub で色々 Firebase に関するイメージがあることは確認できたのですが、どれでデプロイ可能なのか一つ一つ調べていくのは辛かったのと、今後のことも考えて作り方を把握しておくのも自分のためになると思い自分で作ることにしました。

## `rambabusaravanan/firebase`のDockerfileを確認

```Dockerfile
# Base Image - Node Platform
FROM node:alpine
LABEL maintainer="rambabusaravanan@gmail.com" version="2.0.2"

# Install Firebase CLI
RUN npm install -g firebase-tools
```

これだけです。やはりベースイメージのバージョンが固定されていません。
そのため、以前のビルドでNodeのバージョンが12よりも大きくなってしまっていると思われます。

それと、 firebase-tools さえあれば良いということも確認できました。

## ベースイメージは何にすればいいのか

`rambabusaravanan/firebase`の Dockerfile のように alpine のままだと、 Node のバージョンが変わっていってしまうので、ベースイメージは node のバージョン 12 のものにしました。

## 作ったDockerfile

色々試行錯誤して以下のようになりました。

```Dockerfile
FROM node:12.20.0-alpine3.10
LABEL maintainer="okoshi" version="1.0.0"

RUN npm install -g --unsafe-perm firebase-tools
```

## ビルド

最後のドットは打ち間違いではありません。

```
$ docker build -t okoshi/firebase .
```

## Dockerイメージを登録

先に DockerHub でアカウントを作っておく必要があります。また、そのときに指定する Docker ID は、イメージのスラッシュよりも前の部分に使われるものなので覚えておきましょう。

Docker IDというのはサインアップ時に入力した以下の場所に入力したもののことです。

![docker-hub-signin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64294/95dd426b-694f-af03-1ed0-871715b97cc1.png)

CLI から DockerHub にログインします。
Usernameには、DockerHub に登録した Docker ID を指定します。

```
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username:
Password:
Login Succeeded
```

そして、DockerHubに転送します。
実際に転送したものは[こちら](https://hub.docker.com/repository/docker/okoshi/firebase/general)です。

```
$ docker push okoshi/firebase:latest
The push refers to repository [docker.io/okoshi/firebase]
4a542576d013: Pushed
291f6e44771a: Mounted from library/centos
latest: digest: sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX size: 742
```

## FIREBASE_TOKENを発行する

Firebaseにデプロイするためには、firebase login コマンドでログインしておかなければなりません。firebase login コマンドは対話型でログインするものなので、GitLab CI の実行中にfirebase loginコマンドを実行するわけにはいけません。

ではCIツールで使用するにはどうしたらいいかというと、FirebaseにはCIツールで使うためのトークンを発行する方法が用意されています。

コマンドは `firebase login:ci` です。
このコマンドを実行すると、Webブラウザーが開くので、認証を行います。認証が終わると、ターミナル上にトークンが現れます。

そのトークンは GitLab のプロジェクトのSettingsページからFIREBASE_TOKENというキー名で登録しましょう。
![settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64294/e96999fa-7bec-aa24-41b9-dc26e1f77079.png)


## .gitlab-ci.ymlを書く

以下の内容のファイルをプロジェクトのルートディレクトリーに配置しておきます。
`master` ブランチにマージリクエストがマージされたときに `firebase deploy` が動きます。

```yml
image: okoshi/firebase

stages:
  - deploy

cache:                  
  paths:                
    - webapp/node_modules/
    - functions/node_modules/    
  key: "$CI_BUILD_REPO" 

deploy-prod:
  stage: deploy
  only:
    - master
  script:
    - yarn --cwd webapp
    - yarn --cwd functions
    - yarn --cwd webapp build
    - yarn --cwd functions build
    - firebase use my_project --token $FIREBASE_TOKEN
    - firebase deploy --token $FIREBASE_TOKEN
```

## ご注意

2020年11月より、未ログイン状態での DockerHub のプルにはレートリミットが設定されているので、CIには必要に応じてログイン処理を追加して運用してください。
詳細は[こちら](https://www.docker.com/blog/scaling-docker-to-serve-millions-more-developers-network-egress/)。

## 最後に

[Increments × cyma (Ateam Inc.) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/increments-cyma)の7日目はIncrements株式会社の @atm-snag がお送りします！