Docker for MacをやめてVM(Ubuntu 16.04)の中でDockerを動かして開発する

はじめに

どうも@konchanSSです。今回はDocker for Macをやめて、VMを立ててその中でDockerを動かして開発を進めた話をしたいと思います。

なぜDocker for Macやめたのか

  • Docker for Macのvolumeのマウントが重い  
  • マウント遅い問題を解決するためにDocker syncを導入したが、同期が不安定

Dockerにdocker-syncを導入して遅い問題を解決する - こんちゃんブログ

準備

今回VMの環境を構築するのにVirtualBoxVagrantを使用するのでインストールしていきます。

Downloads – Oracle VM VirtualBox

Download - Vagrant by HashiCorp  
 

VM(Ubuntu 16.04)設定のセットアップ

まずはVM用のディレクトリを用意しましょう。
先ほどいれた vagrant コマンドを使ってインスタンスの初期化と生成をします。

$ vagrant init bento/ubuntu-16.04
$ vagrant up

上の vagrant init をしたディレクトリに Vagrantfile が生成されます。
ゲストOSの設定はここに書いて再起動することで反映されるようになります。

インスタンス立ち上げ際のはまりポイント
ホストとゲスト間のGuestAdditionsのバージョンが違うとVMの起動やSSHできないことがあるので vagrant vbguest 入れておくと便利です。
詳しくはこちらの記事がわかりやすいので詰まった方は読んでみてください。
 
qiita.com
また、もともとVagrantもしくはVirtualBox使ってたよって人はバージョンが違うと怒られが発生したりするので最新のやつを入れときましょう。  

GUIとデスクトップ環境の設定

Ubuntu GUIも必要なのでその設定を追加していきますが、 生成されたVagrantfileにはあらかじめGUIなどの設定がコメントアウトされた状態であるのでそのコメントアウトを外しましょう。

 config.vm.provider "virtualbox" do |vb|
   # Display the VirtualBox GUI when booting the machine
   vb.gui = true

   # Customize the amount of memory on the VM:
   vb.memory = "1024"
 end

 
あとは vagrant ssh コマンドを使ってVMの中に入り、Ubuntuのデスクトップ環境をインストールしましょう。

$ vagrant ssh
$ sudo apt-get install ubuntu-desktop

 

Ubuntu大地に立つ

以上の設定が一通り終わったら再起動して動かしてみましょう。

$ vagrant reload
$ vagrant up

 

UbuntuにDockerを入れる

Ubuntuを起動することがあとはDockerを入れるだけですね。
 
必要なパッケージのインストールします。

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates

 
GPG鍵の取得します。(これないとapt-get updateできなくなる)

$ sudo apt-key adv \
               --keyserver hkp://ha.pool.sks-keyservers.net:80 \
               --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

 
依存パッケージのインストールします。

$ sudo apt-get update
$ sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual

 
sourceの更新します。

$ echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list

 
これでdockerのインストール準備が整ったのでインストールしていきます。

$ sudo apt-get update
$ sudo apt-get install docker-engine

 
apt-get update 忘れるとうまくいかなかったりするのでコマンド叩いてみてください。

これでインストールが終わると docker コマンドが使えるようになっています。

vagrant@vagrant:~$ docker

Usage:  docker COMMAND

A self-sufficient runtime for containers
...

毎回docker叩く時にsudo打つのめんどくさい

グループに追加しておきましょう。

$ sudo usermod -aG docker $USER

最後に

これであとは好きなエディター入れたりして開発進めていけそうです!
本当はDocker for Macが快適に使えるようになると良いんですけどね〜

Dockerにdocker-syncを導入して遅い問題を解決する

はじめに

どうもこんちゃんです。最近開発環境にDockerを使用するようになって、いざ使ってみるとdocker for Macだと同期がクソ遅い問題(ページのロードで20秒)が発生してイライラしてたのが、docker-syncの導入で遅い問題が解決されたのでそれについて話していきたいと思います。
 

