ねぎ嫌い

思いついたことをてきとうに。

Docker Volumeが削除できない!

背景

ローカルマシンのDocker VolumeのMount先を変更しようとしたときに、Volumeが消せなくなって困った

環境

  • macOS Monterey 12.1
  • Apple M1
  • Docker Desktop 4.4.2 (73305)

エラーメッセージ

Cannot remove volume XXX. Reason: Error invoking remote method 'docker-remove-volume': Error: (HTTP code 500) server error - remove XXX: volume has active mounts

結論

  • 利用しているコンテナは停止した上で、きちんとGUIから削除する
    • CLI経由だとVM上のボリュームが残ったっぽい挙動がある
  • 削除した後もVolumeがコンテナの残骸を見てることがあるので、Docker Desktopを再起動する
    • docker system pruneをやってもダメだった

改めて調べてみたら docker compose down --volumesを実行すればよかったっぽい。 確かに docker compose から作成したボリュームだった・・・。

stackoverflow.com

Docker Desktop (M1 Mac) でVolumeが作れない

課題

docker compose up を実行すると、以下のエラーが発生する

ERROR: for postgresql  Cannot start service db: error while mounting volume '/var/lib/docker/volumes/postgresql_db/_data': failed to mount local volume: mount /tmp/postgresql/data:/var/lib/docker/volumes/ghost-postgresql_db/_data, flags: 0x1000: no such file or directory

環境

  • macOS Monterey
  • Apple M1
  • Docker Desktop 4.4.2 (73305)

結論

Preferences > General にある Use gRPC FUSE for file sharing のオプションを無効化する

関連するGitHub issue:

github.com

状況

version: "3.9"

...

volumes:
  db:
    driver_opts:
      type: none
      device: /tmp/postgresql/data
      o: bind

こんな感じで、ローカルにマウントするボリュームを書いていると、冒頭のエラーが発生しContainerが立ち上がらない。
Volumeは作成されているものの、そんなファイルはない、と怒られてしまう。

結論に書いた通り、オプションのせいで動かなかった。   詳細は調べてないので、わかる方いたら教えてほしいです。。

社内システムの認証にOktaを使って楽をする

背景

  • 社内システムを使うのにアカウントの管理が面倒だった
  • ちょうどOktaを使い始める風潮があったので相乗りしたかった

前提

  • Oktaを導入している

やること

  • Oktaのアプリを登録する
  • フロントエンドでOktaのSSOを実装する
  • バックエンドでアクセストークンの検証をする

参考

  • フロントエンド (Next.js)

developer.okta.com

  • バックエンド (NestJS)

developer.okta.com

実装の一部

フロントエンド

// pages/api/auth/[...nextauth].ts

import NextAuth from 'next-auth';
import provider from 'next-auth/providers';

export default NextAuth({
  providers: [
    provider.Okta({
      clientId: process.env.OKTA_CLIENTID,
      clientSecret: process.env.OKTA_CLIENTSECRET,
      domain: process.env.OKTA_DOMAIN,
    }),
  ],
  theme: 'auto',
});

アプリを登録した際に発行されるClient ID/Client Secretを渡してあげる。 DomainはHTTPスキーマを抜いた形式 (xxx.okta.com/oauth2/$issuer)

