2017新卒に捧ぐ!俺の開発環境!!

こんにちは、奥村です。

今回のエンジニアブログも前回に引き続き「新卒に捧ぐ!俺の〇〇」シリーズです (前回の記事はこちら↓)

blog.engineer.adways.net

第三回のテーマはタイトルの通り

「新卒に捧ぐ!俺の開発環境」

です。

新人エンジニアにとって開発環境を準備するのは、どんな環境を用意したら良いのか悩んでしまうことが多いですよね。

本記事では2人のエンジニアがどのような環境で開発しているかを紹介しています。 是非参考にしてみてください。

  • 一人目:メインでscala、たまにHTML,javascriptを扱っている(古川)
  • 二人目:ruby on Railsで開発を行なうことがメイン(足立)

一人目

こんにちは、古川です。PCはMacbook Proをつかっています。

入社して以来色々な言語をさわってきましたが、最近はScala、たまにHTMLやJavascriptを使ってサービスを開発しています。

■ エディター

  • Scalaの開発の場合

他の言語はいくつか選択肢あると思いますが、Scalaに至ってはIntelliJ IDEA一択かと感じています。

なぜなら、補完機能やリファクタリング機能・デバッグ機能などが充実しているからです。

IntelliJ IDEAにはCommunity版とUltimate版がありますが、Scalaメインの開発だけならCommunity版でも十分です。HTMLなどの開発もやりたいのならUltimate版にしたほうが良さそうです。

自分の場合は、WebAPIの開発が多く、HTMLなどを扱うことはそこまで多くないので、Community版で事足りてます。

また、必要に応じてプラグインを入れればDockerやShellスクリプトにも対応してくれるので個人的に便利だと思います。

  • HTMLやJavascriptの開発の場合

こちらは選択肢はたくさんありますが、個人的にはVisual Studio Codeがオススメでしょう。

Javascriptの場合は簡単にデバッグ実行ができますし、コードジャンプやリファクタリング機能も使えるので重宝しています。

■ 開発環境の整備

サービス開発をする際、MySQLやRedisなどミドルウェアを用意しておく必要があったので、かつては「仮想マシンを作り、ミドルウェアと必要なライブラリをインストール」そして他人に渡す場合は、「それをコピーする」なんてことをしていました。

しかし、つぎの問題があって開発がはばかられます。

  • 仮想マシン自体を立ち上げるとPCが重くなっていく
    • 特に複数プロジェクトに関わっていたときは、その分仮想マシンを立ち上げておかないといけなく、そのせいでCPUやメモリを食い尽くすわで、本当に大変でした
  • 仮想マシンをコピーしたとき、オレオレ設定を相手に強要させてしまうことはまだしも、下手すると必要以上の情報が他人に渡ってしまうこともある
  • 仮想マシンを使えば使うほど容量が大きくなるので、HDDを圧迫させてしまうだけでなく、他人に渡すのも時間がかかって大変
  • 仮想マシンの起動に時間がかかるのですぐに開発に取り掛かれない
  • Sambaなどのツールでホストとつなげておかないと、好きな開発環境で開発ができない

そこで最近はDockerを使って、サービス単位でミドルウェアの管理しています。

Dockerを使うことでコレくらいのメリットはあるので、開発環境の整備にはうってつけです。

  • ミドルウェアが必要になったときはコンテナを立ち上げたり落としたりすれば良くなるので、マシン環境を汚すことなくミドルウェアが簡単に扱える
  • 仮想マシンは立ち上げに数十秒以上はかかるものの、コンテナは立ち上がる速度もたったの数秒

さらにDocker Composeを使えば、プロジェクトごとに必要なミドルウェアをコードで設定できるので環境整備がかなり楽になるだけでなく、開発環境の切り替えも楽になります。

具体的には、サービスのプロジェクトごとにこんな感じにdocker-compose.ymlを定義しておき、

version: '2'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: eventapi
      MYSQL_USER: admin
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"

開発時には、このコマンドをうてばサービスに必要なミドルウェアは一発で立ち上がります。

docker-compose up -d

そして、違うプロジェクトの開発をしたい場合は、このコマンドでコンテナを落としておき、違うプロジェクトで同じようにコンテナを立ち上げるだけで良いです。

docker-compose down

なので、プロジェクトの切り替えに時間をあまりかかりません。

また、大体のミドルウェアはDocker Hubに公開されていますので、環境構築自体も時間はかかりません。