docker sync

docker sync はホスト側のファイルを rsyncunison もしくは native_osx を使って転送するという仕組みを導入しています。なので、重たくなる原因でもあったホスト側のディレクトリをマウントしていません。 github.com  

いざ導入

 

インストール

公式によるとこれだけ gem install docker-sync  

docker syncの設定を追加する

下記の docker-compose.yml を例に設定を進めていきます。  
docker-compose.yml

 version: '2' 
 
 services: 
    app: 
     image: test
     volumes: 
      - $DEV_DIR : /var/dev 
     command: yarn build:dev 

 
まず、docker-sync.yml というファイルを追加します。 わかりやすくするためにdocker-syncの設定は docker-sync.yml書いていきますが、docker-compose.yml 自体に書いていくこともできます。
僕の周りではDockerをLinux仮想環境を自分で用意してその中で動かしている人も一定数いたため、
既存の人は既存のまま使えるようにdocker-compose.yml はそのままにDockerの上書き用のymlである docker-compose-dev.yml に設定を追加していきます。  
docker-sync.yml

 version: '2' 
 
 syncs: 
   sync-volume:
    src: $DEV_DIR
    sync_strategy: native_osx
    sync_excludes: [ '.git', '.idea', '.vagrant' ]

 
docker-sync.yml では、まず src でホスト側のディレクトリを指定します。 sync_strategy では同期方法を選択できます。今回は native_osx という方法を選択しました。 native_osxUnison とDocker用のファイル共有システムである OSXFS の組み合わせです。 sync_excludes では同期しないファイルもしくはファイル形式を配列で渡すことができます。指定されたファイルもしくはファイル形式は同期対象外になります。
* sync-volume は任意の名前で構いませんが、ここでの名前がDockerの名前付きvolumeとして作られます。  
docker-compose-dev.yml

 version: '2' 

 volumes: 
   sync-volume:
    external: true
    services:
     app:
     volumes:
      - sync-volume:/var/dev 

 
docker-compose-dev.ymlでは、docker-sync側で作るvolumeexternal として宣言し、それを sync-volume:/var/test としてマウントするように設定しています。
設定は以上になります。
 
 

とりあえず動かしてみようぜ

設定追加できたらとりあえず動かしてみましょう。  
docker-sync-stack start で動きます。
 
内部的にやっていることはdocker-syncを起動してupしてるだけらしい  
内部的にはこういうこと

docker-sync start 
docker-compose -f docker-compose.yml -f docker-compose-dev.yml up 

2.2 sync stack commands · EugenMayer/docker-sync Wiki · GitHub
 
 

ここで指定している -f オプションが先ほど言っていた上書き設定のオプションで、ここでファイルを複数指定すると指定された順番に設定を反映します。 なので docker-compose.yml -> docker-compose-dev.yml という順番に設定を反映していきます。 同じ設定があった場合は後に反映された設定が前の設定を上書きされるようになります 。
このあとこの上書きした項目の1つが原因でえらいことになる  
 

動かしてみると...

実際に動かしてみると 20秒ぐらいだったページのロードが1秒ぐらい になりました。やっほー!めっちゃ快適やんけーって思いながら開発を進めていると.....
 
ファイルの変更が反映されてないぞ という問題が発生しました。実は先ほど上書きした設定の中に問題の原因が隠れていました。 それは volumeの設定です 。
下記のissueコメントなどを参考に話をしていくと、どうやらupしたymlが複数指定されていると volume は上書きされないっぽい。

Your issue is, that you think you can override volume defintions, but you cannot. So ${SYMFONY_APP_PATH}:/var/www/symfony stays in charge and supersync-sync:/var/www/symfony:nocopy never gets used.
 

github.com  

volumeオーバーライドされない問題を解決しよう