pages/api/auth/[...nextauth].tsのパスはnext-authの指定。 NextAuth.jsに処理を以上するためには/api/auth/*の形式である必要がある。

バックエンド

基本的には参考したURLのものそのままだが、やることは以下

  • passport jsの実装
  • guardsの実装

Passport Strategyをまず実装する。

// auth/http.strategy.ts
import { HttpException, Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-http-bearer';
import { AuthService } from './auth.service';

@Injectable()
export class HttpStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly service: AuthService) {
    super();
  }

  async validate(
    token: string,
    done: (error: HttpException, value: boolean | string) => any,
  ) {
    try {
      return await this.service.validateToken(token);
    } catch (error) {
      done(error, 'token is invalid');
    }
  }
}

AuthService内で実際の検証作業を実施する。 validateはAuthGuardによって呼ばれており、User等を返すとそのままリクエストに付与してくれる。

ガードしたいエンドポイントにデコレータで宣言すれば終わり。

// user.controller.ts
  @Get()
  @UseGuards(AuthGuard('bearer'))
  async getUsers(): Promise<User[]> {
    return this.service.getUsers();
  }

CoverityとJIRA CloudをIntegrationする

背景

  • Coverityで発見された脆弱性をJIRAに起票したい
  • 大したことは書かないけどちょっと詰まったので脳から消す意味でも書き残す

参考

環境

  • Coverity Platform

やること

  • Configuration > System > バグ追跡システム:JIRA から設定を作成する

詰まりポイント

  • JIRA サーバーの設定で 場所 をどこに設定するか
  • パスワードは何を設定するか

JIRA サーバーの設定で 場所 をどこに設定するか

https://XXXX.atlassian.net/ を指定する。
ログイン直後ではなく、このURIを指定する必要がある。

内部的にはJavaで実装され、AtlassianのSDKを利用している。
そのため、接続方法はそれに則る必要がある。

パスワードは何を設定するか

上記の通り、AtlassianのSDKに実装されている方法で設定を組む必要がある。
参考に挙げた2件目で言及されている通り、Basic認証時に利用するパスワードの値が変更されたため、
JIRAでAPIトークンを発行し、その値を利用する必要がある。

Cloud Run x Cloud SQLでGrafanaをTerraformで立てる

背景

  • プロダクトの監視に安くダッシュボードを作りたい
  • 運用コストをあんまり上げたくない

=> (フル)マネージドな環境でGrafanaを立てればええやん

TL;DR

github.com

前提

  • GCPのプロジェクトがセットアップされている

構築手順

  1. Terraformを記述する
  2. Deployする

以上

Terraformの環境セットアップ

terraform --helpコマンドが使えない人向け。

公式に従ってインストールするのも良いけれど、バージョン管理が面倒だと思うので、tfenvを入れる。
GitHubに記載の手順に従ってインストールする。

Macなので brew install tfenv を実行すれば良い。

その後、tfenv install latest && tfenv use latest を実行すると terraform --help が使えるようになる。

.tfファイルを実装する

必要になるのは大きく分けて2つ。

  • GCPの定義を書いた.tfファイル
  • Grafanaの定義を書いた.tfファイル

またそれらのProviderを管理するためのファイルの3つで管理すると見通しが良い。

GCPの定義

作成する必要があるのは、

  • Cloud SQL
  • Cloud Run
  • Cloud RunとCloud SQLを接続出来るようにするためのVPC

3つ目はCloud SQLをPublicなネットワークに公開する覚悟がある人は不要だと思う。
私は自信がないのでVPCを貼ってその上で接続するようにしている(というか参考にしたものがそうだったのでそれに乗っかっただけ)。

詳細は 参考先のソース を見てもらったほうが早い。

複数人で運用する想定なら、tfstatをGCSにあげて管理するのも考えて良いかも。 その場合は以下追記する。

terraform {
  backend "gcs" {
    bucket  = "事前に手作業で用意したバケット名"
    prefix = "バケット内のパス(必要があれば)"
  }
}

terraform"を"管理するためのリソースはterraform外で管理されるべき、というどこかで聞き覚えたものに従ってるので手作業が必要。
(元ネタ誰か分かったら教えてほしいです、、、)

Deployする

Service Accountでの適用が望ましいため、GCP上でService Accountおよびキーの払い出しを行い、 GOOGLE_APPLICATION_CREDENTIALSに取得した鍵ファイル(.json)のパスを指定してあげる。

その上で、terraform apply を実施する。

defaultが未定義な変数に関しては対話式で聞かれるので回答してあげればOK。
初回はDB構築等も含まれるので5分以上かかるかも。

以上。

ハマりポイント

  • Service Accountの権限

必要な権限のみを割り当てるべき、という大原則は認識しているものの、洗い出しが面倒だったのでオーナー権限付けた。
特にネットワークの構成あたりで死んでたのはこれで解決した。編集者じゃ足りない模様。

  • Cloud SQLの削除に失敗して terraform destroyterraform init も通らんくなる

コンソールから残ってしまったリソースを削除した上で、tfstatファイルも削除する。
と、terraform applyが通るようになる。

ボツにした構成

  • GKEに立てる
  • GCEにインスタンスを立てて、その上でDocker Composeで拡張性を考慮した構成にする

GKEに立てて上げるほどのものでもなかったので、 && キャッチアップコストが高すぎたので却下
GKEに慣れている人は多分サクッと構築出来るんだと思う。

GCEにインスタンス立ててやるのはSSL証明書の準備やロードバランサの構成等を考えるのが面倒だったので却下。
またContainer Optimized OSの癖が強すぎるのもあったw