もし存在しないバージョンのミドルウェアやサービス専用のコンテナを作りたい場合は、(用意するまでは大変なものの)Dockerfileでコンテナイメージを作っておき、一度公開さえしておけば、他の人もすぐにそのコンテナイメージを利用できるようになります。

ただし、うちの場合は社外に公開したくないコンテナイメージもあるので、その場合は社内に立ててあるGitLabのリポジトリにアップロードしています。

■ その他

Macbook Proは熱くなると極端に重くなります。重くなると本当に仕事にならなくなるので、冷却台を使っています。

自分はこの冷却台を使っています。

冷却台を買う前は、ちょっと重いプロセスを走らせるとすぐカクカクになってしまいましたが、この冷却台をつかっているときは重くなることはだいぶ減りました。

冷却台は正直なんでも良いと思いますが、評判の高そうなものを選んだほうがいいと思います。


二人目

初めまして。社会人2年目エンジニアの足立です。

最近、開発環境をDocker Composeを使って構築するように変更して便利だったので紹介します。 便利な点としては

  • 誰でも同じ環境を作れる
  • テスト環境と同じ環境を準備できる
  • ローカル環境でのミドルウェアの管理が便利
  • 設定さえしっかりすれば、コマンド2つで開発環境が立ち上がる

等が挙げられます。

以下では、デモを通して、この便利な開発環境を手に入れる方法を紹介していきます。

デモのゴール

  • railsでresqueを使用し、workerでjobを回しlogに「HelloWorld」を出力されていることを確認する。

使用環境

Docker for Mac(version 17.03.1-ce-mac5)
docker-compose(version 1.11.2)

■ docker-compose関係のファイル

下記のコンテナを用意するため、

  • Dockerfile
  • Dockerfile-nginx
  • docker-compose.yml

を作成します
〜railsのプロジェクトは用意している前提で話をさせて頂きます。〜

コンテナ 詳細
datastore 永続化、共有したいパス設定
redis redisサーバー
nginx nginxサーバー
rails railsサーバー

・Dockerfile