ここでvolumeをオーバーライドされない問題を解決する手段は2つあります。
そもそも、ymlの設定を複数に渡ってせずに docker-compose.yml に統一してしまう。もしくは、 volumes の設定を他の設定ファイルに切り出すことです。 今回は後者の volumes の設定を切り出すことを選択しました。(先ほどにもあげたようにdocker-syncを使わなくても良いユーザも一定数いるため)  

Dockerにはデフォルト上書きしてくれるymlファイルがある

では、volumes の設定をどこに書くのかというと、Dockerではデフォルトで2つのファイルを読みます。 それは docker-compose.ymldocker-compose.override.yml です。 今回はこの docker-compose.override.ymlvolumes を切り出しました。  
docker-compose.override.yml

 version: '2' 

 services: 
  app: 
   volumes: 
    - sync-volume:/var/dev 

 
これでdocker-syncを使わない人と使う人で特に意識することなく利用できそうです。  
サービスの拡張と Compose ファイル — Docker-docs-ja 17.06.Beta ドキュメント

追記(2018/7/5)

volumeオーバーライドされない問題はどうやら解決されたらしいです。(下記issue参照)

Docker Compose 1.17 fixed volumes override 🕊 · Issue #507 · EugenMayer/docker-sync · GitHub

しかし、同時に同期が安定的でないというissueもあります。 僕の方でも同期がうまくいかないという場面が度々見受けられました。 とりあえずこの問題が解決次第また記事に追加していこうと思います。

Synchronization stops. · Issue #517 · EugenMayer/docker-sync · GitHub

IntelliJで利用するReact Nativeのスニペットを作った

こんにちは、こんちゃんです。 今日はReact Nativeのスニペットを作ったのでその紹介をしたいと思います。

早速紹介

IntelliJで毎回Componentの定義書くのめんどくさいですよね。ということでスニペット作成しました。

github.com

最後に

まだReact Native書き始めたばかりなので後からどんどんスニペット更新していこうと思います。

React NativeにFlowを導入する

こんにちは、こんちゃんです。

最近React Nativeを書き始めて、その中でFacebook製の静的解析ツールであるFlowを導入した時の話をしようと思います。

はじめに

React NativeでFlowを選んだ理由としては導入のしやすさとメルカリの記事を見たからでした。

speakerdeck.com

環境 2018/3/8現在

react-native ver 0.54.0

yarn ver 1.5.1

flow-bin ver 0.66.0

いざ導入

公式のドキュメントを見てやれば余裕やろ(鼻ほじ)って思ってました。

flow.org

ドキュメントに従って yarn run flow (タンッ!) って打つと大量のエラーが押し寄せてきました。

f:id:kazumasaSS:20180308155657p:plain

なんじゃこれーーって思って見ると node_module が解析対象内になっていたらしくそこでエラーが出ていました。
とりあえず、node_moduleを解析対象外にするために .flowconfig内の[ignore]セクションの設定をしました。

[ignore]
.*/node_modules/.*

これで大丈夫かと思ってもう一度走らせて見るとまた別のエラーが。。。

f:id:kazumasaSS:20180308151718p:plain

node_moduleを解析対象外にしたせいでreact-nativeのモジュールが見つからないと言われてしました。

解決策

まず、libdefs.jsというファイルを作成しましょう

touch libdefs.js

libsdef.jsでは必要なライブラリの定義を行います。

declare module 'react-native' { declare module.exports: any; }

そのあとは.flowconfig内の[libs]セクションに設定を追加します。
.flowconfigファイルの[libs]セクションは、コードの型チェック時に指定されたライブラリ定義をインクルードします。
また、libdefs.js自体は静的解析の対象にしたくないので[ignore]セクションに追加します。

[ignore]
.*/node_modules/.*
./libdefs.js

[libs]
./libdefs.js

これで yarn run flow を走らせると

f:id:kazumasaSS:20180308160356p:plain

今度はうまくいきました。 次回以降ではReact Nativeで開発していく上での困ったことやTipsを記事にできればと思っています。

