VagrantのAnsible Local Provisionerの実行ユーザー

開発環境は、Vagrantで構築することが多くなりました。
Vagrantでは、Ansible Local Provisionerという機能があり、VMへのAnsibleのインストールやPlaybookに従って構成管理出来ます。
そう、Ansibleの実行時にハマりました。

要点だけ書くと、remote_userで実行ユーザーを指定しても、そのユーザーで実行されないのです。
例えば、以下のようなplaybookだと、systemdモジュールのところでエラーになります。(Boxはcentos/7

- hosts: all
  remote_user: root
  become: false
  tasks:
    - name: install epel-release
      yum:
        name: epel-release
        state: present
      become: true
    - name: update packages
      yum:
        name: '*'
        state: latest
      become: true
    - name: install yum-utils
      yum:
        name: yum-utils
        state: present
      become: true
    - name: install device-mapper-persistent-data
      yum:
        name: device-mapper-persistent-data
        state: present
      become: true
    - name: install lvm2
      yum:
        name: lvm2
        state: present
      become: true
    - name: add docker repo
      shell: 'yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo'
      args:
        chdir: '/etc/yum.repos.d'
        creates: docker-ce.repo
      become: true
    - name: install docker-ce
      yum:
        name: docker-ce
        state: present
      become: true
    - name: restart docker
      systemd:
        name: docker.service
        state: restarted
        daemon_reload: yes
        enabled: yes
      changed_when: false
      become: true

remote_userでrootを指定しているので成功するように思ってたんですが、これじゃダメでした。
これだ!っていう情報が見つからなかったですが、何を指定しようとvagrantユーザーで実行されます。
そのため、

  • sudoで実行する必要がある箇所にのみ、become: trueをつける
  • トップレベルでbecome: trueにし、sudoで実行する必要がないところだけbecome: falseにする

あたりが、落としどころこかなぁと思いつつ。

Alpineのパッケージ一覧

仕事ではDockerに触れる機会が余りないのですが、プライベートでは結構使っています。
Dockerを本格的に使うと、Dockerイメージのサイズ削減に勤しむことになるんですが、ベースイメージをAlpineにすることが多くなります。
Alpineだとパッケージが提供されておらず、自前ビルドする必要がある時が多いため、そのビルドに必要なパッケージが存在するのか確認したい時が多々あります。
そういう時は、Alpine packagesで必要なパッケージを探せます。

適当にコンテナ立ち上げて探した方が早いんですが、立ち上げられない時に利用する時には便利です。

BitbucketのプライベートリポジトリをCircleCIでビルドする時にハマった

楽できるCIツールないかなぁと探しているんですが、CircleCIをよく聞くので利用しようと思い、試してみました。

仕事でも使えればいいなぁと思い、実際に使ってみようとBitbucketのプライベートリポジトリで試したところ、ビルド結果が未ログインユーザーでも見れてしまうことが確認出来てしまいました。

ビルド結果が見える?

すでにCircleCIを利用している方などから話を聞いてみたのですが、「404 Not Found」とのことでした。
話を聞いた人がGithubのプライベートリポジトリを利用している方でしたので、Bitbucket特有の問題かなぁと思い、調査してみました。

本当に見えるのか

先に結論を言うと、設定ミスでした!すいません!

設定ミスというか初期設定が予期せぬ設定になっているのが、原因でしたね。
初期設定のままだと、何が問題だったかというと

  • 未ログインユーザーでビルド結果が閲覧可能(標準出力や.circleci/config.ymlが閲覧可能)
  • URLフラグメントの推測が容易なので、未ログインユーザーで成果物(artifact)が取得可能

結構ヤバそうですよね。
なんで、ちょっと注意点を。

何故、ビルド結果が見える?

Bitbucketについてだけ言っていきます。(Githubはならないという話ですし、Githubの有料アカウント持ってない)
Add Projectでリポジトリを選択すると、そのリポジトリがプライベートであろうとなかろうと、ビルド結果が見えるような初期設定になっているようです。
これは、Free and Open Sourceという設定が、初期でONになっているためのようでした。

そのため、プロジェクト追加後は、この設定を出来る限り早くオフにすることを推奨します。(ビルド結果を公開したい場合は除く)

最後に

ちゃんと設定を見て見つけておけば良かっただけですので、こういうことがないように出来る限り注意してきたいと思います…
リプライなどをくれた皆さん、ありがとうございました。

もし、Bitbucketのプライベートリポジトリを連携する時は、注意してくださいね!

Let’s Encryptの証明書を導入してみました

特に難しいこともなく、割りと簡単に導入することが出来ました。
すでに公開されているサーバーであれば、比較的簡単に導入出来ますし、Dockerで構築している方は、便利なイメージなども公開されているので探してみてくださいね。

本当にハマりどころ無かったのが逆に怖い

Devise関連のControllerの親クラス

BigQueryを使う仕事が、ちょっと暇になってしまったので、またRails周りの記事を少し。

Devise関連のControllerの親クラス

Ruby on Railsを使っている人達では有名なDeviseですが、その中で使われているControllerが何を継承しているのか追ってみます。(2017年7月19日 v4.3.0時点)

Devise::SessionsController

まずは、Deviseを使う時に必ず見かけると言っても過言ではないDevise::SessionControllerを見ましょうかか。
このクラスの定義はapp/controllers/devise/sessions_controller.rbになります。

先頭の数行を抜粋してみてみると、

class Devise::SessionsController < DeviseController
  prepend_before_action :require_no_authentication, only: [:new, :create]
  prepend_before_action :allow_params_authentication!, only: :create
  prepend_before_action :verify_signed_out_user, only: :destroy
  prepend_before_action only: [:create, :destroy] { request.env["devise.skip_timeout"] = true }

DeviseControllerを継承していますね。
それでは、次にDeviseControlelrの定義を見ましょうか。

DeviseController

このクラスの定義はapp/controllers/devise_controller.rbです。

こちらも抜粋。

# All Devise controllers are inherited from here.
class DeviseController < Devise.parent_controller.constantize
  include Devise::Controllers::ScopedViews

どうやら、DeviseControllerの親クラスは、Devise.parent_controller.constantizeで評価時に動的に決まっているようです。
それじゃ、このparent_controllerの中身は一体何なのでしょうか?

Devise

Deviseは、lib/devise.rbで定義されています。
こちらで、parent_controllerを探してみましょう。

では、抜粋!

  # The parent controller all Devise controllers inherits from.
  # Defaults to ApplicationController. This should be set early
  # in the initialization process and should be set to a string.
  mattr_accessor :parent_controller
  @@parent_controller = "ApplicationController"

はい、定義が見つかりましたね。
parent_controllerの中身は、ApplicationControllerという文字列のようです。
つまり、ApplicationControllerがDeviseControllerの親クラスでした。

そのため、ApplicationControllerで定義しているメソッドなどがDevise::SessionsControllerなどでも利用可能であり、コールバックを定義しているなら実行されてしまうわけです。

DeviseControllerの親クラスを変更する

こちらは、難しいこともないです。
抜粋したコード内のコメントを見てもらうと分かるのですが、initializerで変更することが可能です。

変える時は、以下をinitializerに追記してください。

config.parent_controller = 'OtherController'

簡単ですよね。

最後に

業務のRailsアプリでは、1つのアプリ内に管理画面とフロント画面のCMSを構築することも多いです。
となると、それぞれのApplicationControllerが定義されたりすることがあります。
そういう時にDevise関連のControllerの親クラスを意識せずに使用して、意図しない動作になりうることもあります。
今回は、その一例です。
Gemを利用する場合は、しっかり使う範囲だけで良いので、挙動を把握しておくといいかもしれませんね。

管理画面とフロント側を凄く分けたい…

SELinuxが有効なサーバーでSSHのポートを変更する

我が家のサーバーを入れ替えする時に、新サーバーのOSをSELinuxが有効なCentOS7に切り替えました。
SELinuxを触るのが久しぶりで、sshdのポートを変更する時にハマったメモ。

sshd.confを書き換える

いつも通り、sshd.confを書き換えて、ポートを変更します。

#Port 22
Port 22222

この状態で、sshdの再起動をしてもエラーが起きます。
エラーログを保存するのを忘れたので割愛。

semanageコマンドでポート解放

semanageというコマンドがあるらしく、これを利用してポートを解放します。

$ semanage port -a -t ssh_port_t -p tcp 22222

この後に、sshdを再起動すると、エラーなく再起動することが出来ます。

SELinuxは、開発用のVMだとすぐ切ってしまうので、これからは少しでも仲良くしていきたいと思いましたね。

普段使いはDiscord

仕事で使うチャットツールはSlackが多いのですが、プライベートではDiscordに完全移行しました。

Slackが用意している機能よりは不十分な方も多いかもしれませんが、投稿APIはSlack互換やGithub互換のAPIがあり、既存の外部サービスとの連携が容易であったり、グループ通話が簡単に出来る点で移行するきっかけになりました。
Mackerelの通知もちゃんと表示されます。

Discordを使い始めたのは、去年の7月ぐらいですね。
Tree of Saviorというオンラインゲームを始めた頃ですね。

ゲームやってる人は、Discordも念頭に入れてみるといいと思います。

Digdagでbundle install

最近は、Digdag+Embulkでデータ収集する仕事しています。

普段からRubyを使う機会が多いので、遅かれ早かれRuby APIを使うことになるのですが、スクリプトを書くとなると、それなりのロジックを組み込む時があります。
そういう時、車輪の再発明は面倒なので、公開されているGemを使って書きたい。
DigdagはJRubyではなくrubyコマンドを実行しているだけなので、bundle installが発行さえできればよい。(そのためRubyが実行できない場合は使えない)
いくつか手法があり、こういう記事がヒットします。
が、もっとシンプルにいきたい。
それならシェルで実行しようという考えにいきつきます。

プロジェクト内にGemfileとGemfile.lockを含めて、digdag push
後は、Digdagに以下のようなタスクを追加する。

+bundle_install:
  sh>: bundle install

複数のプロジェクトが同時に実行されたらエラーが出ると思いますが、現状はこれで。
もっと良い方法があれば、是非教えてほしい。

心機一転

今年の2月から4月まで、仕事のストレスで休職していました。
心機一転するためにも、サイトも自分に負担が少ない形まで戻していこうと思い、このような形になりました。

技術的なことも書くでしょうが、あくまで個人ブログとしてやっていきます。
皆さんも、ちょっと疲れたら休んでいいんだからね。