RUN apt-get update && apt-get install -y vim locales --no-install-recommends && rm -rf /var/lib/apt/lists/*

RUN dpkg-reconfigure locales && \
        locale-gen C.UTF-8 && \
        /usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV TERM xterm
# END: ~~~~~ 日本語対応

RUN mkdir -p /usr/src/docker_compose_app
RUN mkdir -p /usr/src/docker_compose_app/tmp
WORKDIR /usr/src/docker_compose_app

COPY ./Gemfile /usr/src/docker_compose_app/Gemfile
COPY ./Gemfile.lock /usr/src/docker_compose_app/Gemfile.lock

RUN bundle install -j4

EXPOSE 3000

ENV RUN_AT_EXIT_HOOKS=1
ENV VERBOSE=1
ENV PIDFILE=./tmp/resque.pid
ENV TERM_CHILD=1
ENV QUEUE='resque_sample'

CMD bash -c "bundle exec unicorn_rails -c config/unicorn/docker.rb -E docker -D && bundle exec rake resque:work"

DockerfileでCMDが一つしか使えないのを知らなくて少し詰まりました。。

・Dockerfile-nginx

FROM nginx:1.11.0-alpine # Docker Hubからimageを持ってきます

COPY container/nginx/vh-site.conf /etc/nginx/conf.d/default.conf

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

・docker-compose.yml

---
version: '2'
services:
  datastore:
    build: container/datastore
    container_name: docker-test-container
  redis:
    image: redis:3.2.0 # Docker Hubからimageを持ってきます
    ports:
      - '6379:6379'
  nginx:
    build:
      context: .
      dockerfile: Dockerfile-nginx
    ports:
      - '8080:80'
    links:
      - rails
    volumes:
    - .:/usr/src/docker_compose_app
    - ./tmp/logs/:/var/log/nginx # ここでコンテナ内のlogをローカルの/tmp/logs以下にマウント
    volumes_from:
    - datastore
  rails:
    build: .
    ports:
      - '3000:3000'
    links:
      - redis
    environment:
      RAILS_ENV: docker
    volumes:
    - .:/usr/src/docker_compose_app
    volumes_from:
    - datastore

・container/datastore/Dockerfile

FROM busybox:latest

VOLUME /usr/src/app/tmp
VOLUME /usr/src/app/public/system

CMD /bin/sh

・container/nginx/vh-site.conf

upstream docker_compose_app {
  server rails:3000 fail_timeout=0;
}
server {
  listen       80;
  server_name  localhost;
  root /usr/src/docker_compose_app/public;
  location / {
    try_files $uri @webapp;
  }
  location @webapp {
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://docker_compose_app;
  }
  location ~ ^/(assets|uploads)/ {
    gzip_static on;
    gzip_types text/css text/js text/xml;
    add_header  Cache-Control public;
    break;
  }
  error_page 404 /40x.html;
  location = /40x.html {
    index 404.html;
  }
  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   html;
  }
}

Dockerfileのオプションの詳細は過去の記事に纏めてあるので下記を参照してください。
Docker Composeを使ってマイクロサービスを作ってみた

■ ファイルの削除・ファイル設定

今回はデータベースは使わないので不要ファイルは削除します

rm config/database.yml

config/application.rbのファイルの require 'rails/all' をコメントアウトし下記を追加し、

config.active_record.raise_in_transactional_callbacks = true こいつもコメントアウトします。

# config/application.rb

# require 'rails/all'

require 'action_controller/railtie'
require 'action_mailer/railtie'
require 'sprockets/railtie'
require 'rails/test_unit/railtie'

module DockerComposeApp
  class Application < Rails::Application
    # config.active_record.raise_in_transactional_callbacks = true
  end
end

config/environments/docker.rbconfig.assets.debug = false に変更します。

# config/environments/docker.rb

config.assets.debug = false # falseに変更

・Resqueの設定

mkdir workers
vim workers/hello.rb
class Hello
  @queue = :resque_sample

  def self.perform(msg)
    sleep 5
    logger = Logger.new(File.join(Rails.root, 'log', 'resque.log'))
    logger.info "HelloWorld!! [#{msg}]"
  end
end

・Rakeタスクを追加

lib/tasks/resque.rake

require 'resque/tasks'
task "resque:setup" => :environment

resqueの設定

config/initializers/resque.rb

require 'resque'
Resque.redis = 'redis:6379' # 環境に合わせて変更必要あり(docker環境のみならOK)

・Railsのルーティング設定

config/routes.rb

require 'resque_web'

Rails.application.routes.draw do
  mount ResqueWeb::Engine => "/"
  get '/resque_web' => redirect('/')
end

■ 開発環境の起動

docker-compose build ← このコマンドでimage作成
docker-compose up -d ← このコマンドでimageを使ってコンテナ作成 + 起動
docker ps ← 起動中のコンテナの確認

docker-compose build  
docker-compose up -d 
docker ps

f:id:AdwaysEngineerBlog:20170419114708p:plain

上記の画像のようにコンテナ

  • nginx
  • rails
  • redis

のコンテナ3台が立ち上がれば成功です。

今のままだとprecompileが通ってないので下記のコマンドを叩いてprecompileを行いrails再起動します。

docker-compose run rails rake assets:precompile && docker-compose restart rails

これで localhost:8080 にアクセスするとResqueのページが無事に表示されるかと思います。

f:id:AdwaysEngineerBlog:20170419115057p:plain

これでようやく準備ができました。
コマンドラインでjobを生成してredis::workerが動くか確認していきましょう。

#jobの生成
docker-compose run rails bundle exec rails runner 'Resque.enqueue(Hello, "hogeee")'[f:id:AdwaysEngineerBlog:20170419114708p:plain]

f:id:AdwaysEngineerBlog:20170419115112p:plain 動いていますね!

ログを見てみましょう

tail -f log/resque.log

f:id:AdwaysEngineerBlog:20170419115125p:plain

しっかりと「HelloWorld!!」が表示されていますね!

ハマりポイント

Already running on PID:14 (or pid=/usr/src/docker_compose_app/tmp/unicorn.pid is stale) (ArgumentError)

このエラーを初めてみたときは、コンテナ立ってないんだから入れなくない??っとパニクりましたが先輩に聞いて解決しました。

上記のエラーが出たら

#コンテナの中に入る
docker-compose run コンテナ名(rails) bash
# ゴミファイルを削除する
rm tmp/unicorn.pid
# railsコンテナを起動させる
docker-compose start rails

まとめ

新しくチームにジョインする人も簡単に開発環境を手に入れられるのがdocker-composeの強みだなと感じています。
( dockerコマンドの学習コストはありますが。。

以上です。ありがとうございました。


以上になります。今の内から開発環境にこだわっておくとあとあと楽になると思います。
色々試して自分が使いやすいものを選択できるようになると良いですね!