内定先のインターンでTAをしてきた話

今日は内定先で行われたインターンでTAをしてきたのでTA業で思ったことについて書いていきたいと思います。 読者が今度どこかのイベントなどでTAなどをするときに参考にしてもらえると幸いです。

はじめに

僕は内定先であるVOYAGE GROUPで行われるTreasureというインターンに参加してきました。 Treasureは「Go言語を使って学ぶ、価値のあるもの創りとチーム開発」をテーマとして3週間でユーザーにとって価値あるサービスをトップエンジニアのサポートを受けつつ開発します。インターンについての詳しいことは下記のリンクに書いてあるので割愛します。 今回僕はTreasureの中でも前半8日間で行われるトップエンジニアによる講義のTAをしてきました。僕自身去年のTreasureに参加しています。 TAとして参加したのも去年の経験からTreasure参加生にとってかけがえのない経験をするサポートをしたいという思いがあったからというのもあります。 voyagegroup.com

基本的な業務内容

TAとしての基本的な業務は前半に行われる講義の内容に関して参加者がわからないところがあった場合や演習の際に詰まったときにサポートをして参加者が滞りなく講義を受けれる状態にすることです。

講義について

Treasureの講義内容としては

1日目 ~ 3日目 Goの講義 by @suzu_v

4日目 Web APIの講義 by @gomachan46 @brtriver

5日目 中間課題

6日目 中間課題の発表、セキュリティの講義 by @co3k

7日目 データベースの講義 by @hironomiu @larufa @takeru0911

8日目 チーム開発の講義 by @katzchang @ara_ta3

となっています

Web APIの講義は公開されています speakerdeck.com

わからなくてもなかなか質問できない子がいる

Treasureの参加者には様々なバックグラウンドの人がいるので、人によってスッと理解できる子もいれば初めて聞く内容だという子もいます。 こちらとしてはわからなかったら気軽にTAに質問してくださいと言っていますが、なかなか質問できない子はいます。また、わからないことがわからないという子も一定層いるのでそういう子たちが置いていかれないようにTAがサポートしてあげる必要があります。具体的には

参加者に「今何してるの?」って声をかけてみる

定期的に参加者のことを見回るのもいいのですが、参加者が警戒していて質問できない場合もあるのでこちらから警戒をといてあげるという意味で気軽に声をかけてみると意外と詰まっていたりします。

わからなくても一緒に悩んで解決方法を探す

TA自身も人なので質問された内容全てに対して答えられない場合もあると思います。そういう場合はわからないと突き放すのではなく、質問者と一緒に調べたり、解決策を探ることで少しでも質問者の不安を解消してあげましょう。 相談に気軽に乗る姿勢 ってすごい大事だと思いました。

講師に参加者の状況を報告する

講義を受けている人数が多いとどうしても参加者側からの反応が薄かったりするので、TAが講師にどのくらい参加者が理解しているかなどを都度報告してあげることで講義がより良いものになると思いました。また、前もってTAには次の講義内容を伝えておくことで講義全体を把握しつつ、詰まりそうなポイントがわかるのでサポートしやすく講義がスムーズになるのではないかと思いました。

さいごに

色々ありましたが、Treasure参加生にとって最高の3週間になって欲しいです。また、今後Treasureに応募しようとしている人も、僕たちVOYAGE GROUPのクルーは参加者にとってかけがえのない経験になるよう全力を尽くしているので是非受けてみてください。

SupervisorでGolangで書かれたアプリケーションのデーモン化をした話

今回は前回の記事に関連してGoで書かれたアプリケーションをSupervisorを使ってデーモン化した時の話を書いていきたい思います。

はじめに

開発環境

  • CentOS 7.3
  • Go 1.8
  • Supervisor 3.3.3

前提条件

Goのアプリケーションがデプロイされている、 go build したバイナリがある

Supervisorとは

そもそもSupervisorってなんぞや?っていう人もいると思うので説明します。
Supervisorはpythonで書かれているプロセス管理ツールです。
Supervisorは設定ファイルをちょこっと書くだけで簡単にデーモンプロセスの生成ができるのでとても楽です。

Supervisor: A Process Control System — Supervisor 3.3.3 documentation

インストール

yumでインストールしておきましょう
yum install supervisor

設定ファイルに新しく追加する

Supervisorがinstallされると /etc/supervisord.conf が作成されています。これが設定ファイルなので編集していきましょう。
設定ファイルの中にはsupervisor自身の設定も含まれています。
早速ですが、これが完成形です。詳しい内容については後述していきます。
※ 今回はSupervisor自身の設定は省きます。

;/etc/supervisord.conf
[unix_http_server]
file = /run/supervisor.sock
chmod = 0777
chown= root:root

[supervisorctl]
serverurl = unix:///run/supervisor.sock

[supervisord]
logfile=/var/log/supervisor/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=true
minfds=1024
minprocs=200
user=root
ehildlogdir=/var/log/supervisor/

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

; Goアプリの設定
[program: sample]
command=sample-go-app
autostart=true
autorestart=true
user=sample-user
startsecs=5
redirect_stderr=true
stdout_logfile=/var/log/sample-go-app.log

[program:]
アプリをデーモン化する際はこのprogramセクションを使用します。

command
ここで設定したコマンドが起動時に実行されるようになります。
Goはビルドするとそれ自体で実行可能なバイナリになるのでここではバイナリを指定します。

autostart
Supervisor起動時に自動的にprogramセクションが起動するように設定できます。

autorestart
プロセスが死んだ時にSupervisorが自動的に再びプロセスを立ち上げるように設定できます。

user
programセクションを実行するユーザーを指定することができます。

redirect_stderr
エラー出力を標準出力にリダイレクトできます。

stdout_logfile
標準出力のログをファイルを指定することで保存できます。

Supervisorを起動してみる

設定を追加し終わったら次は実際に起動してみましょう。
supervisord を叩くと起動することができます。
もし、本当に起動しているのか確認したい場合は supervisorctl を叩くと確認することができます。

Supervisor自身の自動起動設定

最後にSupervisor自身を自動起動できるようにしましょう。
ありがたいことに起動時のスクリプトを書いてくれている方がいたのでこれをcloneしてきてコピーしましょう

git clone git://github.com/Supervisor/initscripts.git
cd initscripts/
cp redhat-init-jkoppe /etc/init.d/supervisord
cp redhat-sysconfig-jkoppe /etc/sysconfig/supervisord
chkconfig --add supervisord
chkconfig supervisord on

github.com

Golangで書かれたWebアプリをWerckerでVPSにデプロイした話

今回はGoで書かれたWebアプリケーションをWerckerを使ってビルドとデプロイをしたのでその時のWerckerのデプロイ設定などについて書いていきたいと思います。

はじめに

開発環境

前提条件

  • Githubで開発しているリポジトリがあること
  • すでにWercker側でApplicationの作成をしていて、PushするとBuildフェーズが通るようになっていること

Werckerの全体像

WerckerのPipelineという概念があります。 下記画像のようにBoxという仮想環境の中でBuildフェーズとDeployフェーズが順番に実行され、その中でstep と呼ばれる個別の処理で発生します。
今回はmasterにpushされたタイミングでBuildフェーズとDeployフェーズが実行されるように設定します。

f:id:kazumasaSS:20170615124847p:plain

Wercker側でDeployフェーズの追加

werckerのアプリケーションのページに移動します。 開くとWorkFlowsというタブがあるのでそれを選択します。

f:id:kazumasaSS:20170615123440p:plain

続いて選択して移動したページにAdd new pipelineと書いてあるボタンがあるので選択します。

f:id:kazumasaSS:20170615123441p:plain

新しいpipelineのNameを入力します。今回はDeployフェーズの追加なので deploy と入力しましょう。 YML Pipeline Nameも同様で良いです。
Hook Typeですが、今回はBuildフェーズが通った後にDeployフェーズを実行するため Default を選択しましょう。 f:id:kazumasaSS:20170615124319p:plain 必要な項目を全て入力したら Create しましょう。
作成すると下記画像のようにdeployが追加されるので確認してみてください。

f:id:kazumasaSS:20170615133437p:plain

秘密鍵の設定

VPSにログインするために秘密鍵の設定をする必要があります。先ほどの画像の deploy をクリックして詳細のページに飛びます。
詳細のページに移動すると Generate SSH Keys というボタンがあるのでそれを押すと秘密鍵の生成ができます。

f:id:kazumasaSS:20170615123446p:plain

鍵の名前は自由でいいのですが、今回は DEPLOY_KEY とします。 RSAですが、2048と4096がありますが、どちらでも構いません。

f:id:kazumasaSS:20170615133937p:plain

Create を押すと公開鍵と秘密鍵のペアがこのように生成されます。
DEPLOY_KEY_PUBLIC は後でVPSの方で鍵を設定するのに必要なのでコピーしておきます。 f:id:kazumasaSS:20170615134741p:plain

VPS側の設定

VPSの方にSSH接続し、今回Deployする用のユーザーを作成します

#今回はdeploy用のユーザーはwerckerとします
$ adduser wercker

# wheelグループにwerckerを追加
$ gpasswd -a wercker wheel
$ su - wercker
$ cd ~/
$ mkdir .ssh

# ここで先ほどコピーした公開鍵を貼り付ける
$ vi .ssh/authorized_keys
$ chmod -R 700 .ssh
$ chmod 644 .ssh/authorized_keys

# deploy用のディレクトリの用意
$ mkdir /srv/rsync
$ chmod 755 /srv/rsync

これで一旦VPS側の設定は終わります。

wercker.ymlにDeployフェーズを追加

次にwercker.ymlを編集していきます。

box: golang
build:
    steps:
        - setup-go-workspace
#何かしらの処理(今回はBuildフェーズの詳細については省きます)

deploy:
  steps:
# デプロイするファイルの表示
    - script:
        name: deploy info
        code: find .
# VPSのIPもしくはドメインを入力しましょう
    - add-to-known_hosts:
        hostname: IPアドレスもしくはドメイン名
#ここでは先ほど登録した鍵の変数名を入力しましょう
    - add-ssh-key:
        keyname: DEPLOY_KEY

# 今回はrsyncというファイル同期ができるコマンドを使って転送します
    - install-packages:
        packages: rsync

# 転送
    - script:
        name: rsync
        code: rsync -azvv --delete -e "ssh -v -o StrictHostKeyChecking=no -o UserKnownHostsFile=no" $WERCKER_ROOT/* wercker@ IPアドレスもしくはドメイン名 :/srv/rsync

以上でwercker.ymlの設定は終了です。

Buildフェーズが通ったらDeployフェーズが実行されるようにする

これまででほとんどの設定は終了しました。あとはBuildフェーズ後にDeployフェーズが実行されるようにすればいいだけです。
もう一度アプリケーションのページから WorkFlows のページに飛んでください。 WorkFlowsのページから下記画像のように+ボタンを押してpipelineを追加することができます。
これはWorkFlowと言って1つのCIのプロセスを複数のパイプラインに分割することのできる機能です。これを使ってbuildフェーズの後にdeployフェーズの追加をしてあげます。
on branch でDeployフェーズが実行されるブランチを決めることができます。今回はmasterにします。
Execute pipeline はdeployを選択しましょう。 f:id:kazumasaSS:20170615141419p:plain

これでGithubからmasterにpushされたらdeployされるようになりました。

追記

デプロイ用に作ったユーザーのロックされているとデプロイできないです。

passwd -S デプロイ用のユーザー

passwdコマンドでユーザーがロックされていないか確認して見ましょう