20201115のdockerに関する記事は23件です。

Ruby on Railsの開発環境をDockerで構築する方法(Rails 6.x)

Docker公式手順を参考に、Rails 6系で Dockerの開発環境を構築する手順を詳解します。

各コマンドの詳しい解説は私が以前に書いた Rails5系での手順 で解説しているので、本記事では割愛します。

ファイルの準備

作業用のディレクトリを作成し、以下の 5 つのファイルを作成します。

  • Dockerfile
  • docker-compose.yml
  • Gemfile
  • Gemfile.lock
  • entrypoint.sh
FROM ruby:2.7.0

## nodejsとyarnはwebpackをインストールする際に必要
# yarnパッケージ管理ツールをインストール
RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn

RUN apt-get update -qq && apt-get install -y nodejs yarn
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

RUN yarn install --check-files
RUN bundle exec rails webpacker:compile

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"
    volumes:
      - ./tmp/db:/var/lib/mysql

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
source 'https://rubygems.org'
gem 'rails', '6.0.3'
Gemfile.lock(空ファイル)
```entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

Rails プロジェクトを作成

$ docker-compose run web rails new . --force --no-deps --database=mysql

コンテナをビルド

$ docker-compose build

データベースファイルの修正

上記実行後、config/database.yml ファイルを下記の通りにまるっと修正します。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  host: localhost

development:
  <<: *default
  database: myapp_development
  host: db
  username: root
  password: password

test:
  <<: *default
  database: myapp_test
  host: db
  username: root
  password: password

データベースを作成

$ docker-compose run web rails db:create

Webpackerをインストール

Rails 6系から Webpacker が必要となっているため、webサーバのコンテナにwebpackerをインストールします。

$ docker-compose run web rails webpacker:install 

docker-compose でコンテナを起動

$ docker-compose up -d

アクセスして起動を確認

ブラウザから localhost:3000 にアクセスし、Rails の初期画面が表示されることを確認しましょう。

image.png

コンテナを停止

検証を終え、コンテナを停止させるときも docker-compose を使います。

$ docker-compose down
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-composeでコンテナが立ち上がらない

(余談)dockerを初めて触り、導入しました。

初学者にはネットワーク基礎からの知識が必要になり、かなり苦戦しました。
まず、docker導入にあたり、学習した書籍を紹介します。

  1. キタミ式イラストIT塾 基本情報技術者 令和02年 Kindle版
  2. [試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識 Kindle版
  3. Docker/Kubernetes 実践コンテナ開発入門 Kindle版
  4. (こちらはサイト)入門 Docker https://y-ohgi.com/introduction-docker/

docker-composeでコンテナが立ち上がらない

コンテナ環境 
-macOS catalina 10.15.7
-Docker version 19.03.13
-docker desktop version 2.4.0.0
rails+nginx+unicorn+mysql環境構築を試行錯誤で何度もコマンドを打っているうちにバックグラウンドに使っていないデータが溜まっていた事が原因でした。

special thanks>>
環境構築はこちらの記事を参考にしました。
https://qiita.com/E6YOteYPzmFGfOD/items/509dbabeb20bf2487283
https://qiita.com/AK4747471/items/39ddacfde6a235103277

打ったコマンド
docker-compose build(イメージ作成)
docker-compose up(コンテナ作成、実行)
docker-compose down --volumes(コンテナ削除、docker外で指定した保存ファイルのデータも同時に削除)
docker desktopでイメージをアイコン選択で削除

解決法

以下コマンドでは、可動していないものも含め全てのDockerイメージを削除します。
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
docker rmi $(docker images -q)
https://qiita.com/suzy1031/items/1b4e1d717b6052a02307

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

はじめてDockerを触ってみた

こんにちは。むんです:grinning:
次案件でDockerを使う事になったので、すこし触ってみました。
自分用の備忘録として書いてますが、この記事が少しでもはじめてDockerをさわる方の役に立てば嬉しいです!
記事の内容に関して間違いや、こうした方がいい等のアドバイス等ありましたら、気軽にコメントください:sunny:

では、はじめて参りましょう!

※前提
・使用PC:Mac

予備知識や関係することなど。

下記記事ご参照ください。

目次

  • Dockerって何?
  • Dockerインストール
  • イメージの取得、コンテナ起動

Dockerって何?

ざっくり言うと、元々あった仮想マシンの「重い」と言う問題を解決するために生まれたのがコンテナ型仮想化技術で、Dockerはコンテナ型仮想化技術の代表です。
(詳しいことはこちらの記事(記事作成中)をご参照ください)

インストールから起動まで

1.Dockerをインストールする
 インストール方法は公式ページに丁寧に記載されています。
 お使いのOSによってインストールするものは異なるので、下記公式ページからそれぞれ適したものをインストールして下さい。
 :point_right_tone1: Docker公式ページ
 
2.バージョン確認をする
 インストールが完了したら、Docker, Docker composerのバージョンを確認してみましょう。
 コマンドプロンプトで、下記コマンドを打ち込みます。
 docker -v
 docker composer -v
JPEGイメージ-9BA33E12401D-1.jpeg
 ※Docker composerとは、複数のコンテナを操作する際に使うツールですが、今回は使用しません。
 
3.ターミナルよりコンテナを起動する
 コンテナの起動にはイメージが必要ですが、そのイメージは
「WEB上のDocker Hubから取得する方法」と「自分で作成する方法」があります。
今回は入門書編として、前者を説明していきます。
 
 インストール後、Dockerを開くと下記の様な画面が表示されます。
Screen Shot 2020-11-10 at 4.25.38 PM.png

 ※表示されているコマンドは、Docker Hubよりチュートリアル用のイメージを取得して、コンテナを起動する物です。
 今回は、チュートリアル用のコンテナではなく、ngixを起動してみましょう。
 下記コマンドをターミナルに打ち込み、Docker hubよりnginxのイメージを取得し、コンテナを起動します。
docker run --name some-nginx -d -p 8080:80 nginx

 ※既に起動してるプロセスのポートが被って怒られる場合は、既に起動してるプロセスを落とすか、コンテナを別のポートで起動しましょう。

 起動に成功すれば、下記の様にRUNNINGと表示されます。
Screen Shot 2020-11-15 at 11.46.41 AM.png

Docker hubにはnginx以外にapacheなど他にも様々なイメージがあるので、試してみることをお勧めします!
 
4.コンテナが起動できているか、確認しましょう。
ブラウザから下記URLにアクセスします。
http://localhost:8080
※ポートは適宜読み替えて下さい。

下記の様な画面が出れば、コンテナ起動成功です!

Screen Shot 2020-11-15 at 12.02.57 PM.png

まとめ

以上、Dockerインストールからコンテナ起動までまとめてみました。
いかがでしたでしょうか。
ご参考になれば嬉しいです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Hubとコマンドの紹介 自己学習①

Dockerの学習中に、たくさんのコマンドが出てきたのでアウトプットしていきます。

Docker Hubとは

image.png
Docker imageが管理されているレジストリの名前(Git Hubみたいな感じ)。
Docker imageを管理するレジストリは他にもあるが、その一つがこのDocker Hubである。

リポジトリーの共有

Git Hub同様、Docker Hubもリポジトリーで管理することが可能。
そのリポジトリー(image)をチームなど、様々な人と共有することで簡単に開発環境を整えられる。
Git Hubでいう、リモートリポジトリをローカルにクローンするイメージ。

Docker Hubを使用するには

Docker HubのWebサイトから新規登録を行う。
ターミナルを開き、ログインを行う。

$ docker login 
Login Succeeded

と表示されれば、ログイン成功。

リポジトリー(image)をローカル(Host)へPullする

Docker Hubで管理しているリポジトリーをローカルにプルする。

$ docker pull <imageの名前>

例えば、testOSがリポジトリ名であれば

$ docker pull WindowsOS

これで、リポジトリのクローンがローカルに完成。

コンテナを作成する

WindowsOSが入ったコンテナで作業するために、runコマンドを実行する。

$ docker run -it testOS bash

これでコンテナを作成し、コンテナの中に入ることが出来る。
ここで一旦次のパートで情報を整理する。

コンテナを作成する理由は?

先ほどDocker HubからtestOSというリポジトリー(image)をローカルにPullしました。
しかし、この時点ではローカル環境でtestOSを使うことは出来ません。

例えば、作成するアプリケーションの開発環境でtestOSが必要なので、testOSを使えるようにしたいとする。
そこで、testOSが含まれるコンテナを作成し、そのコンテナの中で作業することで、testOSが使えるようになる。

コンテナから抜けるには

$ exit

このコマンドで、コンテナから抜けることが出来る。

ローカルで管理しているコンテナの確認方法

$ docker ps -a

-aを付けないと、動いているコンテナしか表示されないので、全て表示するには-aが必要。

ローカルで管理しているイメージの確認方法

$ docker images

exitした後に、再度コンテナの中に入る方法

runした後にexitコマンドでコンテナから抜けると、コンテナはexited状態になる。
このままではコンテナが起動しておらず、中に入ることが出来ないので、再度立ち上げる。

$ docker restart

その後、execコマンドで、再びコンテナに入るコマンドを打つ

$ docker exec -it <containerの名前> bash 

Docker imageに変更を保存する方法

開発環境で、RubyやPHP、Javascriptが必要になったとする。
一人がコンテナの中で、Ruby、PHP,Javascriptを扱えるように設定した。

他の人も同じ環境構築をするのは手間も時間もかかり大変。
→ 一人が設定したコンテナの作業環境をimage(リポジトリ)に保存し、提供すれば解決!

$ docker commit <container> <image>

このコマンドで、コンテナの変更内容をimageに保存する。

Docoker Hubにimageをプッシュ前に、タグで名前を一致させる

予めDocker Hubでリポジトリを新規作成しておく。(ここではnew-repoとする)
名前が一致している必要があるので、タグを付ける。

$ docker tag old-repo:updated username/new-repo

old-repoが変更を加えたローカルのリポジトリで、タグが更新を表すupdated。
Docker Hubで新規作成した「new-repo」にusername/new-repoで名前を一致させる。

Docoker Hubにimageをプッシュする

$ docker push username/new-repo

これでDocker Hubで管理しているリポジトリにプッシュが完了
プルすることで、変更が加えられたimage(リポジトリ)をローカルで扱えるようになる。

imageの削除方法

$ docker rmi <image>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【基本編】Dockerを使ってみる 自己学習①

Dockerの学習中に、たくさんのコマンドが出てきたのでアウトプットしていきます。

Docker Hubとは

image.png
Docker imageが管理されているレジストリの名前(Git Hubみたいな感じ)。
Docker imageを管理するレジストリは他にもあるが、その一つがこのDocker Hubである。

リポジトリーの共有

Git Hub同様、Docker Hubもリポジトリーで管理することが可能。
そのリポジトリー(image)をチームなど、様々な人と共有することで簡単に開発環境を整えられる。
Git Hubでいう、リモートリポジトリをローカルにクローンするイメージ。

Docker Hubを使用するには

Docker HubのWebサイトから新規登録を行う。
ターミナルを開き、ログインを行う。

$ docker login 
Login Succeeded

と表示されれば、ログイン成功。

リポジトリー(image)をローカル(Host)へPullする

Docker Hubで管理しているリポジトリーをローカルにプルする。

$ docker pull <imageの名前>

例えば、testOSがリポジトリ名であれば

$ docker pull testOS

これで、リポジトリのクローンがローカルに完成。

コンテナを作成する

testOSが入ったコンテナで作業するために、runコマンドを実行する。

$ docker run -it testOS bash

これでコンテナを作成し、コンテナの中に入ることが出来る。
ここで一旦次のパートで情報を整理する。

コンテナを作成する理由は?

先ほどDocker HubからtestOSというリポジトリー(image)をローカルにPullしました。
しかし、この時点ではローカル環境でtestOSを使うことは出来ません。

例えば、作成するアプリケーションの開発環境でtestOSが必要なので、testOSを使えるようにしたいとする。
そこで、testOSが含まれるコンテナを作成し、そのコンテナの中で作業することで、testOSが使えるようになる。

コンテナから抜けるには

$ exit

このコマンドで、コンテナから抜けることが出来る。

ローカルで管理しているコンテナの確認方法

$ docker ps -a

-aを付けないと、動いているコンテナしか表示されないので、全て表示するには-aが必要。

ローカルで管理しているイメージの確認方法

$ docker images

exitした後に、再度コンテナの中に入る方法

runした後にexitコマンドでコンテナから抜けると、コンテナはexited状態になる。
このままではコンテナが起動しておらず、中に入ることが出来ないので、再度立ち上げる。

$ docker restart

その後、execコマンドで、再びコンテナに入るコマンドを打つ

$ docker exec -it <containerの名前> bash 

Docker imageに変更を保存する方法

開発環境で、RubyやPHP、Javascriptが必要になったとする。
一人がコンテナの中で、Ruby、PHP,Javascriptを扱えるように設定した。

他の人も同じ環境構築をするのは手間も時間もかかり大変。
→ 一人が設定したコンテナの作業環境をimage(リポジトリ)に保存し、提供すれば解決!

$ docker commit <container> <image>

このコマンドで、コンテナの変更内容をimageに保存する。

Docoker Hubにimageをプッシュ前に、タグで名前を一致させる

予めDocker Hubでリポジトリを新規作成しておく。(ここではnew-repoとする)
名前が一致している必要があるので、タグを付ける。

$ docker tag old-repo:updated username/new-repo

old-repoが変更を加えたローカルのリポジトリで、タグが更新を表すupdated。
Docker Hubで新規作成した「new-repo」にusername/new-repoで名前を一致させる。

Docoker Hubにimageをプッシュする

$ docker push username/new-repo

これでDocker Hubで管理しているリポジトリにプッシュが完了
プルすることで、変更が加えられたimage(リポジトリ)をローカルで扱えるようになる。

imageの削除方法

$ docker rmi <image>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker自己学習①

Dockerの学習中に、たくさんのコマンドが出てきたのでアウトプットしていきます。

Docker Hubとは

image.png
Docker imageが管理されているレジストリの名前(Git Hubみたいな感じ)。
Docker imageを管理するレジストリは他にもあるが、その一つがこのDocker Hubである。

リポジトリーの共有

Git Hub同様、Docker Hubもリポジトリーで管理することが可能。
そのリポジトリー(image)をチームなど、様々な人と共有することで簡単に開発環境を整えられる。
Git Hubでいう、リモートリポジトリをローカルにクローンするイメージ。

Docker Hubを使用するには

Docker HubのWebサイトから新規登録を行う。
ターミナルを開き、ログインを行う。

$ docker login 
Login Succeeded

と表示されれば、ログイン成功。

リポジトリー(image)をローカル(Host)へPullする

Docker Hubで管理しているリポジトリーをローカルにプルする。

$ docker pull <imageの名前>

例えば、testOSがリポジトリ名であれば

$ docker pull WindowsOS

これで、リポジトリのクローンがローカルに完成。

コンテナを作成する

WindowsOSが入ったコンテナで作業するために、runコマンドを実行する。

$ docker run -it testOS bash

これでコンテナを作成し、コンテナの中に入ることが出来る。
ここで一旦次のパートで情報を整理する。

コンテナを作成する理由は?

先ほどDocker HubからtestOSというリポジトリー(image)をローカルにPullしました。
しかし、この時点ではローカル環境でtestOSを使うことは出来ません。

例えば、作成するアプリケーションの開発環境でtestOSが必要なので、testOSを使えるようにしたいとする。
そこで、testOSが含まれるコンテナを作成し、そのコンテナの中で作業することで、testOSが使えるようになる。

コンテナから抜けるには

$ exit

このコマンドで、コンテナから抜けることが出来る。

ローカルで管理しているコンテナの確認方法

$ docker ps -a

-aを付けないと、動いているコンテナしか表示されないので、全て表示するには-aが必要。

ローカルで管理しているイメージの確認方法

$ docker images

exitした後に、再度コンテナの中に入る方法

runした後にexitコマンドでコンテナから抜けると、コンテナはexited状態になる。
このままではコンテナが起動しておらず、中に入ることが出来ないので、再度立ち上げる。

$ docker restart

その後、execコマンドで、再びコンテナに入るコマンドを打つ

$ docker exec -it <containerの名前> bash 

Docker imageに変更を保存する方法

開発環境で、RubyやPHP、Javascriptが必要になったとする。
一人がコンテナの中で、Ruby、PHP,Javascriptを扱えるように設定した。

他の人も同じ環境構築をするのは手間も時間もかかり大変。
→ 一人が設定したコンテナの作業環境をimage(リポジトリ)に保存し、提供すれば解決!

$ docker commit <container> <image>

このコマンドで、コンテナの変更内容をimageに保存する。

Docoker Hubにimageをプッシュ前に、タグで名前を一致させる

予めDocker Hubでリポジトリを新規作成しておく。(ここではnew-repoとする)
名前が一致している必要があるので、タグを付ける。

$ docker tag old-repo:updated username/new-repo

old-repoが変更を加えたローカルのリポジトリで、タグが更新を表すupdated。
Docker Hubで新規作成した「new-repo」にusername/new-repoで名前を一致させる。

Docoker Hubにimageをプッシュする

$ docker push username/new-repo

これでDocker Hubで管理しているリポジトリにプッシュが完了
プルすることで、変更が加えられたimage(リポジトリ)をローカルで扱えるようになる。

imageの削除方法

$ docker rmi <image>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCode Remote Containers で --privileged と /sbin/init を渡したコンテナで開発する方法

はじめに

VSCode Remote Containers を使って開発する場合、Dockerfile を書いて「Reopen in Container」とすると Docker コンテナが起動しますが、この時 VSCode が docker run を実行します。
このため、何も気にせず公式の手順などを参考に起動すれば、--privileged オプションを付加できず、ENTRYPOINT に /sbin/init も渡せないため、コンテナで systemctl を実行できません。
※実行すると「Failed to get D-Bus connection: Operation not permitted」と表示されエラーとなります。
※このあたりの仕組みについては、既に「CentOS 7のDockerコンテナ内でsystemdを使ってサービスを起動する」などの記事で語られているため、本記事では割愛します。

本記事では、題記の通り、VSCode Remote Containers で使うコンテナで、docker run--privileged/sbin/init を渡すための調査経緯と、実現した方法を紹介します。

0. 序章: 調査編

まずは正攻法で行けないかと調査してみると、設定ファイルの devcontainer.json には「runArgs」というパラメータがあり、ここで docker run する時のパラメータを追加できることが分かりました。
参考: devcontainer.json reference

しかし、この方法では --privileged を追加できても、--entrypoint を上書きできませんでした。
VSCode Remote Containers で 「Reopen in Container」 して docker コンテナを起動すると、docker run の引数に --entrypoint /bin/sh <各自のDocker Image> -c echo Container started ; trap "exit 0" 15; while sleep 1 & wait $!; do :; done が付加されてしまい、devcontainer.json に書いたパラメータではこれを上書きできない仕様となっているようです。

起動時にどんなコマンドが流れているかは、起動中に表示される以下ポップアップのリンクを押すことで見えるログから把握できます。
image.png

また、次のリンク先で解説されているように、Dockerfile に書いた ENTRYPOINT と CMD よりも、引数で指定された --entrypoint が優先されるため、Dockerfile に書いても上書きできません。
VSCode が必ず docker run に引数で --entrypoint を付加するためこれが最優先されてしまいます。
参考: Dockerfileによるビルド

1. 実現手順

そこで、以下の手順を辿ることにしました。

(1) まずは手順通り 「Reopen in Container」 を実行

この手順により Docker イメージがビルドされ、コンテナが起動します。
この時、先ほどのポップアップのリンクからログを開き、ログの中から以下のコマンドを探してコピーします。

docker run -a STDOUT -a STDERR --mount type=bind,source=<各自の環境のパス>,target=<各自の環境のパス>,consistency=cached -l vsch.quality=stable -l vsch.remote.devPort=0 -l vsch.local.folder=<各自の環境のパス> --entrypoint /bin/sh <各自のDocker Image> -c echo Container started ; trap "exit 0" 15; while sleep 1 & wait $!; do :; done

(2) VSCode でコンテナとの接続を解除

(1) で起動したコンテナは --privileged されていませんので、VSCode で一旦接続を解除します。

(3) コピーしたコマンドを一部変更

コピーしたコマンドに --privileged を追記し、--entrypoint を書き換えます。

docker run -a STDOUT -a STDERR --mount type=bind,source=<各自の環境のパス>,target=<各自の環境のパス>,consistency=cached -l vsch.quality=stable -l vsch.remote.devPort=0 -l vsch.local.folder=<各自の環境のパス> --privileged --entrypoint /sbin/init <各自のDocker Image>

(4) 上記コマンドをローカルのターミナルで実行

実行すると (3) のオプション通りに docker コンテナが起動します。
docker ps で起動状態を確認できます。

(5) VSCodeで「Attach to Running Container」を実行

次に、(4) で起動したコンテナを VSCode にアタッチします。
まず、以下画像のように「Attach to Running Container」を選びます。

image.png

次に起動中のコンテナを選ぶ画面で、コンテナを選ぶだけです。
image.png

ここまでで、VSCode からコンテナに接続して、開発環境を開けます。

2. 動作確認

VSCode でコンテナのターミナルを開いて systemctl を打ってみます。

bash-4.2# systemctl
  UNIT                          LOAD   ACTIVE     SUB       DESCRIPTION
  dev-vda1.device               loaded activating tentative /dev/vda1
  -.mount                       loaded active     mounted   /
  dev-hugepages.mount           loaded active     mounted   Huge Pages File System
  dev-mqueue.mount              loaded active     mounted   POSIX Message Queue File Syste
  etc-hostname.mount            loaded active     mounted   /etc/hostname
  etc-hosts.mount               loaded active     mounted   /etc/hosts
(以下長いので略)

このようにエラーが解消され、打てるようになっています。

最後に

このように、起動したコンテナに VSCode から接続する手順を踏むことで、VSCode Remote Containers でも systemctl が実行できるようになります。
今回、少々面倒ですが docker build までは VSCode で実行して、各種オプションが含まれる docker run コマンドを VSCode のログから発掘する方が早いと判断しました。
(もっと良い方法があるのかもしれませんが、もし見つかったら追記します)

なお --privileged はその名の通り特権という意味なので、ご利用は計画的に、とすべきです。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初級編】Dockerってそもそも何?基礎からわかりやすく解説!

はじめに

今更ではありますが、Dockerについて基礎から勉強したのでまとめます。
全てのコマンドの細かいオプションとかはまとめていません。
本記事の目的はDockerというツールを知るという初歩的(だけど重要)なものです。

Dockerってそもそも何?

Docker(ドッカー)とは「仮想環境の構築ツール」です。

仮想環境って何?

仮想環境というのは、コンピュータの中に疑似的に作る仮の空間(何かを実現する場)のことを指します。もう少し噛み砕くと、本来物理的に必要なものを仮想的にあるようにして動かすことのできる環境のことです。

スクリーンショット 2020-11-15 18.17.42.png
参照:仮想マシンとは?よく聞く"仮想化" "仮想マシン"の基礎知識と特徴を解説

例えば、Windows環境の中で、仮想的に作られたLinux OS環境や、別のWindows OS環境が用意できるというのが仮想環境の例です。一般的に仮想環境をつくる土台となるOSを「ホストOS」、仮想環境上のOSを「ゲストOS」と呼びます。仮想環境を構築することで、Linux用のパソコンとWindows用のパソコンをそれぞれを物理的に用意する必要がなくなり、一つのハードウェアで一元管理できるようになります。
また、メモリやハードディスク容量などを柔軟に調整ができるというメリットもあります。仮想環境を構築すれば、ハード機器の節約にもなります。

仮想マシンの種類

仮想マシンには、いくつか種類があります。それぞれのメリット、デメリットについて簡単に説明します。

①ホスト型
②ハイパーバイザー型
③コンテナ型

image.png
参照:仮想環境とは?メリットやデメリット、代表的なソフトウェア「VMware」について解説

①ホスト型

パソコンやサーバにホストOSをインストールし、そのOS上に仮想環境作成ソフトウェアをインストールして構築するタイプです。ホストOSの上にゲストOSが並びます。

・メリット:既存のサーバなどにインストールすればすぐに利用でき、手軽に始められる。
・デメリット:ホストOSを起動しなければならない。ハードウェアを起動した際に、ホストOSが立ち上がるまで時間がかかる場合がある。

②ハイパーバイザー型

1つのハードウェアに「ハイパーバイザー」と呼ばれる仮想化ソフトウェアを直接インストールし、仮想化を構築するタイプがハイパーバイザー型です。ホストOSを起動しなくてよいので、ホストOS型と比べて早く起動できます。

・メリット:ホストOSがないため、リソースのほとんどを仮想環境に充てられる。
・デメリット:既存のパソコンやサーバを使い回せず、新しくハードウェアを購入しなくてはいけない。構築する際は、コスト面にも注意する必要がある。

③コンテナ型

ホストOSに「コンテナエンジン」とよばれる仮想化ソフトウェアをインストールし、その中でコンテナと呼ばれる環境を作り、アプリケーションを実行させます。
コンテナにはゲストOSという概念はありません。ホストOSからは、一つのプロセスとして認識されます。そのため、余分なリソースが不要であり、軽快な環境を提供できるのです。実際に使用してみると、アプリケーションを短時間で起動できるでしょう。

・メリット:リソース効率がよく、コストパフォーマンスにも優れている。
・デメリット:新しい技術ということもあり、構築できるベンダーが少ない。便利な管理ツールなどが不足している。

ここで改めてDockerとは??

Dockerは前述した通り、「仮想環境の構築ツール」です。その中でも「コンテナ」という仮想環境を構築し、そのコンテナの中でアプリケーション、ミドルウェア、OSなどを動かすことができます。コンテナは非常に軽量で、起動や停止などを素早く完了させることができるのが魅力の一つです。
では実際にDockerがどんな仕組みで動くのか見ていきましょう。

Dockerの仕組み

ここではDocker初心者なら抑えておきたい用語をもとに、Dockerの仕組みについて理解を深めていきます。

・Dockerエンジン
・Dockerコンテナ
・Dockerイメージ

Dockerエンジンとは?

Dockerエンジンは「Docker自体そのもの」という理解でいいです。Dockerイメージの作成やコンテナ起動などを行うDockerのコアな部分です。このDockerエンジンはホストOS(Windows, Mac, Linux)にDockerをインストールすることで簡単に利用できます。インストールしたらホストOS上にDockerエンジンが動き、その上で各コンテナが動いているという感じです。

画像参照:https://www.ogis-ri.co.jp/otc/hiroba/technical/docker/part1.html

Dockerコンテナとは?

DockerコンテナとはDockerエンジン上で動いている仮想環境のことです。
Dockerコンテナでは、CentOSやUbuntsuなどのOSから、NginxやMySQLなどのミドルウェア、RailsやWordpressなどのアプリケーションまで様々な環境を作ることができます。
これらのコンテナは「**ホストOSのカーネル(Linuxカーネル)を利用して動いている**」という特徴があります!
Linuxカーネルというのは、OSに必要な基本機能を集めた中心核のようなソフトウェアのことです。

ここで疑問なのが、「Linuxを持たないWindowsやMac上でもDockerは立ち上がるのか?」ということです。
答えは、立ち上がります!
なぜかというと、Docker起動の裏でLinux仮想マシンが動くようになっているため、各コンテナもこの仮想マシン上で動く仕組みになっているのです。

またこの仮想マシンであるLinuxはコンテナごとに独立している訳ではなく、コンテナ全てで共通したものが使われるため、ホストマシンのリソース(CPUやメモリ)を節約しながら動いているのです。そうすることでコンテナ自体は軽量化されますし、何よりDockerのコンテナの起動が早い理由なのです。

参照:https://kitsune.blog/docker-summary#Docker%25E3%2582%25B3%25E3%2583%25B3%25E3%2583%2586%25E3%2583%258A%25E3%2581%25A8%25E3%2581%25AF

Dockerイメージとは?

DockerイメージとはDockerコンテナを作るためのマニュアルみたいなものです。
このDockerイメージをもとにコンテナが作られます。各イメージは元のイメージとなる「ベースイメージ」となるものに、「レイヤー(層)」を重ねることで新しいイメージを作成することができます!


画像参照:https://dzone.com/articles/optimizing-spring-boot-application-for-docker

まとめ

DockerについてとDockerの仕組みについて簡単にまとめました。
Dockerの概要は理解できても、Linuxの基礎知識がないとDocker環境設定で詰まってしまうと思うので、Linuxについても勉強していきたいところです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2にDockerをインストールして起動してみた

はじめに

EC2 (AmazonLinux2)にDockerをインストールして使ってみた時の備忘録です。
普通はECSやElasticBeanstalkなどのコンテナ基盤を使うと思うので、あまり機会はないかもですが書いてみました。

EC2でDockerをインストールしていく

EC2にログインします

$ ssh -i ~/.ssh/****.pem ec2-user@***.***.***.***

git をインストール

$ sudo yum install git -y

Docker をインストール

$ sudo amazon-linux-extras install docker -y

Docker を起動

$ sudo service docker start 

おわりに

もし ERROR: Couldn’t connect to Docker daemon at http+docker://localhost – is it running? みたいなエラーが出ればこちら↓の記事を参考にしてみてください。

https://qiita.com/u_query/items/14a31721a2870b735938

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsの開発環境をDockerで構築する方法

この記事では、Dockerを用いてRuby on Rails(以下、rails)の開発環境を構築する方法を紹介します。

通常、rails の初学者の方はマシンに直接インストールして開発環境を構築する人がほとんどだと思います。
しかし、環境の微妙な際(Rubyのバージョンや環境変数など)によってつまづいた場合、
そのトラブルシューティングには多くの時間を要してしまうかと思います。

そこで、Dockerで仮想環境上にrailsの環境を構築してあげることで
どのマシン上の開発環境でも等しい動作を行うことができるため、環境の差異によるエラーを避けることができます。
環境をいじりすぎた時には最悪一度リセットを出来るというのもメリットですね。

また、作成したアプリケーションを本番環境として外部へ公開しようとするときにも
開発環境と本番環境での違いを最小限に抑え、安定したアプリケーションとして稼働させることができます.

Dockerで仮想環境を作って公開するなんて難しそうと思うかもしれませんが、
最近ではAWSといったクラウドサービスでもDockerコンテナをそのまま実行できるECS等のサービスが整っているので
Dockerで作った環境を公開するのも楽になってきています。

前提条件

マシンに Docker がインストールされていること

Docker をインストールしていない人は、公式サイトから Docker のインストーラをダウンロードしてインストールしておきましょう。
Docker公式

また、任意の作業フォルダを作成しておきます。
ここでは "rails-docker" というフォルダを作成し、その中で作業していくことにします。

$ mkdir rails-docker
$ cd rails-docker

Docker関連ファイルの準備

rails-docker 内に以下4つの空ファイルを準備しておきます。
VScode を利用しているなら新規ファイルの作成で作ったり、
Mac のターミナルから touch コマンドを使ってもよいです。

.
├── Dockerfile # 新規作成
├── Gemfile # 新規作成
├── Gemfile.lock # 新規作成
└── docker-compose.yml # 新規作成

Dockerファイルの解説

Dockerでは、Dockerfileというファイルに基づいてコンテナのビルドが行われ、
Docker Image(コンテナの雛形)が作成されることになります。

まず Dockerfile の全文を記載します。
使用する Ruby のバージョンは 2.7.0 としています。

FROM ruby:2.7.0
RUN apt-get update -qq && apt-get install -y build-essential nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

箇条書きとはなりますが、それぞれの意味を解説します。

  • FROM ruby:2.7.0
    • 公開されている ruby インストール済みコンテナのうち、Rubyのバージョンが 2.7.0 であるものを引っ張ってきます。
  • RUN apt-get update -qq && apt-get install -y build-essential nodejs
    • Rails の実行に必要なパッケージをインストールしています
  • RUN mkdir /app
    • Rails のプロジェクトファイルを作成するアプリディレクトリを作成
  • WORKDIR /app
    • 作業用のディレクトリを指定
  • COPY Gemfile /app/Gemfile
    • 自分のマシン(PC)上にある Gemfile をコンテナの作業用ディレクトリに移動させ、コンテナから利用できるようにします
    • Gemfile.lock も同様
  • RUN bundle install
    • Gemfileに記載されているgemを一括インストール
  • COPY . /app
    • Dockerファイルが置いてあるフォルダのファイルすべてをコンテナ内の app ディレクトリにコピー
    • Rails の実行に必要なファイルをコンテナに含めるためにコピーしています

Gemfile の解説

Ruby では Gemfile というファイルで環境で使いたい gem を定義することができます。

gemとはRubyのライブラリのことをいいます。
gemはRubyGemsと呼ばれるRuby用のパッケージ管理システムで管理されており、RubyGemsが提供するgemコマンドを通じてインストール等ができます。

source 'https://rubygems.org'
gem 'rails', '5.2.1'

また少し解説します。

  • source 'https://rubygems.org'
    • gem のダウンロード元を指定
  • gem 'rails', '5.2.1'
    • インストールする gem である rails というパッケージ名と、バージョンを指定
    • 今回は rails のバージョンは 5.2.1 を指定しています
    • どのバージョンを指定してもよいのですが rails 6 以降は webpacker, yarn が必要になるので注意してください
    • ここでは簡単に検証するため rails 5 系を使用

Gemfile があるディレクトリで "bundle install" コマンドを実行すると、
Gemfile の定義に従って、定義した gem をインストールすることができます。

先ほど解説した Docker ファイルでも、Gemfile をコンテナの作業用ディレクトリにコピーして
そのフォルダ内で bundle install を実行するように指定していましたね。

Gemfile.lock の解説

実は Gemfile.lock は最初の時点では何も書き込む必要がありません。
これは直接編集するようなファイルではなく、
Gemfile に基づいて bundle install を実行した後に
インストールされた gem が Gemfile.lock に一覧として記述されるようになります。

使い方としては、Gemfile.lock を参照すればインストールされている gem とバージョンが分かり、
Gemfile.lock から bundle install を実行することもできるので
完全に同じ環境をもう一度作りたいときや、多人数で開発をするときに Gemfile.lock が使われます。

Gemfile だけでも良いのでは?と思った鋭い方に補足しますと、Gemfile では実はこういう書き方もできることが理由の一つになっています。

gem 'rails', '~> 5.2.1'

この場合、bundle install でインストールされる rails のバージョンは 5.2.1 以上であるものの
実際にインストールできる(公開されている)バージョンはその時点によって変わってきます。

しかし Gemfile.lock では Gemfile に従ってインストールしようとした時に実際にインストールされた gem 本体と具体的なバージョン、
付随して必要となるためにインストールされたパッケージまで記録されます。

少し整理すると Gemfile は「アプリで必要な gem の一覧」であり、
一方の Gemfile.lock は「Gemfile に従った結果、実際にインストールした gem の情報」が記述されることになります。

docker-compose.yml の解説

この yml ファイルは Docker Compose で使用されます。

Docker Composeは、複数のコンテナで構成されるアプリケーションについて
Dockerイメージのビルドや各コンテナの起動・停止といった管理を行うためのツールです。

Docker Composeでは、Dockerビルドやコンテナ起動のオプションも含め、複数のコンテナのための定義を docker-compose.yml というファイルに記述し、
それを利用して Docker イメージのビルドやコンテナ起動をすることができます。

開発環境のように、Rails をそれ単体で動かすならば Dockerfile だけでもよいのですが
Rails を動かすためのアプリケーションサーバに加え、
実際に公開するときにはインターネットからのアクセスを受け付けるための Web サーバや、
またデータを保存・処理するためのデータベースサーバも用意することがあります。

docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:

rails ではデータベースも必要になるため、WebサーバだけではなくMySQLを用いたデータベースサーバのコンテナも構築します。
ここでは詳解しませんが、web という欄の中の「depends_on」で rails が連携するデータベースサーバ(コンテナ)を名前で指定しています。

rails の立ち上げ

rails プロジェクトの作成 (rails new)

docker-compose.yml が置いてあるフォルダ(rails-dockerフォルダ)で以下の docker-compose コマンドを実行します。

$ docker-compose run web rails new . --force --database=mysql

コマンドについて、オプション含め少し読み方を解説します↓

  • docker-compose: docker-compose というツールをつかって
  • run: 以下のコマンドを実行します
  • web: web コンテナで
  • rails new: rails で新しいプロジェクトを作成する
  • . : 現在のディレクトリに対して
  • --force: 既存の file (ここでは Gemfile, Gemfile.lock) は上書きする形で
  • --database=mysql: ただし rails のデータベースには MySQL を使用します

という意味を持っているのです。

この一行のコマンドを実行すると数分単位で処理に時間がかかるので、チョコレートでも食べながら気長に待ちましょう。

build の実行

Gemfile に追記された gem のインストール、
および作成されたファイルをコンテナ内に取り込むため build を実行します。

$ docker-compose build

データベース設定ファイルの編集

build が完了したら、rails で使用するデータベースファイルの設定を編集します。
config ディレクトリ内の database.yml というファイルが対象です。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # 追加
  host: db # 変更

password は docker-compose.yml で指定したパスワードと合わせる必要があります。

docker-compose.yml
...
    environment:
      MYSQL_ROOT_PASSWORD: password # ここと合わせる
...

また、host の欄は MySQL コンテナ名を設定しています。

コンテナの起動

コンテナを起動するため、次のコマンドを実行します。

$ docker-compose up -d

docker-compose up がコンテナをdocker-compose.yml に基づいて起動するコマンドであり、
オプションの「-d」によりバックグラウンドで起動させることができます。

データベースの作成

いまはまだコンテナが起動しただけであり、データベースは作成されていないので
次のコマンドを実行してデータベースを作成します。

$ docker-compose run web bundle exec rails db:create

rails を実行している web コンテナで、rails db:create (=データベースの新規作成)を実行する処理となっています。

rails 開発用サーバの起動確認

これで無事に rails の開発用サーバが起動したことになります。
ブラウザのアドレスバーに localhost:3000 と入力し、起動を確認してみましょう。

image.png

rails ではお馴染みの画面が表示されれば完了です。

コンテナの停止

開発用サーバを止めるため、コンテナを一括で停止するには以下のコマンドを実行します。

$ docker-compose down

また立ち上げたいときには docker-comopose up -d を実行しましょう。

最後に

これによって作られるファイルの一式は Github にあげています。
フォルダ構成が分からなくなったり、自分の環境でうまくいっているか比較して確かめたい方はご参照ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsの開発環境をDockerで構築する方法(Rails 5.x)

この記事では、Dockerを用いてRuby on Rails(以下、rails)の 5.x 系における開発環境を構築する方法を紹介します。
※Rails 6.x 系で Docker 環境を作りたい場合は こちら をご覧ください。

Docker で環境構築をするメリットとは?

通常、rails の初学者の方はマシンに直接インストールして開発環境を構築する人がほとんどだと思います。
しかし、環境の微妙な際(Rubyのバージョンや環境変数など)によってつまづいた場合、
そのトラブルシューティングには多くの時間を要してしまうかと思います。

そこで、Dockerで仮想環境上にrailsの環境を構築してあげることで
どのマシン上の開発環境でも等しい動作を行うことができるため、環境の差異によるエラーを避けることができます。
環境をいじりすぎた時には最悪一度リセットを出来るというのもメリットですね。

また、作成したアプリケーションを本番環境として外部へ公開しようとするときにも
開発環境と本番環境での違いを最小限に抑え、安定したアプリケーションとして稼働させることができます.

Dockerで仮想環境を作って公開するなんて難しそうと思うかもしれませんが、
最近ではAWSといったクラウドサービスでもDockerコンテナをそのまま実行できるECS等のサービスが整っているので
Dockerで作った環境を公開するのも楽になってきています。

前提条件

マシンに Docker がインストールされていること

Docker をインストールしていない人は、公式サイトから Docker のインストーラをダウンロードしてインストールしておきましょう。
Docker公式

また、任意の作業フォルダを作成しておきます。
ここでは "rails-docker" というフォルダを作成し、その中で作業していくことにします。

$ mkdir rails-docker
$ cd rails-docker

Docker関連ファイルの準備

rails-docker 内に以下4つの空ファイルを準備しておきます。
VScode を利用しているなら新規ファイルの作成で作ったり、
Mac のターミナルから touch コマンドを使ってもよいです。

.
├── Dockerfile # 新規作成
├── Gemfile # 新規作成
├── Gemfile.lock # 新規作成
└── docker-compose.yml # 新規作成

Dockerファイルの解説

Dockerでは、Dockerfileというファイルに基づいてコンテナのビルドが行われ、
Docker Image(コンテナの雛形)が作成されることになります。

まず Dockerfile の全文を記載します。
使用する Ruby のバージョンは 2.7.0 としています。

FROM ruby:2.7.0
RUN apt-get update -qq && apt-get install -y build-essential nodejs
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

箇条書きとはなりますが、それぞれの意味を解説します。

  • FROM ruby:2.7.0
    • 公開されている ruby インストール済みコンテナのうち、Rubyのバージョンが 2.7.0 であるものを引っ張ってきます。
  • RUN apt-get update -qq && apt-get install -y build-essential nodejs
    • Rails の実行に必要なパッケージをインストールしています
  • RUN mkdir /app
    • Rails のプロジェクトファイルを作成するアプリディレクトリを作成
  • WORKDIR /app
    • 作業用のディレクトリを指定
  • COPY Gemfile /app/Gemfile
    • 自分のマシン(PC)上にある Gemfile をコンテナの作業用ディレクトリに移動させ、コンテナから利用できるようにします
    • Gemfile.lock も同様
  • RUN bundle install
    • Gemfileに記載されているgemを一括インストール
  • COPY . /app
    • Dockerファイルが置いてあるフォルダのファイルすべてをコンテナ内の app ディレクトリにコピー
    • Rails の実行に必要なファイルをコンテナに含めるためにコピーしています

Gemfile の解説

Ruby では Gemfile というファイルで環境で使いたい gem を定義することができます。

gemとはRubyのライブラリのことをいいます。
gemはRubyGemsと呼ばれるRuby用のパッケージ管理システムで管理されており、RubyGemsが提供するgemコマンドを通じてインストール等ができます。

source 'https://rubygems.org'
gem 'rails', '5.2.1'

また少し解説します。

  • source 'https://rubygems.org'
    • gem のダウンロード元を指定
  • gem 'rails', '5.2.1'
    • インストールする gem である rails というパッケージ名と、バージョンを指定
    • 今回は rails のバージョンは 5.2.1 を指定しています
    • どのバージョンを指定してもよいのですが rails 6 以降は webpacker, yarn が必要になるので注意してください
    • ここでは簡単に検証するため rails 5 系を使用

Gemfile があるディレクトリで "bundle install" コマンドを実行すると、
Gemfile の定義に従って、定義した gem をインストールすることができます。

先ほど解説した Docker ファイルでも、Gemfile をコンテナの作業用ディレクトリにコピーして
そのフォルダ内で bundle install を実行するように指定していましたね。

Gemfile.lock の解説

実は Gemfile.lock は最初の時点では何も書き込む必要がありません。
これは直接編集するようなファイルではなく、
Gemfile に基づいて bundle install を実行した後に
インストールされた gem が Gemfile.lock に一覧として記述されるようになります。

使い方としては、Gemfile.lock を参照すればインストールされている gem とバージョンが分かり、
Gemfile.lock から bundle install を実行することもできるので
完全に同じ環境をもう一度作りたいときや、多人数で開発をするときに Gemfile.lock が使われます。

Gemfile だけでも良いのでは?と思った鋭い方に補足しますと、Gemfile では実はこういう書き方もできることが理由の一つになっています。

gem 'rails', '~> 5.2.1'

この場合、bundle install でインストールされる rails のバージョンは 5.2.1 以上であるものの
実際にインストールできる(公開されている)バージョンはその時点によって変わってきます。

しかし Gemfile.lock では Gemfile に従ってインストールしようとした時に実際にインストールされた gem 本体と具体的なバージョン、
付随して必要となるためにインストールされたパッケージまで記録されます。

少し整理すると Gemfile は「アプリで必要な gem の一覧」であり、
一方の Gemfile.lock は「Gemfile に従った結果、実際にインストールした gem の情報」が記述されることになります。

docker-compose.yml の解説

この yml ファイルは Docker Compose で使用されます。

Docker Composeは、複数のコンテナで構成されるアプリケーションについて
Dockerイメージのビルドや各コンテナの起動・停止といった管理を行うためのツールです。

Docker Composeでは、Dockerビルドやコンテナ起動のオプションも含め、複数のコンテナのための定義を docker-compose.yml というファイルに記述し、
それを利用して Docker イメージのビルドやコンテナ起動をすることができます。

開発環境のように、Rails をそれ単体で動かすならば Dockerfile だけでもよいのですが
Rails を動かすためのアプリケーションサーバに加え、
実際に公開するときにはインターネットからのアクセスを受け付けるための Web サーバや、
またデータを保存・処理するためのデータベースサーバも用意することがあります。

docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:

rails ではデータベースも必要になるため、WebサーバだけではなくMySQLを用いたデータベースサーバのコンテナも構築します。
ここでは詳解しませんが、web という欄の中の「depends_on」で rails が連携するデータベースサーバ(コンテナ)を名前で指定しています。

rails の立ち上げ

rails プロジェクトの作成 (rails new)

docker-compose.yml が置いてあるフォルダ(rails-dockerフォルダ)で以下の docker-compose コマンドを実行します。

$ docker-compose run web rails new . --force --database=mysql

コマンドについて、オプション含め少し読み方を解説します↓

  • docker-compose: docker-compose というツールをつかって
  • run: 以下のコマンドを実行します
  • web: web コンテナで
  • rails new: rails で新しいプロジェクトを作成する
  • . : 現在のディレクトリに対して
  • --force: 既存の file (ここでは Gemfile, Gemfile.lock) は上書きする形で
  • --database=mysql: ただし rails のデータベースには MySQL を使用します

という意味を持っているのです。

この一行のコマンドを実行すると数分単位で処理に時間がかかるので、チョコレートでも食べながら気長に待ちましょう。

build の実行

Gemfile に追記された gem のインストール、
および作成されたファイルをコンテナ内に取り込むため build を実行します。

$ docker-compose build

データベース設定ファイルの編集

build が完了したら、rails で使用するデータベースファイルの設定を編集します。
config ディレクトリ内の database.yml というファイルが対象です。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # 追加
  host: db # 変更

password は docker-compose.yml で指定したパスワードと合わせる必要があります。

docker-compose.yml
...
    environment:
      MYSQL_ROOT_PASSWORD: password # ここと合わせる
...

また、host の欄は MySQL コンテナ名を設定しています。

コンテナの起動

コンテナを起動するため、次のコマンドを実行します。

$ docker-compose up -d

docker-compose up がコンテナをdocker-compose.yml に基づいて起動するコマンドであり、
オプションの「-d」によりバックグラウンドで起動させることができます。

データベースの作成

いまはまだコンテナが起動しただけであり、データベースは作成されていないので
次のコマンドを実行してデータベースを作成します。

$ docker-compose run web bundle exec rails db:create

rails を実行している web コンテナで、rails db:create (=データベースの新規作成)を実行する処理となっています。

rails 開発用サーバの起動確認

これで無事に rails の開発用サーバが起動したことになります。
ブラウザのアドレスバーに localhost:3000 と入力し、起動を確認してみましょう。

image.png

rails ではお馴染みの画面が表示されれば完了です。

コンテナの停止

開発用サーバを止めるため、コンテナを一括で停止するには以下のコマンドを実行します。

$ docker-compose down

また立ち上げたいときには docker-comopose up -d を実行しましょう。

最後に

これによって作られるファイルの一式は Github にあげています。
フォルダ構成が分からなくなったり、自分の環境でうまくいっているか比較して確かめたい方はご参照ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerについて理解した後、実際に導入してみました。

1 本記事について

明日から新しい職場でDockerというものを使うっぽいのですが、よく(というかほぼ何も)分からないので、調べてみました。

2 Dockerとは

そもそもDockerとは何なのか分からないので調べてみました。

Dockerとは、ひとことでいうと「Linux上で動作するシンプルで使いやすい軽量コンテナ環境」です。 LinuxというOS上にコンテナという箱を用意し、そのコンテナの中に必要なソフトウェアやライブラリ(ツール)などをインストールしてひとつのまとまりとしてパッケージングすることができます。

引用元:開発環境にDockerを導入し開発を効率化する話〜開発本部・TechLunch〜


Dockerは、インフラ関係やDevOps界隈で注目されている技術の一つで、Docker社が開発している、コンテナ型の仮想環境を作成、配布、実行するためのプラットフォームです。
Dockerは、Linuxのコンテナ技術を使ったもので、よく仮想マシンと比較されます。VirtualBoxなどの仮想マシンでは、ホストマシン上でハイパーバイザを利用しゲストOSを動かし、その上でミドルウェアなどを動かします。それに対し、コンテナはホストマシンのカーネルを利用し、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができます。そのため、軽量で高速に起動、停止などが可能です。

引用元:Docker入門(第一回)~Dockerとは何か、何が良いのか~

Dockerというコンテナ環境で開発を行うと、その環境をパッケージング化できて何かと便利ということみたいです。

3 Dockerのインストール

公式ドキュメントに沿って、ubuntu上で、Dockerのインストールをしていきます。

3.1 念のため古いバージョンのDockerをアンインストール

古いバージョンのDockerをインストールしている可能性が微粒子レベルで存在するので削除コマンドを実行します。やらなくても良いみたいです。

$ sudo apt-get remove docker docker-engine docker.io containerd runc

Package 'XXXX' is not installed, so not removedみたいなのが出てくればOKです。

3.2 パッケージインデックスを更新・aptがリポジトリを利用できるようパッケージをインストール

Dockerをインストールするために必要なパッケージをインストールします。主にaptがHTTPSに対応していないのを補う目的があるみたいです。

$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

3.3 公式GPGキーを追加

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

何をしているのかよく分からないので、ちょっと詳しく見ます。

3.3.1 curlとは

3.2でcurlをインストールしているので、curlコマンドが使えるようになっています。curlコマンドは何かというと、

引数にURLを指定すると、そのURLのファイルをダウンロードします。デフォルトの出力先は「標準出力」なので、リダイレクトで保存するか、「-O」オプションまたは「-o」オプションを指定します。

引用元:【 curl 】コマンド――さまざまなプロトコルでファイルをダウンロード(転送)する

curlコマンドはダウンロードするコマンドです。(-fsSLはそのオプションです。今回は省略します。)

3.3.2 GPGとは

curlコマンドの引数のURLはDockerのGPGのURLになっています。curlコマンドはダウンロードするコマンドなので、DockerのGPGをダウンロードすることになります。GPGとはGnuPGの略で、これは何なのかというと、

公開鍵でファイルの署名を検証したり、公開鍵と秘密鍵のペアでメールの暗号化・復号化を行ったり署名を添付したりするツール。

引用元:GnuPG | IT用語辞典 | 大塚商会

つまり、認証に必要な鍵のことと思っておけばよさそうです。

3.3.3 apt-keyとは

DockerのGPGをapt-keyに渡しています。apt-keyとは何かというと、

「apt-key」は、「apt」が パッケージの認証に使用するキーの一覧を管理するコマンドです。Ubuntu公式以外からパッケージを取得するには、このコマンドで認証する鍵情報を取り込んでおく必要があります。

引用元:apt ・ apt-keyの使い方|npaka|note

つまり、DockerをインストールするためにはDockerのGPGをローカルのapp-keyに取り込んでおく必要がある、ということみたいです。

3.4 キーの確認

GPGキーが追加されていることを確認します。DockerのGPGキーのフィンガープリントは「9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88」なので、この下8桁で以下のように検索し、結果が表示されればOKです。

$ sudo apt-key fingerprint 0EBFCD88
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

3.5 stableリポジトリを設定

$sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

【Ubuntu】PPAを追加・削除する方法について | Hbk project

この記事を見ると、何のための作業なのかわかりやすいと思います。aptをつかってインストールできるパッケージは、デフォルトでは/etc/apt/source.listにあるものだけです。つまり、Dockerをインストールするためには、PPA(Personal Package Archive)を追加する必要があるということですね。

3.6 インストールの実行

アプトのパッケージインデックスを更新し、インストールを実行します。

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

これでDockerのインストールが完了しました。

4 Dockerを使ってみる

ここからが本番です。公式ドキュメントに沿って実際にDockerを使ってみます。

4.1 オリエンテーション

まずはDockerが動くか確認します。

4.1.1 バージョンの確認

本当にDockerがインストールされているか確認します。

$ docker --version
Docker version 19.03.12, build 48a66213fe

されていました。

4.1.2 hello-worldイメージを実行

hello-worldイメージを取得します。

$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:ca0eeb6fb05351dfc8759c20733c91def84cb8007aa89a5bf606bc8b315b9fc7
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

何をしているのかは以下のサイトを参考にするとわかりやすいです。

Docker入門(第二回)~Dockerセットアップ、コンテナ起動~ | さくらのナレッジ

Docker Hubとよばれるコンテナ共有サービスにある、公式のイメージ「hello-world」を取得し、それをもとにコンテナを起動させた形になります。

参考:hello-worldイメージのページ

4.1.3 イメージがダウンロードされていることの確認

$ docker image ls

hello-worldのイメージがあるのが確認できると思います。

4.1.4 コンテナが起動していることの確認

docker runは元々イメージを取得するコマンドではなくイメージを元にコンテナを起動するコマンドですので、コンテナが起動しているはずです。

$ docker ps --all

CONTAINER ID     IMAGE           COMMAND      CREATED            STATUS
54f4984ed6a8     hello-world     "/hello"     20 seconds ago     Exited (0) 19 seconds ago

確かにコンテナが確認できました。

4.2 イメージのビルド&コンテナの実行

Dockerを動かすことができたので、次はイメージをビルド・実行していきます。

4.2.1 掲示板アプリのgit cloneを作成

テスト用の掲示板アプリのクローンを作成します。

$ git clone https://github.com/dockersamples/node-bulletin-board

4.2.2 イメージのビルド

イメージをビルドします。

$ cd node-bulletin-board/bulletin-board-app
$ docker build --tag bulletinboard:1.0 .

4.1.2にあるように、コンテナを起動させるにはイメージが必要です。4.1.2では公式のイメージを持ってきましたが、コンテナ環境は開発環境の数だけあるため、独自のイメージが必要となります(探せば誰かがDockerHubに公開しているものが使えるかもしれませんが)。ビルドとは既にあるイメージ(ベースイメージ)を元に、新しいイメージを作成することです。ビルドは、Dockerfileがおかれている場所で実行し、Dockerfileを元に実行されます。

Dockerfileを見てみましょう。

Dockerfile
FROM node:current-slim

WORKDIR /usr/src/app
COPY package.json .
RUN npm install

EXPOSE 8080
CMD [ "npm", "start" ]

COPY . .

1行目の「FROM node:current-slim」に注目してください。「node:current-slim」というベースイメージを元に、新しいイメージをビルドするという記述です。先ほど実行したコマンドの引数に当たる「bulletinboard:1.0 .」という名前のイメージが作成されました。実際にイメージが作成されているか確認してみます。

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
bulletinboard       1.0                 789f62d53520        13 minutes ago      177MB
node                current-slim        3aaf4acbaad7        2 days ago          159MB
hello-world         latest              bf756fb1ae65        10 months ago       13.3kB

ベースイメージ、およびビルドされたイメージが確認できました。

4.2.3 コンテナを起動

作成したイメージを元にコンテナを起動します。

$ docker run --publish 8000:8080 --detach --name bb bulletinboard:1.0

ブラウザでlocalhost:8000にアクセスし、掲示板アプリが動作していることが確認できます。
これについて、細かく見ていきます。

4.2.3.1 --publish 8000:8080

8000がホスト側のポート番号、8080がコンテナ側のポート番号です。

4.2.3.2 --detach

コンテナをバックグラウンドで起動する際に使うオプションです。

4.2.3.3 --name bb bulletinboard:1.0

「bulletinboard:1.0」というイメージを元に「bb」という名前のコンテナを起動します。

4.2.4 コンテナを停止

コンテナを停止・削除します。

docker rm --force bb

これで無事、イメージのビルドとコンテナ化の理解ができました。

5 最後に

Dockerを利用したコンテナ環境の構築や配布のイメージがあらかたつかめたのでよかったです。

Twitterのフォローもお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

まだanyenv使ってるの? Docker使ってもっと楽にいこうぜ?

Windowsなどのホストに環境を入れる際に起きる欠点

よくあるのがバージョン差異です。

そして何よりもインストールが面倒。
そしてnodeやmavenがどんどんローカル環境を圧迫していく。

そして発生するMacとWindowsでの環境差異の問題。

極め付けばenvの設定ミスで違うバージョンが使われる。

devcontainerのススメ

devcontainerは、Docker上に開発環境を構築してそこで開発を全て行うための技術です。

GitHub codespaces(Visual Studio codespaces)を利用する場合のコア技術だったりもします。

簡単にいうと開発用の仮想マシンを内部にぽこじゃか作っていくことになるので、

Window AppやモバイルなどのGUIアプリの開発には若干不向きですが、
Web系は基本的にこれで事足ります。

そのため、nodeやRuby、PythonといったものをVSCodeで実行するのであれば、devcontainerで済ませることができます。

必要なもの

  • Docker Desktop
  • Visual Stidio Code
    • Remote Developmentの拡張機能

devcontainerを試しに使ってみる

今回は、例としてnodejs + Express + mongodbを使うことを前提とします。
ただし、mongoは立てるだけで実アクセスはしないことにします。

devcontainerの設定

.devcontainerというディレクトリを作り、その中にdevcontainer.jsonとdockerのコンテナに関する情報を格納します。

 Root Directory
  ├ .devcontainer 
  │   ├ devcontainer.json
  │   ├ docker-compose.yml
  │   └ Dockerfile
  └ 各ソース   

devcontainerを作る

コンテナとそこで動くVSCodeに関する情報を記載します。

.devcontainer/devcontainer.json
{
    // コンテナ名
    "name": "Express Sample",

    // docker-composeのファイル名
    "dockerComposeFile": "docker-compose.yml",

    // コンテナにアタッチされたプロジェクトのルートディレクトリ
    "workspaceFolder": "/work",

    // docker-composeが複数コンテナの場合、
    //  どのコンテナに入るのかを指定
    "service": "app",
    // 外部から接続するポート(開放ポート)を指定
    "appPort": 3000,

    // インストールする拡張機能を設定
    "extensions": [
        "VisualStudioExptTeam.vscodeintellicode",
        "dbaeumer.vscode-eslint",
        "stevencl.addDocComments",
        "eg2.tslint"
    ]
}

ここに記載した拡張機能はホストのVSCodeとはまた違う領域にインストールされます。

そのため、違う言語・プラットフォームに切り替えた際もVSCodeがクソ重くなるようなことは回避することができます。

Dockerの設定ファイルを作る

Dockerfileとdocker-compose.ymlを作成します。
これはdevcontainerに関係なく、開発用で使っているものをそのまま流用することも可能です。

.devcontainer/Dockerfile
FROM node:15.2.0-alpine3.10

EXPOSE 3000
.devcontainer/docker-compose.yml
version: '3'

services:
  app:
    build: .
    ports:
      - 3000:3000
    volumes:
      - ../:/work
    tty: true

  db:
    image: mongo:3.6.20-xenial
    # 本来ならポートやボリュームアタッチが必要。

開き直し

画面をリロードすると、開き直す?と聞かれるので「Reopen in Container」を選択

image.png

あとは画面がリロードされ、イメージの展開とコンテナの生成がおこなれれます。
VSCode関連のインストールも走るので、気長に待ちましょう。

image.png

無事起動したら、nodeが動いていることを確認します。

image.png

この時点で、VSCodeのターミナルはdockerコンテナのターミナルを指していますので、
基本的にはVSCode内のこのターミナルを利用するようにしてください。

アプリの開発

npm initしpackage.jsonを作ります。

# npm init -y
# nom install -S express

次に、以下のコードを作成します。

index.js
'use strict'

const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

app.get('/', (req, resp) => {
    resp.send('Hello, JS WORLD!');
})


app.listen(port, () =>{ 
    console.log(`Example app listening on Port ${port}`);
});

実行してみます。

# node index.js
node index.js
Example app listening on Port 3000

この状態でホストから接続してみましょう。

うまく表示されたら完成です。

image.png

あとは通常のVSCodeと同じように開発を進めることができます。

他の開発者への展開

他の開発者へ展開する場合も、devcontainerさえ作っておけば簡単に構築できます。

必要なのはVSCodeとリモート開発のための拡張機能のみです。

Node.js以外の設定

今回はnode.jsで行いましたが、PythonでもRubyでもJavaでも基本的な使い方は同じです。

次の2点についてのみ気をつけていれば、基本的に困りません。

  • コンテナのベースイメージ
  • インストールする拡張機能

さいごに

コンテナ単位で環境やバージョンを切り分けることができますので、
xEnvを使うよりも安全にバージョン問題を解決することができます。

また、開発環境としてDockerを用いているのであれば、簡単なjsonを書くだけで済みます。

もしVSCodeを使っているのであれば、devcontainerを用いて環境構築を簡略化してはいかがでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ローカルのdockerイメージからHerokuへデプロイする方法

デプロイする流れ

1 Heroku上にHerokuアプリを作成する。(URLが付与される) 

2 Herokuのコンテナレジストリ(Heroku上のDockerイメージ置き場)にDockerイメージをプッシュする。

3  Dockerイメージをアプリへリリース

4 デプロイしたアプリへブラウザでアクセス

事前にアカウントを作成し、クレジットカードを登録しておく。(クレジットカードを登録しないと公開できない。)

heroku cli のインストール(mac)

brew install heroku/brew/heroku

herokuへログイン

heroku login

自動起動するブラウザからログインする。

コンテナレジストリにログイン

heroku container:login

アプリに移動

※herokuはアプリのルートディレクトリ直下のdockerfileを参照する仕様。そのため、dockerfileが違う場所にある場合は、複製してルート直下にheroku用のdockerfileを配置する必要がある。

herokuでapacheを動かそうとするとエラーとなるので一部対処が必要。

エラー対処設定ファイルを作成

run-apache2.sh
sed -i "s/Listen 80/Listen ${PORT:-80}/g" /etc/apache2/ports.conf
rm /etc/apache2/mods-enabled/mpm_event.conf
rm /etc/apache2/mods-enabled/mpm_event.load
apache2-foreground "$@"

dockerfileでコンテナへコピーする記述と実行コマンドを追記

heroku用 dockerfile.
COPY ./docker/app/run-apache2.sh /usr/local/bin/
CMD [ "run-apache2.sh" ]

エラー対処設定ファイルに実行権限を付与する

chmod +x run-apache2.sh

herokuアプリを作成

heroku create

データーベースと連携させるためアドオンをインストールする。(ignite => 無料)

heroku addons:create cleardb:ignite

cleardbの接続設定を確認する。

heroku config | grep CLEARDB_DATABASE_URL

mysql:// ユーザー名 : パスワード @ ホスト名 /データーベース名 ?

環境変数の設定

heroku config:add DB_USERNAME=ユーザー名

heroku config:add DB_PASSWORD=パスワード

heroku config:add DB_DB_HOST='ホスト名' (.が入っているので'で括る)

heroku config:add DB_DATABASE=ユーザー名 

確認

heroku config

テーブルの作成

heroku run "テーブルの作成関数が記載されたファイル"

レジストリコンテナへプッシュ

heroku container:push web

レジストリコンテナへリリース

heroku container:release web

ブラウザ上からアクセス

heroku open

※複数のアプリを登録していた場合

heroku apps:info

アプリケーション名を調べてコマンドの末尾に

--app アプリ名 

を付与する。

herokuアプリを削除する方法

heroku apps:destroy --app アプリ名 -confirm アプリ名

heroku ログの確認(--tail で監視)

heroku logs --tail

修正を反映させる。
ローカルファイルを修正。

レジストリコンテナへプッシュ

heroku container:push web

レジストリコンテナへリリース

heroku container:release web
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubocopの設定を誤って地獄を見た件

Rubocopって何?

RuboCop Logo

Rubocop(ルボコップ)とは、Rubyのコードレビューツールの一種です。

コードレビューツールとは、「インデントが揃っていない」 「無駄な改行・スペースがある」などの指摘を、RubyStyleGuideに基づいて、構文チェックを行います。

Rubocop自体は、デフォルトでRubyのコードの書き方についてのルールを保持しています。
1行あたりの文字数制限や、文字列はすべてシングルクォーテーションで囲まなければならない、などです。こうしたルールはすべて、文法的にはエラーにはならないもののコードの可読性を下げるという理由で設定されています。

コマンドを叩けば悪しき箇所を表示してくるので、コードの保守性、可読性を保つための必須作業です。

※構文チェックは下記コマンドをターミナルで実行します。

bundle exec rubocop

※下記は1行が長すぎると怒られているエラー例
1行が198文字を超えてるから、160文字以下にしなさいと怒られています。
はい、すみません((((;゚Д゚)))))))

Offenses:

bin/bundle:104:161: C: Layout/LineLength: Line is too long. [198/160]
    warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"

長くなりましたが、そんなRubocopには使用準備が必要です。

現役エンジニアの方から伺った話ですが、実際の開発現場でも先輩エンジニアがコードレビューツールの使用準備を終えており、使用準備に関わらない事は普通にあるそうです。
そんなRubocopの使用準備に関わる機会に恵まれたので、その中で体験した地獄を書き記します。

  • Rubocopを構築した環境
    • Ruby2.7
    • Docker
    • Ruby on Rails6
    • Vscode

RubyのLintであるonkcop/pre-commitを入れたら、個人開発が幸せになった話
Rubocopの使用準備にあたり、上記の記事を大いに参照しています。
ありがとうございました?

Gemfileの記述と、rubocop.ymlファイルの作成

まずはGemfileにGemを導入します。
今回はGemfile内の:development doの部分に以下を記述します。

gem 'onkcop', require: false
gem 'rubocop-rails'

上記のonkcopは、Rubocopの拡張版でオニクコップと読むそうです。
onkcopの公式リポジトリはこちら

続いて下記コマンドをターミナルで順に実行します

①bundle install
②bundle exec onkcop init

そうすると、.rubocop.ymlというファイルが作成されるので、次のように書き換えます。

rubocop.yml
require:
  - rubocop-rails

inherit_from:
  - "config/rubocop/rubocop.yml"

inherit_gem:
  onkcop:
    - "config/rails.yml"
    - "config/rspec.yml"

AllCops:
  TargetRubyVersion: 2.7.1 ←※バージョンはruby -vで確認して合わせましょう。
  TargetRailsVersion: 6.0.3.4 ←※バージョンはrails -vで確認して合わせましょう。
  Exclude: ←※とても重要な部分
    - "vendor/**/*" # rubocop config/default.yml
    - "db/schema*.rb"
    - "node_modules/**/*"
    - "db/migrate/**/*" ←※構文チェックが不要ファイルがあれば、この下に追記していく。

使用準備はこれで終わりです。
そしたらコマンドを実行しましょう。

rubocopによる構文チェック(パトロール)の実行

あとはターミナルでbundle exec rubocopコマンドを打てば、Rubocopが無駄なコードを炙り出してくれるので適宜修正していきましょう。

bundle exec rubocop

コマンドを叩くと、下記のような大量出力が出てきますが、これがコード記述の規約違反です。これらがrubocopのパトロールに引っかかった構文エラーなので、適宜修正していきます。
rubocop1.png
最終的に、ターミナルでbundle exec rubocopコマンドを打ってコードに問題がなくなれば、下記のような表示に落ち着きます。

Inspecting 7 files
.......

7 files inspected, no offenses detected

また別途、重要になるのは.rubocop.ymlファイル内のExclude: の部分です。

bundle exec rubocopで構文エラーを炙り出すのですが、そもそもパトロールの必要がない部分もあります。Excludeは「除外」の意味なので、Excludeの下にパトロールの必要がないファイル名を記載する事で、Rubocopのパトロール時間が短縮できます。

パトロールの必要がない判断基準としては、Railsで自動生成されたファイルです。
加えて、人間が手を加えないファイルです。
手を加えない自動精製ファイルはパトロールさせるだけ時間の無駄です。

具体的には下記のようなRailsで自動作成されるファイルたちの事です。
任意でExclude:の下に追加していきましょう。

rubocop.yml
※ここより上のコードは省略

AllCops:
  TargetRubyVersion: 2.7.1 
  TargetRailsVersion: 6.0.3.4 
  Exclude: 
    - "vendor/**/*" # rubocop config/default.yml
    - "db/schema*.rb"
    - "node_modules/**/*"
    - "db/migrate/**/*" 
    - "app/channels/**/*"
    - "config/**/*"
    - "config.ru"
    - "bin/**/*"
    - "public/**/*"
    - "tmp/**/*"
    - "log/**/*"

上記のようにExclude: の下に追加したディレクトリや配下ファイルは、Rubocopによるパトロール対象外となります。以上でRubocopの設定と使い方は終わりです。

そして、最後に地獄を見た注意事項です。

bundle exec rubocopコマンドの種類に注意せよ!

※要注意コマンド
bundle exec rubocop -a

bundle exec rubocop -A

上記のようなコマンドも存在していますが、これらは安易に使用しては危険です。
Rubocopが親切心で自動修正をしてくれるコマンドですが、使用した事で厄介な事が起きました。

必要のない変更が全ファイルに適用されてしまった事です。

コマンドの効果の一つとして、文字列を囲うシングルクォーテーションを、全てのファイルでダブルクォーテーションにRubocopの親切心で自動修正されます。全てのファイルで、です!!

この時点でRubyの規約違反になりますし、英語の文脈がおかしくなる事もあります。
必要のないファイルが変換される無意味さに加え、コードの保守性を損ねるだけです。
コミットをプッシュした後だと更に泣けてきます?

コミット前の状態に戻す方法

コミットしたファイルはコミット前に戻す手段は、下記コマンドでコミット前に戻せますが、手動なので修正漏れが発生する恐れがあります。

①git logでコミット番号を確認
②git checkout {コミット番号} {コミット前に戻したいファイル名}

その為、自動修正が必要ないファイルは、上記の.rubocop.ymlファイルのExclude: の下に追加しておく事を強く推奨します。除外さえしておけば、自動修正コマンドが動いてもその影響から免れます。

vscodeを使ったコードの一括修正方法

もし手動でコードを修正する場合ですが、便利な手段を知ったので記載します。

同じファイル内で同一の記述を個別、または全て文字列を任意のものに変換できます。
個別修正と一括修正のどちらも可能ですが、修正の必要不要に関してはコードをチェックした上で行ってください。英語の文法がおかしくなる恐れがあります。
rubocop2.png
rubocop3.png
rubocop4.png
以上でRubocopの構築に際して沼った部分と対策は終わりです。
プログラミングには様々なコマンドがありますが、慣れないコマンドの実行には本当に注意しましょう。((((;゚Д゚)))))))

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Toolboxでファイル共有する方法

はじめに

Dockerで立ち上げたコンテナに、ローカルPCの任意のフォルダをマウントすれば
docker内の閉じたNW内に自由にファイルをおけるぜー!って思い、調べた結果をまとめる

なぜ今更こんな記事を上げるのか?

googleで「Docker windows ファイル 共有」で検索すれば瞬殺かと思ったらそんなことなくて
・記事の内容を見たら実はDocker for Windows向けだった(※Hyper-V クライアントが実行できないPCはDocker ToolboxでDocker環境を利用するため 参考にならない)
・virtualboxの設定(後述)はあったが、そのあとのdocker上でのコマンド方法の書式があいまいで、結局よくわからなかった
といった感じでイマイチ自分の置かれた環境とハマらなかったので苦労したので、
PCが飛んでもまたやり直せるように記事に残す。

手順(概要)

ちょっと概要だけではわけわからないけど、全部で3STEPあるってところが自分の中ではポイントだったのでメモとして残す。
1.Virtualboxにて共有フォルダ設定を行う
2.Docker Machineにてコンテナ用の共有フォルダを作成し、1.の共有フォルダをマウントする
3.コンテナをコンテナ用共有フォルダとコンテナの任意のディレクトリにマウントさせて起動する

手順(詳細)

1.Virtualboxにて共有フォルダ設定を行う

1.Oracle VM VirtualBoxを起動する
2.default→右クリック→設定
3.共有フォルダークリック
4.ポップアップしたウィンドウの右側にある共有フォルダ新規追加アイコンをクリック
5.下記内容を入力して「OK」
  フォルダーのパス:共有フォルダとして使いたいローカルPCのフォルダパスを入力
   例)C:\Users\watya\work\docker
  フォルダー名:docker-machineが認識するときのフォルダー名
C:\→/C/、\→/に置き換えるところがポイント
   例)/C/Users/watya/work/docker
image.png

2.Docker Machineにてコンテナ用の共有フォルダを作成し、1.の共有フォルダをマウントする

Docker Quickstart Terminal を起動し、コマンドを実行する。
以下のコマンドで /e に、1.で設定した共有フォルダー をマウントする。
これで、ローカルPC→VirtualBox→Docker machineというつながりでファイル共有がつながる。
Docker Machine 側に作成するディレクトリ名は e にしてますが、被らなければなんでもよいです。
個人的にはドライブ番号っぽくなって共有フォルダってことがわかりやすいので気に入っている。

DockerToolbox
$ docker-machine ssh default 'sudo mkdir -p /e'
$ docker-machine ssh default 'sudo mount -t vboxsf -o uid=0,gid=0 /C/Users/watya/work/docker /e'

image.png

3.コンテナをコンテナ用共有フォルダとコンテナの任意のディレクトリにマウントさせて起動する

Docker Toolboxより、コマンドを実行する。
以下のコマンドで、2.で作成した/eがnginxコンテナの/homeにマウントされる。

DockerToolbox
$ docker run -d -v /e:/home --name nginx nginx

確認のためにログインして/homeの内容をチェックすると無事マウントされていることが確認できる

image.png

補足:Docker Machine 起動時に自動でマウントするよう設定

参考URL

今回参考にしたサイトは下記の通り。
っていうかこちらのほうが丁寧で内容の説明が深いのでよくわからなくなったら折に触れて立ち返りたい。
https://humo-life.net/memo/doku.php?id=%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2:docker:docker_toolbox%E3%81%A7%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88_%E5%85%B1%E6%9C%89%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80_%E8%A8%AD%E5%AE%9A

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Error: EPERM: operation not permitted, open '/usr/src/app/src/App.vue'

npm run serve をした際に operation not permitted が出た。

Error: EPERM: operation not permitted, open '/usr/src/app/src/App.vue'

vue-cliアプリをビルドしようとすると、エラーが発生します。依存関係のインストールとアプリの提供は正常に機能していました。

結論

npm install -g @vue/cli --cache /tmp/empty-cache

上記コマンドで解決。

環境

  • Docker
  • Vue
  • Vue CLI
$ npm --version
$ @vue/cli 4.5.8

起きた原因

スクリーンショット 2020-11-15 13.45.26.png

Vue CLI Issue をみる限り、みなさん npm cache clean force はしているようですね。

自分が今回起きたのは 「build に時間がかかるな」 と思ったので 最近していなかった再起動をしました。
↑ 怒らないでください笑

そうすると 今回のErrorが出ました。
理由は正直わかりません。もしわかる方がいらっしゃいましたら、ご教授頂けますと幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでWordpress開発環境をサクッと構築

はじめに

Dockerはインストール済みとします。
Wordpressのテーマ開発を行う場合にサクッと環境構築できます。

Mac 0SX
Docker 19.03.13

環境構築

以下のdocker-compose.ymlを環境を作りたいディレクトリに作成してください。

docker-compose.yml
version: "2"

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "3001:80"
    depends_on:
      - mysql
    env_file: .env
    volumes:
      - ./wp-content:/var/www/html/wp-content

  mysql:
    image: mysql:5.7
    env_file: .env
    ports:
      - "3306:3306"

docker-compose.ymlを作成したディレクトリに移動して、docker-composeコマンドを実行してください。

bash
$ cd 作成したファイルのディレクトリ
$ docker-compose build
$ docker-compose up

ブラウザでアクセスしてセットアップ

これで環境が立ち上がったと思いますので、以下のURLでアクセスして、サイト名やDB構築などをします。
http://localhost:3001/

すると以下のようなフォルダが作成されるかと思います。

├── docker-compose.yml
└── wp-content
    ├── index.php
    ├── languages
    ├── plugins
    ├── themes
    ├── upgrade
    └── uploads

テーマ開発をする際はwp-content/themesの中のテーマを修正することでできます。

2回目移行の立ち上げはDockerのダッシュボードから実行ボタンをクリックして立ち上げるのが早くて便利です。
停止もダッシュボードから行えます。

php.iniなどを変更したい場合は、ダッシュボードのwordpress_wordpress_1の右側に表示される「CLI」ボタンをクリックするとコンテナに接続できるので、そこからviなどを使用して編集することができます。

dashboard.png

終わりに

なにか間違いがあればご指摘ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPのパフォーマンス調査 PHP5とPHP7の処理速度

背景

PHP5からPHP7へアップデートするだけで処理速度が大幅にアップするという話を聞いたので検証してみることにした。

※ ごめんなさい。
 最もらしい建前を立ててみたけど、嘘です。
 実際はQiitaへの投稿に慣れるための記事なので、
 1つの例として参考にしてもらえる程度だと嬉しいな。

この記事の対象者

  • Dockerfileのシンプルなサンプルをみたい人
  • Dockerのamazonlinux2コンテナ内でPHPをインストールしたい人

この記事で記載していない内容

  • LaravelやCakePHP等、フレームワークのセットアップ方法
  • NginxやApache等、ウェブサーバー用ミドルウェアのセットアップ方法

上記の内容が知りたい方は他の記事を参考にされた方が良いと思いますので、そっとページを閉じていただけると幸いです。

検証環境

Machine: Mac mini (2018)
OS: macOS Catalina バージョン 10.15.7
仮想環境: Docker AmazonLinux2イメージ
PHP5: PHP 5.6.40
PHP7: PHP 7.3.24

Dockerfileの内容

PHP5もPHP7もログインしてからPHPをインストールするので、同じDockerfileを使用しています

Dockerfile
# AmazonLiunx2のイメージを使うよ
FROM amazonlinux:2

# ここではユーザー'bearrabi'で管理者用コマンドを使えるようにしてるだけだよ。
# PHPインストールのコマンドはここには書いてないよ
RUN yum -y update && \
  yum clean all && \
  yum install -y sudo && \
  yum install -y vim && \
  yum install -y systemd && \
  yum install -y yum-utils && \
  useradd bearrabi && \
  echo "bearrabi ALL=NOPASSWD: ALL" >> /etc/sudoers

# コンテナログイン時のカレントディレクトリを指定
WORKDIR /usr/local/sbin

Docker イメージのビルドからログインまで

terminal
# ディレクトリを紐づけるために、ローカルにディレクトリを作成
# 途中のディレクトリが存在しないとエラーになるから注意ね
% mkdir /Users/bearrabi/php_56/work

# 自分の指定した名前で、Dockerfileの内容をイメージ化
% docker build . -t php_dif_img

# イメージからコンテナを生成してログイン可能状態にする
% docker run -d --name php_dif_con --privileged -v /Users/bearrabi/php_56/work:/usr/local/sbin:rw php_56_img /sbin/init

# 生成したコンテナにログイン
% docker exec -it -u bearrabi php_dif_con /bin/bash

[【ユーザー】@【コンテナID】 sbin]$ となっていればログインに成功してます。
自分の環境では以下になりました。

terminal
[bearrabi@82461436bd6c sbin]$ 

PHP5.6をインストール

terminal
### epel(Extra Packages for Enterprise Linux)リポジトリをインストール
# レポジトリは「貯蔵庫」の意味で、epelはOSに存在していないものを保管します
# remiレポジトリをインストールするのに必要です
$ sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

### remiレポジトリをインストール
# remiレポジトリにはPHPが保管されています
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

### 各リポジトリのアップデート
$ sudo yum -y update --disablerepo=amzn2-core --enablerepo=epel,remi,remi-php56

### PHP5.6をインストール
$ sudo yum -y install --enablerepo=remi,remi-php56 php56 

PHPのVersion確認

terminal
$ php56 -v
PHP 5.6.40 (cli) (built: Sep 29 2020 11:42:56) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

PHP 5.6.40がインストールされました。

処理速度検証(PHP 5.6.40)

ソースコード

test.php
<?php

  // 速度計測の開始時刻をミリ秒で取得
  $start_time = microtime(true);

  // この変数をループ回数の上限とする
  $max_loop_index = 100000000;

  // ループで上限値まで繰り返し
  $counter = 0;
  for($i=0; $i<$max_loop_index; $i++){ $counter += 1; }

  // 速度計測の終了時刻をミリ秒で取得
  $end_time = microtime(true);

  // 処理開始から終了まで何ミリ秒必要だったかを取得
  $time_defference = $end_time - $start_time;

  // 計測時間を出力
  print "time: ".$time_defference."秒\n";

  // ループ処理が最後まで完了しているか確認
  print "counter: $counter 回ループ処理を行いました\n";
?>

スクリプトの実行と計測結果

terminal
$ php56 test.php 
time: 8.2781031131744秒
counter: 100000000 回ループ処理を行いました

何度やっても大体8.2秒でした。

PHP5.6をPHP7.3へアップデート

terminal
# インストール済みのPHPを削除
$ sudo yum -y remove php*

# インストール済みのepelレポジトリを削除
$ sudo yum -y remove epel*

# 新しいepelレポジトリをインストール
$ sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-12.noarch.rpm

# 新しいremiレポジトリをインストール
$ sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

# レポジトリのアップデート
$ sudo yum -y update --disablerepo=amzn2-core --enablerepo=epel,remi,remi-php73

# php7.3をインストール
$ sudo yum -y install --disablerepo=amzn2-core --enablerepo=remi,remi-php73 php

PHPのバージョン確認

terminal
$ php -v
PHP 7.3.24 (cli) (built: Oct 27 2020 11:01:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.24, Copyright (c) 1998-2018 Zend Technologies

PHP 7.3.24がインストールされました

処理速度検証(PHP 7.3.24)

terminal
$ php test.php 
time: 0.89267206192017秒
counter: 100000000 回ループ処理を行いました

あれ?
全く差がないどころか、PHP7.3の方が少し遅いじゃないか!!

考察

恐らく、単純にインタプリタの処理が早くなった訳ではないのでしょう。
他の記事では、ライブラリを利用した計算時の処理速度とメモリの使用状況をモニタリングしていました。

※参照
PHPのパフォーマンス比較(5.3〜7.0)

この記事では明らかにPHPのバージョンアップによって処理速度が早くなっています。
なので、一概に嘘ではないかと。

最後に

今回はPHPのバージョンによる速度の処理速度の検証を行いました。
結果的には、単純な処理をさせても処理速度に差は発生しないという結果です。
パフォーマンス改善を提案する時の簡単なエビデンスとしたかったのですが、残念?

とはいえ、Dockerの簡単な使い方や、amazon-extra-installを利用しないPHPのインストール方法など、最小限に記載することはできたかと思います。
どなたかのお役に立てれば幸いですね。

以上です。
最後まで読んでいただき、ありがとうございます☺️

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub ActionでDockerのビルドキャッシュを有効にしてAmazonECSへデプロイする

やること

GitHub Actionを用いてDockerイメージをビルドし、Amazon ECRに保存し、Amazon ECSへデプロイします。

  • ポイント
    • 本番運用を想定し、ブランチにリリースを作成した場合にGitHub Actionが動作するようにする。
    • Dockerのビルドを高速化するために、ビルドキャッシュを有効にする

準備

  • 保存先のECRを作成
  • デプロイ先のECRを作成
  • GitHub Actionで使用するためのAWS IAMユーザーを作成(ECRとECSの権限が必要です)

これらは作成済みとして進めます。

作成するワークフロー

下記のようなワークフローを作成し、レポジトリの.github/workflows/deploy-to-ecs.ymlのような適当な名前で保存します。
mainブランチにtagをpushすることにより、このワークフローが動作し、ECRへDockerイメージがpushされ、ECSへデプロイします。
Githubのリリースを用いることにより運用することを想定しています。

.github/workflows/deploy-to-ecs.yml

name: Deploy to ECS 
on:
  push:
    tags:
      - v*

env:
  ECR_REPOSITORY: your-repository-name
  ECS_SERVICE: your-service-name
  ECS_CLUSTER: your-cluster-name

jobs:
  deploy:
    name: Deploy to ECS
    if: github.event.base_ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Configure AWS Credentials # AWSアクセス権限設定
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Login to Amazon ECR # ECRログイン処理
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Set Docker Tag Env # Docker Imageのバージョンをタグに合わせる
        run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

      - name: Build, tag, and push image to Amazon ECR # Docker イメージ Build&Push
        env:
          DOCKER_BUILDKIT: 1
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          docker build --cache-from=$ECR_REGISTRY/$ECR_REPOSITORY:latest --build-arg BUILDKIT_INLINE_CACHE=1 -f Dockerfile -t $ECR_REPOSITORY .
          docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:latest
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

      - name: Render Amazon ECS task definition for app container # appコンテナのECSタスク定義ファイルレンダリング
        id: render-app-container
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: .aws/ecs/task-definition.json
          container-name: app
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}

      - name: Deploy to Amazon ECS service # ECSサービスデプロイ
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-app-container.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: false

解説

ワークフローの動作について上から順に具体的に説明します。

1. ワークフロー名

name: Deploy to ECS 

ワークフローの名前を決めています。Githubのレポジトリ、Actionタブからワークフローを一覧で確認する際などにこの名前が表示されます。検証環境や本番環境で複数のワークフローを作成する場合は、区別できる分かりやすい名前に変更する事を推奨します。

2. ワークフローの動作条件

on:
  push:
    tags:
      - v*

v1.0.0のようなvで始まるタグがpushされた場合に動作するようにしており、リリースの作成によりこのワークフローが動作することを想定しています。
また、今回は他のブランチにタグがpushされてしまった場合に動作をしないようにjobs内に

if: github.event.base_ref == 'refs/heads/main'

のようにmainブランチではない場合には動作をしないようにしています。

特定のブランチにpushされた場合に動作するようにするにはifの記述を無くし

on:
  push:
    branches:
      - target-branch

のように記述してください。(target-branchはデプロイ対象とするブランチに変更して下さい。)

補足

on: push:の記述方法で、特定のブランチにタグがpushされた場合動作するという事を実現するために

on:
  push:
    tags:
      - v*
     branches:
      - target-branch

のように記述すると、and条件ではなくor条件(タグかブランチのどちらかがpushされた場合)になってしまう為、on: push:で対象のタグを指定し、ifで対象のブランチを指定しています。

3. 環境変数への代入

env:
  ECR_REPOSITORY: your-repository-name
  ECS_SERVICE: your-service-name
  ECS_CLUSTER: your-cluster-name

jobで何度も使う値の記述を減らすために環境変数へ代入しています。
your-〇〇〇-nameは各自の環境のものへ変更して下さい

4. Jobsの実行開始

jobs:
  deploy:
    name: Deploy to ECS
    if: github.event.base_ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

ubuntu-latestの環境にて対象ブランチにcheckoutし、jobの実行を始めます。
(先程にも記述しましたが、タグがpushされた場合のmainブランチでのみ実行するようにif行を記述しています。動作条件をブランチのpushに変更した場合は不要です。)

5. AWSへのログイン

- name: Configure AWS Credentials # AWSアクセス権限設定
    uses: aws-actions/configure-aws-credentials@v1
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ap-northeast-1

pushを行うECR、デプロイ先のECSを作成してあるAWS アカウントへログインをしています。
Githubのシークレットを用いてデプロイを行うIAMのアクセスキーとシークレットキーをAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYへ登録してください。

6. ECRログイン

 - name: Login to Amazon ECR # ECRログイン処理
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

5.でログインしたAWSアカウントのECRへのログインを行います。

7. Dockerのイメージタグの設定

  - name: Set Docker Tag Env # Docker Imageのバージョンをタグに合わせる
    run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

Dockerのイメージタグがgitのtagと同じ値になるようにpushされたtagをv1.0.0のような形式で取り出し、環境変数へ代入しています。
ワークフローの動作条件にタグを用いない場合は、

run: echo "::IMAGE_TAG=${{ github.sha }}" >> $GITHUB_ENV

のようにコミットハッシュを用いてイメージタグが一意になるようにすると良いと思います。

8. Dockerイメージのビルド&ECRへのPush

  - name: Build, tag, and push image to Amazon ECR # Docker イメージ Build&Push
    env:
      DOCKER_BUILDKIT: 1
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
    run: |
      docker build --cache-from=$ECR_REGISTRY/$ECR_REPOSITORY:latest --build-arg BUILDKIT_INLINE_CACHE=1 -f Dockerfile -t $ECR_REPOSITORY .
      docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
      docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:latest
      docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
      docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

ローカルでDockerイメージをビルドする場合、前回にビルドしたイメージを用いてビルドが高速化されますが、GitHub Actionでは前回のビルド結果を保持していないため、毎回ビルドに時間が掛かってしまいます。
そこで、ここではDockerのdocker build --cache-fromを用いてビルドの高速化を行っています。
行っている内容としては、dockerイメージをビルドし、環境変数IMAGE_TAGに保存されているタグをpushしつつ、その値はワークフローの動作毎に動的に変化してしまい、前回ビルドした際の値を取得することが難しいためlatestタグもpushし、latestタグをキャシュに用いるようにしています。このようにすることにより、リリースタグと整合性を取りつつ、キャッシュを用いれます。
(DOCKER_BUILDKIT, BUILDKIT_INLINE_CACHE--cache-fromを用いるために必要なため記述しています。)
注意: Dockerのマルチステージビルドを用いている場合は、Dockerのイメージ中にビルドプロセスが全て含まれていないためこの方法ではキャッシュできません。その場合は、このような記事を参考にすると良いと思います。

9. ECSタスク定義の作成

- name: Render Amazon ECS task definition for app container # appコンテナのECSタスク定義ファイルレンダリング
    id: render-app-container
    uses: aws-actions/amazon-ecs-render-task-definition@v1
    with:
      task-definition: .aws/ecs/task-definition.json
      container-name: app
      image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}

ECSの実行にはタスク定義が必要になり、そこに使用するDockerイメージのレポジトリやタグの情報を記述する必要があります。
従って、DockerImageを更新した際はタスク定義の更新も必要になり、その処理を行っています。

今回はレポジトリへタスク定義ファイル.aws/ecs/task-definition.jsonを作成してあり、そのファイルを呼び出し、Dockerイメージの情報を更新しています。
task-definition.jsonの参考例)

{
  "containerDefinitions": [
      "portMappings": [
        {
          "hostPort": 80,
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "image": "your-image-name",
      "name": "app"
    }
  ],
  "cpu": "256",
  "executionRoleArn": "your-role-name",
  "family": "your-family",
  "memory": "512",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "networkMode": "awsvpc"
}

s3から読み出す事も可能のようなので各々お好きなタスク定義の管理をして下さい。

10. ECSへデプロイ

- name: Deploy to Amazon ECS service # ECSサービスデプロイ
    uses: aws-actions/amazon-ecs-deploy-task-definition@v1
    with:
      task-definition: ${{ steps.render-app-container.outputs.task-definition }}
      service: ${{ env.ECS_SERVICE }}
      cluster: ${{ env.ECS_CLUSTER }}
      wait-for-service-stability: false

9で作成したタスク定義をもとにECSへデプロイしています。
wait-for-service-stabilitytrueにすることにより、デプロイが完了するまで実行完了を待機させ、デプロイ完了を通知すること等が可能ですが、Github Actionsの実行時間が増加してしまい、実行枠を越えてしまう等の可能性が存在します。
AWS Lambdaを用いてデプロイの完了をフックし、通知する事も可能なのでデプロイの多い環境ではそうする事を推奨します。

11. おわり

上記のフローが正しく動作すればデプロイ完了です。

おまけ. task単体の実行

- name: Run Migrate # Migrationを実行
    env:
      CLUSTER_ARN: your_cluster_arn
      ECS_SUBNER_FIRST: your_subnet_first
      ECS_SUBNER_SECOND: your_subner_second
      ECS_SECURITY_GROUP: your_security_group
    run: |
      aws ecs run-task --launch-type FARGATE --cluster $ECS_CLUSTER --task-definition ${{ steps.put-migrate-task.outputs.render-app-container }} --network-configuration "awsvpcConfiguration={subnets=[$ECS_SUBNER_FIRST, $ECS_SUBNER_SECOND],securityGroups=[$ECS_SECURITY_GROUP],assignPublicIp=ENABLED}" > run-task.log
      TASK_ARN=$(jq -r '.tasks[0].taskArn' run-task.log)
      aws ecs wait tasks-stopped --cluster $CLUSTER_ARN --tasks $TASK_ARN

今回デプロイ前にDBのmigrationを行いたく、このようなjobを手順10のECSへデプロイ前に追加しtaskを単体で実行しました。
このようにすることにより、Github Actions内でtask単体を実行することも可能です。

まとめ

ECSへのデプロイですとAWS CodeBuild、AWS CodePipelineを組み合わせるといった選択肢もあると思いますが、GitHub Actionを用いても簡単にデプロイすることが可能です。

参考記事

下記の記事を大変参考にさせて頂きました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

APIとフロントのアプリ両方が含まれたdocker-composeプロジェクトに VSCode Remote Containersを導入する方法

背景

  • 社内で新規プロジェクトを立ち上げる上で、Visual Studio Code(以下 VSCode)のプラグインであるRemote - Containersを使用して開発したかった。
    • docker利用で、アプリケーションの動作環境はチーム内で共通化できるが、エディタの動作環境の構築は各メンバーに任されたままである。今回のプロジェクトでは、eslintやrubocopなどの構文チェックやコード補完ツールを複数個入れることが序盤から決まっていたので、Remote - Containersを入れることで、エディタの動作環境もまとめてdockerでメンバーと共有して効率化したかった。
  • 今回のプロジェクトでは、同一プロジェクトの中で、APIとフロントを別々のレポジトリとしてgit管理しており、それらを同一のdocker-compose.ymlで管理しているという条件だった。この場合のRemote - Container設定の書き方でかなり悩んだ。

想定読者

  • すでに docker-compose.yml で管理しているプロジェクトがあり、そのプロジェクトの中に複数のアプリケーション(例:APIとフロント)が含まれている
  • それぞれのアプリケーションを Remote - Containersで開発できるようにしたい

修正前のプロジェクト構成

フォルダ構成

project-docker
┣ project-api (railsのレポジトリ)
┃ ┣ app
┃ ┣ ...
┃ ┗ Gemfile
┣ project-front (Next.jsのレポジトリ)
┃ ┣ .next
┃ ┣ ...
┃ ┗ package.json
┣ docker-compose.yml
┣ Dockerfile.backend
┗ Dockerfile.frontend

project-docker 直下で docker-compose up を叩くと、APIとフロント(とDB)が同時に起動してハッピー、という構成。

docker-compose.yml

docker-compose.yml が 以下。ひとまずservicesが少なくとも以下の3つがある。

  • db
  • backend
  • frontend

※本当はredisとかsmtpとかもあったけどこの記事の趣旨には関係ないから除外した

docker-compose.yml(一部省略)
services:
  db:
    image: postgres:11.5
    ports:
      - "5432:5432"
  backend:
    build:
      context: .
      dockerfile: Dockerfile.backend
    volumes:
      - ./project-api:/project-api
    command: /bin/sh -c "rm -f /api-okapi/tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3000:3000"
    depends_on:
      - db
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.frontend
    command: npm run dev
    volumes:
      - ./project-front:/project-front
    ports:
      - "8080:8080"

Remote - Containers の導入手順

  • 基本的には、各レポジトリ(project-api, project-front)の下に Remote - Containers の設定ファイルを入れるディレクトリ .devcontainer を作成し、その下に devcontainer.jsondocker-compose.extend.yml の2つの設定ファイルを作成するのが目標になります。

前提

  • VScodeおよびdockerはインストール済み
  • VScodeの拡張機能ペインから、Remote - Containers をインストール済み
    • インストールすると、VScodeの画面左下にRemote - Containersのアイコンが追加されます

手順

api側を例に解説します。front側は同じことをやり直してください。

1. .devcontainer を自動作成する

  1. 「file(ファイル)」の「open workspace(ワークスペースを開く)」から、 project-docker を開く
  2. 画面左下にRemote - Containersのアイコンをクリックし、Reopen in Container を選択
  3. From docker-compose.yml を 選択
  4. select a service で backend を選択
  5. project-docker 直下に、 .devcontainer ディレクトリと、 その下に devcontainer.jsondocker-compose.yml の2つの設定ファイルが作成されるので、これを project-api の下に移動させる

2. .devcontainer/devcontainer.json の修正

自動的に作られた直後の .devcontainer/devcontainer.json は以下です。

devcontainer.json
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
    "name": "Existing Docker Compose (Extend)",

    // Update the 'dockerComposeFile' list if you have more compose files or use different names.
    // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
    "dockerComposeFile": [
        "../docker-compose.yml",
        "docker-compose.yml"
    ],

    // The 'service' property is the name of the service for the container that VS Code should
    // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
    "service": "backend",

    // The optional 'workspaceFolder' property is the path VS Code should open by default when
    // connected. This is typically a file mount in .devcontainer/docker-compose.yml
    "workspaceFolder": "/workspace",

    // Set *default* container specific settings.json values on container create.
    "settings": {
        "terminal.integrated.shell.linux": null
    },

    // Add the IDs of extensions you want installed when the container is created.
    "extensions": []

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [],

    // Uncomment the next line if you want start specific services in your Docker Compose config.
    // "runServices": [],

    // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
    // "shutdownAction": "none",

    // Uncomment the next line to run commands after the container is created - for example installing curl.
    // "postCreateCommand": "apt-get update && apt-get install -y curl",

    // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
    // "remoteUser": "vscode"
}

これを以下に書き換えます。

devcontainer.json(修正部分のみ)
{
    "name": "project-api-docker", // 適当にナイスな名前にする
    "dockerComposeFile": [
        "../../docker-compose.yml", // フォルダ移動したのでパスを修正
        "docker-compose.extend.yml" // .extend をつける (動作するだけなら不要だけど私はわかりやすさを重視して名前を変えました)
    ],
    "runServices": [
        "db",
        "backend",
        // stmpなど他のサービスがあれば追加。 "frontend" を 含めないのが重要。空だと、デフォルトで全てのserviceを起動する。
    ],
    "workspaceFolder": "/workspace/project-api/", // workspaceを project-api にする
}

3. docker-compose.yml の修正

自動的に作られた直後の .devcontainer/docker-compose.yml は以下です。

docker-compose.yml
version: '3'
services:
  # Update this to the name of the service you want to work with in your docker-compose.yml file
  backend:
    # If you want add a non-root user to your Dockerfile, you can use the "remoteUser"
    # property in devcontainer.json to cause VS Code its sub-processes (terminals, tasks, 
    # debugging) to execute as the user. Uncomment the next line if you want the entire 
    # container to run as this user instead. Note that, on Linux, you may need to 
    # ensure the UID and GID of the container user you create matches your local user. 
    # See https://aka.ms/vscode-remote/containers/non-root for details.
    #
    # user: vscode

    # Uncomment if you want to override the service's Dockerfile to one in the .devcontainer 
    # folder. Note that the path of the Dockerfile and context is relative to the *primary* 
    # docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
    # array). The sample below assumes your primary file is in the root of your project.
    #
    # build:
    #   context: .
    #   dockerfile: .devcontainer/Dockerfile

    volumes:
      # Update this to wherever you want VS Code to mount the folder of your project
      - .:/workspace:cached

      # Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker-compose for details.
      # - /var/run/docker.sock:/var/run/docker.sock 

    # Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
    # cap_add:
    #   - SYS_PTRACE
    # security_opt:
    #   - seccomp:unconfined

    # Overrides default command so things don't shut down after the process ends.
    command: /bin/sh -c "while sleep 1000; do :; done"

まず、ファイル名を .devcontainer/docker-compose.extend.yml に変更しておきます。
これは、.devcontainer/docker-compose.extend.yml は、project-docker 直下の docker-compose.yml の一部要素を上書きしているだけの存在であることをわかりやすくするためです。

そして、.devcontainer/docker-compose.extend.yml の中身を以下に書き換えます。

docker-compose.extend.yml(修正部分のみ)
services:
  backend:    
    volumes:
      - .:/workspace:cached
      - ~/.gitconfig:/root/.gitconfig # ローカルの.gitconfig設定をコンテナ内に共有するため、コンテナ側のホームディレクトリ(この場合は/root)にマウントします。
      - ~/.ssh:/root/.ssh # ローカルの.ssh 設定ををコンテナ内に共有するため(以下略)
      - /var/run/docker.sock:/var/run/docker.sock # 一応アンコメントしてるけど必要性がよくわかってない。誰か教えてください・・・
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0' ; while sleep 1000; do :; done" 
  • 特に command の修正が重要。元の記述のままだと、親玉の docker-compose.ymlbackendcommand (今回の場合はrailsのサーバー起動コマンド) を上書きしているので、サーバーが起動しません。 元の記述を持ってきて、最後に while sleep 1000; do :; done を加えます。
  • circleci系のコンテナなど、 コンテナ側のユーザがrootではないコンテナを使っている場合は、"environment" で環境変数 HOME の指定が必要だそうです。詳しくはこっちの記事を参照してください。

4. Remote - Containers で開く

  1. 設定が完了したので、「file(ファイル)」の「open workspace(ワークスペースを開く)」から、このリポジトリの直下にcloneした api-okapi (or front-okapi) を開きます。
  2. 左下のアイコンをクリックし、 Remote-Containers: Reopen in Container を選択します。
  3. 自動的にcontainerが起動し、コンテナ内でVSCodeが開きます。(ビルドが必要な場合、長い時間がかかります)

front側の相違点

  • front側を設定するときは、 runServices の中を frontend のみにしてください。
devcontainer.json(修正部分のみ)
{
    "runServices": [
        "frontend"
        // "db",
        // "backend",
    ],
}
  • このように、backend側とfrontend側で起動するserviceを振り分けることで、同時にbackend側とfrontend側をRemote - Containersで起動しても、それぞれのレポジトリで起動するserviceが衝突しないので安心。(必要ないかもしれない。誰か詳しい人教えてください)
  • 親の docker-compose.yml の方で depends_on を指定していると、 runServices の設定から外しても起動するのでご注意ください。

導入後の設定

VScodeのエディタ設定の変更

  • 例: .tsファイルを保存する度に、ESLintでフォーマットが走るようにする
  • 各レポジトリの .devcontainer/devcontainer.jsonsettings の中を修正してください。
    • ここが .vscode/settings.json の代わりになります。
.devcontainer/devcontainer.json
{
    "settings": {
        "editor.codeActionsOnSave": {
            "source.fixAll.eslint": true // ファイル保存時にESLintでフォーマット
        }
        ...
    },
}

VScodeのプラグイン設定の変更

  • 例: eslint の VScodeプラグインを入れる
  • 各レポジトリの .devcontainer/devcontainer.jsonextensions の中を修正してください。
    • 各プラグインのIDは、VScodeの拡張機能ペインにて、該当のプラグインを右クリックして「拡張機能IDをコピーする」で取得できます。
  • 通常通り、VScodeの拡張機能ペインからプラグインを追加することもできますが、この場合、他の開発者の環境には追加されないっぽい?。
.devcontainer/devcontainer.json
{
    "extensions": [
        "dbaeumer.vscode-eslint",
        ...
    ],
}

bash設定の変更

  • 例: gitコマンドの補完スクリプトを入れる
  • .bashrc などのファイルを準備した上で、docker-compose.ymlvolume を修正して、container側のホームディレクトリ(この場合は/root)直下にマウントしてください。
    • 以下では、 project-docker の 下に bash-config フォルダを用意して、親玉の方の docker-compose.yml でマウントの設定をしてます。
docker-compose.yml
frontend:
  volumes:
    - ./bash-config/.bashrc:/root/.bashrc
    - ./bash-config/.git-completion.bash:/root/.git-completion.bash
    - ./bash-config/.git-prompt.sh:/root/.git-prompt.sh
    ...
  • 各レポジトリでbashの設定を変えたい場合は、 各レポジトリ以下に bash-config フォルダを用意して docker-compose.extend.yml の設定を変えるといいでしょう。

参考

VSCode Remote Container関連

導入後の設定関連

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナ内でgnome-terminalの実行を試みるもエラー(ailed to execute child process “dbus-launch” (No such file or directory))

Dockerコンテナ内でgnome-terminalの実行を試みるも以下の通りエラー

# gnome-terminal -e "python3 test.py"
# Option “-e” is deprecated and might be removed in a later version of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to execute after it.
# Error constructing proxy for org.gnome.Terminal:/org/gnome/Terminal/Factory0: Failed to execute child process “dbus-launch” (No such file or directory)

dbus-x11をインストールして解決

sudo apt-get install -y dbus-x11

gnome-terminalがない場合は以下でインストール可能

sudo apt-get install -y gnome-terminal

参考

simple interprocess messaging system (X11 deps)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナ内でgnome-terminalの実行を試みるもエラー(Failed to execute child process “dbus-launch” (No such file or directory))

Dockerコンテナ内でgnome-terminalの実行を試みるも以下の通りエラー

# gnome-terminal -e "python3 test.py"
# Option “-e” is deprecated and might be removed in a later version of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to execute after it.
# Error constructing proxy for org.gnome.Terminal:/org/gnome/Terminal/Factory0: Failed to execute child process “dbus-launch” (No such file or directory)

dbus-x11をインストールして解決

sudo apt-get install -y dbus-x11

gnome-terminalがない場合は以下でインストール可能

sudo apt-get install -y gnome-terminal

参考

simple interprocess messaging system (X11 deps)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む