Help us understand the problem. What is going on with this article?

GitLabの環境変数設定をラクにした話

こんにちは。NRI aslead チームで新サービス開発をしているk5-saitoと申します。
aslead チームでは、GitLabを開発ツールとして活用しているのですが、環境変数を登録する手間を大きく削減したので、その話を書きました。

TL;DR

  • CLIフレームワークとして、cobraを使うことでKubectlライクなコマンドを簡単に作ることができた。
  • クロスコンパイルが容易にできるので、Windows、MacOS、GitLabCIでの実行も可能

背景

プロジェクトのCICDパイプラインとしての利用

ある大規模アプリケーションにCICDを導入して、開発の生産性を向上しようというプロジェクトがありました。しかしアプリケーションが大規模になればなるほど、環境変数は多くなっていき、変更も頻繁に走ります。毎回変更があるたび、環境変数にミスがないかを確認して、手作業で変更して、ということを繰り返していました。

実際のプロジェクトの環境変数の具体例としては、

  • サブシステム名
  • デプロイパス
  • パッケージリポジトリ
  • データベース名

などなど、合計で30個くらいあって、実際の様子がこんな感じでした。image.png
ぞっとする量ですね。

プロジェクトのインフラ構築job実行基盤として

当初aslead Remoteを社内展開する際、各人のユーザIDや認証情報、接続ポート番号をVariablesに入力をして、パイプラインを回して、インフラを構築していました。
環境変数としては6つほどだったのですが、それが300人くらいに対応する必要がありました。これも手動でコピペをしてパイプラインを操作していました。

これをどうにか楽にできないか、ということで環境変数の入力を簡単にするツールを作ることにしました。

作るもの

  • GitLabのVariablesをYAMLで変更できるようなツール
    • gv-ctlという名前にしました。
  • 手元のマシン(Windows)でも動かしたいし、将来的にはGitLabCIパイプラインでも実行したい

python-gitlabというCLIもあるのですが、YAMLファイルからshell芸をするよりかは、Cobraを使った方が便利でした。
Variablesは、認証情報などが入るため隠す必要があります。ここが実現に向けて難しいところでした。

作り方

大まかには3ステップに分かれます。
1. cobraコマンドを使って、雛形を作成
2. 実装する
3. ビルドする

2と3については、プロジェクトによって異なるので、省略します。
cobra 用のプロジェクトのひな型の作成は方法は、

$cobra init gv-ctl --pkg-name gv-ctl

今回は、$GOPATH配下外で作業するので、--pkg-name を追加しました。またそれに伴い、go moduleを有効化をしておいてください。

$ cobra add setup

これでサブコマンドが作れます。
後は実装するだけ。

注意するところ

フラッグ変数の受け渡し

cobra.Command.PersistentFlags().StringP(...)cobra.Command.PersistentFlags().StringVar(...)があります。
短縮系が使えるか、変数のアドレスで指定するかという違いがあります。
私は、短縮形を使いたかったので前者を採用

(サブ)コマンドにflagを登録

func init() {
    setupCmd.PersistentFlags().StringP("filePath", "f", "gvctl.yaml", "variables config file path")
    rootCmd.AddCommand(setupCmd)
}

呼び出し

func(cmd *cobra.Command, args []string) {
  filePath, err := cmd.PersistentFlags().GetString("filePath")
  
引数 StringPの入力値 StringVarの入力値
第1引数 フラグ名 変数のアドレス
第2引数 短縮系 フラグ名
第3引数 デフォルト値 デフォルト値
第4引数 説明 説明

YAMLファイルの読み込み

viperを使って、yamlファイルを読み込むことができます。入れ子の構造体も良しなにやってくれて楽。

type Variable struct {
    Key       string
    Value     string
    Protected bool
    Masked    bool
}

type Manifest struct {
    BaseURL   string
    Type      string
    ID        string
    Token     string
    Variables []Variable
}

func readManifest(filePath string) (manifest *Manifest, err error) {
    // YAMLファイルを開き、値を手に入れる
    viper.SetConfigFile(filePath)
    err = viper.ReadInConfig()
    if err != nil {
        return manifest, err
    }
    err = viper.Unmarshal(&manifest)
    if err != nil {
        return manifest, err
    }
    return manifest, nil
}

効果

非公開リポジトリを用意し、頻繁に変更になるVariablesをバージョン管理することができた。
Variablesは隠す必要があるので、別リポジトリを作って、そこでパイプラインを運用する形で運用しました。

また、インフラ構築部分でも1800回分のコピペを削減し、私たちの労力を大幅に削減しました。

おわりに

他にもやりたいことを実現する違うアプローチはあると思いますが、ソースを乗っけておきます。実際に社内で使われたものとそのままというわけではないのでしっかり動くことは保証できませんが、反響があれば順次拡張していければいいなと思っています。

https://github.com/lottotto/gv-ctl

k5-saito
発言は個人の見解です。
nri
NRIは「コンサルティング」「金融 ITソリューション」「産業 ITソリューション」「IT 基盤サービス」の4事業でお客様のビジネスや快適な社会、暮らしを支えています。※各記事の内容は個人の見解であり、所属する組織の公式見解ではありません。
https://www.nri.com/jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした