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

CircleCIで試行錯誤した話

紹介

ZOZOテクノロジーズでSREをやっています。
先ずは、いままでCircleCIについて書いてきた記事を紹介させてください

2018年:弊社のアドベントカレンダー

「CircleCI + AWS Lambda function + Slackを使ったChatOps環境構築」

その他

  1. 「Incoming webhookを使ってCircleCIのSlackへの通知をJob別に分ける」
  2. 「CircleCIで重複したWorkflow(Job)を止める」
  3. 「CircleCIで、直前に実行したJobによって次のJobで実行する処理を変える」
  4. 「CircleCIでDockerコマンドを使う」
  5. 「CircleCIで使われているコンテナの中身」

何を記事にするのか

今回は、上記の記事以外で、CircleCIを使う上で対処してきた内容について書きます
CIといえど、使い方は人それぞれなのですが、どなたかの助けになれればいいなと思っています

[ 項目 ]

  1. パッケージ管理ソフト(aptとかyum)でインストールしたバイナリファイルはキャッシュに保存できても、リストアできない
  2. CircleCIで使っているグローバルIPアドレスの範囲がわからない
  3. .から始まるディレクトリ内のファイルを編集できない
  4. CircleCIから外部にsshしたい
  5. 外部からCircleCIのコンテナにsshしたい
  6. pythonのライブラリ依存のエラーが突然起きる
  7. machine executor だと pythonのバージョンがデフォルトで2系になっている

パッケージ管理ソフト(aptとかyum)でインストールしたバイナリファイルはキャッシュに保存できても、リストアできない

例えば以下のようなconfig.yamlがあったとします

config.yml
version: 2
jobs:
  test_job:
    machine: true
    steps:
    - run:
        name: Install redis-cli
        command: |
          sudo apt update && sudo apt install -y redis-server
    - save_cache:
        paths:
        - "/usr/bin/redis-cli"
        key: {{ checksum ".circleci/config.yml" }}

  test_job2:
    machine: true
    steps:
      - restore_cache:
          name: Restore cache
          key: {{ checksum ".circleci/config.yml" }}

上記の test_job は成功します、ただし test_job2 はキャッシュをリストアする際に /usr/bin への書き込み権限がなく失敗します

エラーは以下のようになります

shell
Downloading cache archive...
Validating cache...

Unarchiving cache...
tar: usr/bin/redis-cli: Cannot open: Permission denied
tar: Exiting with failure status due to previous errors

Error untarring cache: exit status 2

/bin 以下にあるバイナリファイルをキャッシュするのは諦めましょう
Job毎にインストールするのをおすすめします

CircleCIで使っているグローバルIPアドレスの範囲がわからない

参考URL: https://support.circleci.com/hc/en-us/articles/115014372807-IP-Address-ranges-for-whitelisting-

CircleCI builds are currently run mainly from AWS East and West. 
Google Cloud Platform and additional services may be used in the future. 
For this reason we can't give a list of IP addresses that our cloud system will use.

要約すると「AWSとGCPとその他のサービスを使っている、もしくは使うつもりだからIPアドレスのリストは教えられないよ」と言っています

仕方ないので、CIを実行するたびにグローバルIPを調べるようにしました

参考URL: http://mgi.hatenablog.com/entry/2014/10/30/085403

以下のコマンドを使えばグローバルIPアドレスを取ってこれます

shell
$ curl -f -s ifconfig.me

ちなみに、ifconfig.me がサービスダウンすると、CIが失敗するので、以下のほうがいいかもしれません

shell
$ curl checkip.amazonaws.com

.から始まるディレクトリ内のファイルを編集できない

たまに、CIの中で .dir/sample.txt などのファイルを書き換えようとすると、エラーは発生しないが、ファイルが書き換えられていないときがあります

そういうときは ファイル書き換え → ファイルの置き換え とやったほうが確実です

config.yml
- run:
    command: |
      echo 'OK' > sample.txt
      cd sample.txt .dir/sample.txt

ちなみに、machineを使っていると、デフォルトのShellは dash になっています
これの影響なのかな??

shell
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Feb 19  2014 /bin/sh -> dash

# bashもちゃんとあります
$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1021112 May 16  2017 /bin/bash

CircleCIから外部にsshしたい

CircleCIの公式のドキュメントだと以下のようになっています

参考URL: https://circleci.com/docs/2.0/configuration-reference/#add_ssh_keys

config.yml
steps:
  - add_ssh_keys:
      fingerprints:
        - "b7:35:a6:4e:9b:0d:6d:d4:78:1e:9a:97:2a:66:6b:be"

ちなみに。上記のfingerprintを書いても失敗した気がします
やっていることは .ssh/ にfingerprint名で暗号鍵を置いているだけです

shell
# イメージ

$ ls ~/.ssh/id_rsa_*
/home/circleci/.ssh/id_rsa_b735a64e9b0d6dd4781e9a972a666bbe

# `id_rsa_` 以降がfingerprintsから `:` を抜いた文字列になっている

以下のようにすればsshできます。sshする際に鍵を指定しなくてもいいみたいです。

config.yml
steps:
  - add_ssh_keys
  - run: ssh < domain name or IP Address >

外部からCircleCIのインスタンスにsshしたい

CircleCIのWebサイトにアクセスし、実行済みのJobにアクセス、
右上のプルダウンを押し Rerun job with SSH でJobを起動します。

スクリーンショット 2018-12-06 20.36.57.png

ターミナル (shell) で $ ssh -p XXXXXXXX:XXXX を実行

スクリーンショット 2018-12-06 20.38.56.png

ちなみに、公開鍵はCircleCIと連携させているGitHub/BitBucketアカウントに登録されているものを使っているみたいです
なので、sshしたときに聞かれるパスワードはGitHub/Bitbucketからgit cloneをするときに聞かれるパスワードと同じです

プルダウンが出てこないときは、連携しているサービスに公開鍵が登録されていない可能性があります

pythonのライブラリ依存のエラーが突然起きる

これが一番やっかいでした・・・

例えば、以下のような場合

config.yml
    - run:
        name: Install python module and awsebcli
        command: |
          sudo apt update && sudo apt install -y python-dev python-pip
          pip install awsebcli --upgrade --user

pip install するとライブラリの依存でインストールできないというエラーがでることがあります
Jobの実行に使っているのがコンテナなら、Dockerhubでコンテナのタグを探し、以下のように設定すればOKです

config.yml
    docker:
      - image: ubuntu:14.04

タグが latest でなければ、中身のライブラリのバージョンが変わることはないと思います

ちなみに、machineもバージョン指定が可能です ( pythonのバージョン管理には何度泣かされたか・・・ )

config.yml
jobs:
  build:
    machine:
      image: circleci/classic:2017-01

ちなみに以下のように、ライブラリのバージョンを固定してもOKです

shell
pip install awsebcli==3.14.5 --upgrade --user

machine executor だと pythonのバージョンがデフォルトで2系になっている

machine executor は shell scriptを使ってライブラリをインストール管理しているらしいです

参考URL: https://circleci.com/docs/2.0/vm-service/#customization

ちなみにGitHubではこんな感じで Python 2.7.11 がデフォルトバージョンになっています。

Dockerfile
ADD circleci-provision-scripts/python.sh /opt/circleci-provision-scripts/python.sh
RUN circleci-install python 2.7.10
RUN circleci-install python 2.7.11
RUN circleci-install python 3.4.3
RUN circleci-install python 3.5.1
RUN sudo -H -i -u ubuntu pyenv global 2.7.11

最終的に pyenv global 2.7.11 となっているので、 3系を使いたい場合は以下のようにします

config.yml
- run:
    command: |
      pyenv global 3.5.1

感想

いろいろと苦労を書きましたが、結果的にCircleCIはGitHubとの連携や各種APIが優れているので、すごく使いやすいです。
個人的には、GitHubをお使いであれば非常におすすめです!
ここまで、読んでいただきありがとうございました
また、CircleCIのアドベントカレンダーに参加できたことを光栄に思います

fnaoto
フリーランスのなんでもエンジニア
https://fnaoto.github.io/home
campfirejp
国内最大の流通を誇るクラウドファンディングサービス「CAMPFIRE」の企画・開発・運営を行うスタートアップです
https://camp-fire.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