20200909のdockerに関する記事は15件です。

DockerでのRails環境構築(個人的黙示録)

Dockerfileの作成

-# ビルドコンテキスト
% mkdir product-register
% cd product-register
-# GemfileとGemfile.lockの作成
% touch Gemfile Gemfile.lock
-# Gemfileの編集
% vim Gemfile
product-register/Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5.2'
-# Dockerfileの編集
% vim Dockerfile
product-register/Dockerfile
FROM ruby:2.5
RUN apt-get update && apt-get install -y && \
    buile-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /product-register
COPY Gemfile Gemfile.lock /product-register/
RUN bundle install
-# コンテナの作成
% docker build .

docker-compose.ymlの記述

-# docker-compose.ymlの編集
% vim docker-compose.yml
docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - '.:/product-register'
    tty: true
    stdin_open: true
-# コンテナの立ち上げ
% docker-compose up -d
-# コンテナ内に入って作業をする場合 
% docker-compose exec web bash

Railsのセットアップ

-# アプリの作成、DBの設定、bundleはDockerfileで行うので—skip
# rails new . —force —database=postgresql —skip-bundle
-# ホスト側でGemfileの内容が変わっていることを確認する
% cat Gemfile
-# bundle installする必要があるので一度停止する
# exit
$ docker-compose down
-# docker-compose upをすると前のイメージが使われるので再度buildを行う
$ docker-compose up —build -d
% docker-compose exec web bash
-# railsのサーバを起動
$ rails s -b 0.0.0.0

localhost:3000で接続できるがDBの設定を行っていないのでエラーページとなる。

DBのセットアップ

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  user: postgres
  port: 5432
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>
  # For details on connection pooling, see Rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

Passwordはセキュリティ的に直接書くのは望ましくないので環境変数で呼び出すようにする。

docker-compose.ymlの変更

docker-compose.yml
version: '3'
# dockervolumeここにデータが保存される
volumes: 
  db-data:

services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - '.:/product-register'
# コンテナの環境変数設定、本来は直接パスワードを書いてはいけない。
    environment:
      - 'DATABASE_PASSWORD=postgres'
    tty: true
    stdin_open: true
# dbサービスが作られたら作成される
    depends_on:
      - db
# webからdbにアクセスできる
    links:
      - db
# postgresのコンテナ
  db:
    image: postgres
# ホストのdb-dataにデータを保管
    volumes:
      - 'db-data:/var/lib/postgresql/data'
    environment:
      - 'POSTGRES_USER=postgres'
      - 'POSTGRES_PASSWORD=postgres'

docker-composeで起動

% docker-compose up -d
-# 2つのサービスが起動しているのが確認できる
Creating product-register_db_1 ... done
Recreating product-register_web_1 ... done
% docker-compose exec web bash
-# DBの作成
# rails db:create
Created database 'product-register_development'
Created database 'product-register_test'

データベースが作られているのが確認できる。
ここからRailsのアプリを作成することができる。

アプリを作り動作を確認する

-# scaffoldで簡単なアプリを作る
# rails g scaffold product name:string price:integer vender:string
-# 作成したテーブルを定義する
# rails db:migrate
-# サーバを立ち上げる
# rails s -b 0.0.0.0

localhost:3000で接続でき、railsのページが表示されていることが確認できる。
localhost:3000/productsで作られたアプリに接続できる。

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

Docker上にvue.jsの開発環境する。docker-composeで簡単に作成する手順。

Docker上にvue.jsの開発環境する。docker-composeで簡単に作成する手順。

dockerを使ってvue.jsの開発環境を簡単に構築できるようにする。

本番に応用できるよう、DockerfileのENTRYPOINTでコンテナ内のスクリプトを実行する。

また、実行はdocker-composeを使用する。
実行順序は docker-composeファイル -> Dockerファイル -> スクリプトファイル となる。

複数人のプロジェクトを想定して、作成したファイル群をgithubにアップして、cloneしvue.jsの開発環境を立ち上げるまで。


開発手順

  1. Dcokerのインストール
  2. Dockerfileの作成
  3. シェルスクリプトの作成
  4. docker-compose.ymlの作成
  5. .dockerignoreの作成
  6. aliasの作成
  7. aliasファイルの読み込み
  8. docker-composeの実行
  9. コンテナ内に入る
  10. vueの開発環境を作成する
  11. ファイルの移動と削除
  12. vue開発環境の確認
  13. githubに作成したファイル群をプッシュ
  14. 他のプロジェクトメンバーのローカルで実行する


Dcokerのインストール

Dockerの公式ページからOSに合ったDockerをインストール

https://docs.docker.com/get-docker/

設定が完了したら、正しくインストールされているかターミナルで確認。

$docker -v
Docker version 19.03.12

$docker-compose -v
docker-compose version 1.26.2

dockerとdocker-composeのバージョンがそれぞれ表示されたらOK。


Dockerfileの作成

環境開発時のコマンドはdocker-composeで実行するが、独自のイメージを作成(build)する際に、Dockerfileを指定する。

Dockerfileはコンテナ内の処理となる。

プロジェクトフォルダを作成したい階層に移動。
ここでは、PJのルートディレクトリとしてvuecliを作成する。

ターミナル
#vuecliフォルダを作成し移動
$ mkdir vuecli && cd vuecli

#Dockerfileを作成
$ touch Dockerfile

#vimエディタでファイルを開く
$ vi Dockerfile

▼vimエディタの超基本コマンド

  • 貼り付け:p
  • インサートモード: i
  • インサートモード終了: esc
  • 保存して終了: :wq



▼Dockerファイルの内容
Dockerfileは拡張子不要。
Dockerfileには下記を記述。

Dockerfile
#nodeイメージをpullする
FROM node:10.15.3-alpine

#working directory
WORKDIR /app

#vuecliインストール
RUN npm install -g @vue/cli

#shファイルをコンテナにコピー
COPY ./scripts/docker.start.sh /scripts/start.sh

#shフォルダの権限追加(全員実行可)
RUN chmod +x /scripts/*

#初期実行
# ENTRYPOINT [ "/scripts/start.sh" ]

Dockerfileはイメージを作成するための元となるファイル。

FROM イメージ名:タグ

継承のような機能。指定したイメージを取得し、以下に続く処理を実行する。

タグはバージョンを指定。記載しない場合は最新版(latest)が選択される。

イメージの取得は、まずdocker公式の共有イメージ置き場であるdockerhubで該当するものがあるか探す。ない場合はローカルのDocker内のイメージを探す。

(補足) node:10.15.3-alpineとは?
本当はvue-cliのイメージを取得したいが、現状dockerhubにはないため、nodeのイメージを取得する。

バージョンは10.15.3、OSはlinux alpineを選択。

linux alpineは軽量のOS。dockerのイメージで見かけることが多い。注意点としてはbashファイルが存在せず、shファイルのみとなること。(後々の記述に影響)

WORKDIR パス

コンテナ内のワーキングディレクトリの指定。

デフォルトではルートディレクトリ(/)が指定されているが、WORKDIRで変更することができる。

RUN コマンド

コンテナ内で実行するコマンドを記述。
「npm install -g @vue/cli」で、vueを操作するコマンドラインインターフェース(cli)をインストールする。

exec形式(配列でコマンドと引数を順に記述)での記述も可能。例えば上のコマンドだと、
RUN ["npm", "install", "-g", "@vue/cli"]

COPY ホスト内パス コンテナ内パス

ホスト内のファイルをコンテナの指定したパスにコピーする。
親フォルダが存在しない場合は自動で作成される。

コンテナ内のシェルスクリプトでコマンドを実行する仕様とするため、予めホスト内でコマンドを記述したシェルスクリプトを作成しておき、それをコンテナ内にコピーする。(シェルファイルの作成は後ほど)

シェルスクリプトに実行権限を与え、ファイルパス指定で実行できるようにする。
「RUN chmod +x /scripts/*」で権限を付与。

実行権限を与えない場合は、shコマンドでないと実行できない。「$sh シェルスクリプトパス」

ENTRYPOINT [ "コマンド", "引数",,]

ENTYPOINTはコンテナ初回起動時に実行するコマンド。

コンテナ内のスクリプトファイルのパスを指定することで、コンテナ初回起動時に指定したスクリプトを実行できる。


(補足)ENTRYPOINTCMDの違い

ENTRYPOINTCMDはどちらもコンテナ初回実行時に実行するコマンド。

どちらか一つは必ず必要で、記述がないとエラーになる。

ENTRYPOINTとCMDもexec形式(配列のような形)でコマンドを渡せる。その際、引数の扱いが異なる。

  • ENTRYPOINT: 引数の変更はできない。追加の引数として処理する。
  • CMD: 引数に変数を指定できる(状況に合わせて変更可能)
コマンドの記述でよく見る例
  • CMD [ "/bin/sh" ] : shファイルを実行
  • CMD [ "/bin/bash" ] : bashファイルを実行
  • CMD [ "npm", "run", "serve" ] : 「$npm run serve」コマンドを実行(vue.jsのサーバー起動)


シェルスクリプトの作成

ローカルのPJルートディレクトリにscriptsフォルダを作成し、シェルスクリプト「docker.start.sh」を作成する。

ターミナル
#scriptsフォルダとシェルファイルを作成
$mkdir scripts && touch ./scripts/docker.start.sh

#vimエディタで開く
$vi ./scripts/docker.start.sh

▼シェルスクリプトの記述内容

docker.start.sh
#!/bin/sh

#node_modulesインストール
echo "npm install"
npm install 

#vue起動
echo "npm run serve. "
npm run serve

#メモを出力
echo "localhost:18080"

※(補足)シェルスクリプトの利用について
指定のシェルスクリプトを使用せず、DockerfileのみでCMD ["npm","run","serve"]でも実行できるが、

実際の開発で、開発環境と本番環境でインストールするライブラリを変更するなど、条件分岐(if)などを使うことを想定。

docker-compose.ymlの作成

docker-composeは複数のコンテナでプロジェクトを立ち上げる時に使う。

例えば、①ruby on rails, ②PostgreSQL, ③Redis, ④Sideqikのコンテナをまとめて立ち上げることができる。

docker-composeで立ち上げたコンテナは自動で独自のネットワーク(コンテナ同士の関連づけ)が設定される。

docker-composeファイルの拡張子はyml(ヤムル)なので、ヤムルの仕様に沿って記述する。

まずはPJのルートディレクトリにファイルを作成する。

terminal
#ファイル作成
$touch docker-compose.yml

#vimエディタで開く
$vi docker-compose.yml

▼docker-compose.ymlの記述内容

docker-compose.yml
#docker-composeのバージョンを指定
version: "3.7"

volumes:
    #volumeはホストにコピー or 表示させないもの
    ##バイナリファイル(node_module)など、OS依存があるもの

    #node_moduleを入れるvolume
    vue-cli-node-volume: 

services:
    #コンテナ詳細
    app:
        image: vuecli:1
        build:
            context: .
            dockerfile: Dockerfile
        container_name: vuecli3
        ports:
            - "18082:8080"
        volumes:
            #node_moduleを入れるボリューム
            - vue-cli-node-volume:/app/node_modules

            #コンテナ内の指定ディレクトリをホスト側と同期
            - .:/app/

        #-it
        stdin_open: true
        tty: true

version:"メジャーNo.マイナーNo"

docker-composeのファイルフォーマットのバージョンを指定する。versionにより記述方法に違いがあるため注意。今回は3.7を指定。

マイナーNoを記述しない場合、0に置き換わる。
例: version:"3" = version:"3.0"

>ファイルフォーマットとdocker-composeのバージョンの対応表
https://matsuand.github.io/docs.docker.jp.onthefly/compose/compose-file/compose-versioning/

volumes:

トップレベルに「volumes:」を記述すると、指定したvolume名を各コンテナで共有できるようになる。

volumeを使用すると、指定したコンテナのディレクトリやファイルをホストのdockerのストレージに保存する。

▼volumeの使い方

volumeの使い方は大きく3つ。

(1)ホスト側のPJルートディレクトリと同期する

コンテナ内のワーキングディレクトリと、PJのルートディレクトリを同期することで、viewファイルやsrcなどがリアルタイムで同期できる。

- .:/app/ (ホスト側のパス:コンテナ側のパス)
上記例では、コンテナのワーキングディレクトリ/app/を、ホスト側のdocker-composeを実行するディレクトリに同期している。

(2)ホスト側にコピーしたくないファイルやディレクトリの指定。

volume名を指定することで、.dockerignoreファイルと組み合わせ、ホスト側に同期させないようにすることができる。

例えば、バイナリファイルが該当する。
バイナリファイルはバイナリ(0,1)で書かれたPC用のテキストファイルでOS毎に内容が異なる(依存性がある)。

コンテナ内にインストールしたnodeはLinux用なので、ホスト側のOSと一致しない場合に不具合を起こす。なので、nodeの入ったnode_modulesはホスト側のPJディレクトに同期させないようにする。(.dockerignoreファイルと合わせて使う)

(3) 同期除外しなくてもいいが、ホスト側にも特に必要ないファイルやディレクトリ

ログファイルなどログ分析用ファイルに同期している場合はホストのPJディレクトリに同期する必要はない。

volumeの記述方法

volumesの記述はホスト側:コンテナ側
実際の記述方法は大きく3つ。

(1)コンテナ側のパスのみ
./logs
/var/lib/mysql

ホスト側のパスを記述しない場合、コンテナ内の指定したフォルダはホストのvolume内のどこかに保存される。

呼び出す必要もないファイルやディレクトリに使う。

(2) ボリューム名で指定
node_volume: ./node_modules

ホスト側をボリューム名で記述する方法。この場合、docker内に指定したボリューム名のディレクトリが作成され、その中に指定したフォルダやファイルが保存される。

ホスト側のPJディレクトリに保存したくない場合に使用。(.dockerignoreを合わせて使う)

(3) パスで指定
./cache:/tmp/cache

パスで指定することも可能。
上記例では、ホスト側を相対パス、コンテナ側を絶対パスで指定。

sevices:

コンテナと使用するイメージを設定する。
今回はappコンテナのみ作成。

image: イメージ名:タグ

コンテナ作成のために使用するimageを指定する。
タグはバージョン。記述しない場合はlatestとなる。

buildがある場合は、buildに記載の内容からイメージを作成する。buildの指定がない場合は、dockerhub、ローカルの順にイメージを探す。

build

イメージを作成するためのDockerfileを指定する。
記述方法は2つ。

(1)Dockerファイルのパスとファイル名で指定

build:
  context: Dockerファイルのパス
  dockerfile: ファイル名
(補足)Dockerfileのファイル名について

Dockerfileのファイル名は「Dockerfile」に限定する必要はない。指定ディレクトリの拡張子のないファイルを構築用ファイルとみなす。

誰が見てもわかりやすいように「Dokerfile」を記述するのが一般的。

▼ファイル名の例
- Dockerfile
- Dev.Dockerfile
- Dockerfile-2

(2)ファイルのパスで指定
構築用ファイル(拡張子のないファイル)がディレクトリに1つのみのとき、ディレクトリパスのみの指定もできる。

build: Dockerファイルのパス

container_name:

作成したコンテナの名前を指定する。
「docker ps -a」 でコンテナの一覧を出した時に表示される名前。

ports: - ホスト側:コンテナ側'

ポートの指定。複数設定することも可能。

「- "18082:8080"」の場合、コンテナ側の通信ポート8080と、ホスト側の18082ポートをつなげる。

ホスト側のブラウザにlocalhost:18082と打ち込むと、コンテナ内で開発用サーバーを立ち上げた時に表示されるlocalhost:8080に接続する。

stdin_open: true

コンテナ起動時のオプション。標準入力(standard in)を許可する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。

Dockerのコマンドでは「-i」

tty: true

コンテナ起動時のオプション。標準出力用の擬似ターミナルを起動する。
コンテナ内のOSとbash(sh)を通してコマンド入力する場合に必要。

Dockerのコマンドでは「-t」
基本的に「-t」と「-i」はセット(-it)で使う。


.dockerignoreの作成

ホスト側に同期したくないファイルやディレクトリのパスを記述する。(.gitignoreと同じ機能)

terminal
#ファイルの作成
touch .dockerignore

#vimエディタで開く
vi .dockerignore

▼.dockerignoreの内容

.dockerignore
#node_modulesは同期しない
node_modules

コンテナ作成を実行すると、ローカル内にnode_modulesという空のフォルダが自動作成される。コンテナ内の同じフォルダの内容を同期しなくなる。


aliasの作成

ここまでで、ようやくイメージとコンテナを作成するために必要なファイルが揃った。

  • docker-compose.yml
  • Dockerfile
  • docker.start.sh
  • .dockerignore

この時点でdocker-composeを実行することもできるが、本番を見据えてdocker-composeコマンドのaliasを作成することで、より簡単に操作できるようにする。

作成の流れは、aliases.shファイルを作成しコマンドを記述。bash_profileでファイルを読み込み、bash_profileをリロード。

terminal
#ファイルを作成
$ touch aliases.sh

#vimエディタで開く
$ vi aliases.sh

▼aliases.shの内容

aliases.sh
#イメージの作成とコンテナ起動
alias vue-pj="docker-compose up --build app"

#コンテナ内のshファイルを起動
alias vue-exec="docker exec -it vuecli sh"

alias ショートカットコマンド="本来のコマンド
イコールの前後にスペースがあるとエラーになる。

docker-compose up --build app
「docker-compose up [サービス名]」:指定したサービスの内容を実行。イメージがない場合はビルドし、コンテナを起動する。

イメージが既に存在する場合は上書きせず、それを使用する。

docker-compose.ymlの変更内容を反映したいため、「--build」オプションをつけることで、イメージが存在しても再度イメージを構築する。(docker-compose build && docker-compose up appと同じ)

▼サービス名の指定がない場合
サービス名を指定しない場合は、記述してある全てのコンテナを起動する。

今回の環境では、appの指定がなくても同じ挙動となるが、実際は開発環境や本番環境で立ち上げるコンテナを切り替えることがあるためあえて指定。

▼「-d」オプション
-dオプションをつけると、バックグラウンドモードでの起動となり、bash(or sh)が起動しない状態となる。
コンテナ内の実行内容が見えなくなってしまうため、今回は付けない。

docker exec -it コンテナ名 sh
指定したコンテナのシェルを立ち上げる。コンテナ内がbashの場合はshではなくbashを指定。

今回はlinux alpineのためshを指定。

aliasファイルの読み込み

作成したaliasが使えるように、bashで読み込む。

terminal
#bash_profileをvimエディタで開く
$ vi ~/.bash_profile

▼bash_profileの内容

bash_profile
#作成したファイルを読み込み(フルパスで記述)
source /Users/.../vuecli/aliases.sh 
terminal
#bash_profileのリロード
$ source ~/.bash_profile

#aliasの確認
$ alias
alias vue-exec='docker exec -it vuecli sh'
alias vue-pj='docker-compose up --build app'

作成したaliasが表示されていればOK。

bash_profileとは?

bash_profileはシェルをbashで起動したときに読み込まれるファイル。

設定したaliasはシェルを閉じると消えるが、bash_profileに記述することで毎回自動でロードされる。

似たファイルで、より高頻度でロードする、.bashrcというのもある。


docker-composeの実行

いよいよdocker-composeを実行し、イメージとコンテナを作成する。

docker-compose.ymlのあるディレクトリで先ほど設定したコマンドを実行。

terminal
vue-pj

これで、コンテナ内にnode.jsとvue-cliがインストールされる。


コンテナ内に入る

コンテナ内でvue-cliを使ってvue.jsの開発環境を作成するため、先ほど作成したaliasでコンテナないのシェルを起動する。

terminal
vue-exec
/app #

/app #と表示されれば、docker内に作成したワーキングディレクトリでコマンドを打ち込める状態になっている。


vueの開発環境を作成する

コンテナ内シェル
/app #vue create -d pj

vue create プロジェクト名
ここではプロジェクト名をPJとして実行。
オプションの「-d」はデフォルト設定(bavelとeslint)で作成。

「-d」を記述せず、vue-cliの対話モードでオプションを選択してくこともできる。


ファイルの移動と削除

vue createを実行するとフォルダは指定したプロジェクト名のフォルダの中に作成される。

ホスト側のプロジェクトファイルのルートディレクトリとコンテナ内のワークディレクトリを同期させたいため、コンテナ内のプロジェクトフォルダの中身を一階層上に上げる。

.dockerignoreに記述しているnode_modulesは同期するディレクトリに移動できないため、一度削除し再インストールする。

まず、コンテナ内のvue-cliが立ち上がっているので、ctrl + cでいったん終了し、コンテナ内のシェルに戻る。

コンテナ内シェル
#pjフォルダを一階層上に移動(隠しファイル含む)
##gitignoreのnode_moduelsは移動できない
mv -f ./pj/* ./pj/.* .


<br>
##node_modulesファイルを削除し、再インストール
rm -r pj && npm install 

##yarn関連ファイルを削除。
rm *yarn* 


##コンテナ内を確認
/app # ls
Dockerfile          node_modules        scripts
aliases.sh          package-lock.json   src
babel.config.js     package.json
docker-compose.yml  public

ホスト側にコンテナ内のファイルが反映されていればOK

image.png


vue開発環境の確認

これで自分のPCでの開発環境の設定が完了したので、実際にWEBページが開けるか確認する。

npm run serveでサーバーを再起動できるが、dockerの練習も兼ね一旦コンテナから出て確認してみる。

#コンテナから抜ける
/app # exit

#起動中のコンテナを確認
$docker ps -a

CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                            NAMES
ebe0276cb7f0        vuecli:0                    "/scripts/start.sh"      36 minutes ago      Up 4 minutes        0.0.0.0:18080->8080/tcp                          vuecli
#イメージを確認
$docker images
REPOSITORY                                      TAG                 IMAGE ID            CREATED             SIZE
vuecli                                          0                   c6a23f947246        32 hours ago        338MB

#イメージの詳細
$docker image inspect vuecli:0

docker-compose.ymlに記述したコンテナ名とイメージ名のコンテナとイメージがそれぞれ存在していることがわかる。

WEBページを確認するため、再びコンテナ内に入る。

#コンテナ内に入る
$vue-exec

#サーバーを起動
/app # npm run serve


App running at:
  - Local:   http://localhost:8080/

  It seems you are running Vue CLI inside a container.
  Access the dev server via http://localhost:<your container's external mapped port>/

上記が表示されればサーバーの起動完了。

WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18080

image.png

WEBページが表示されれば成功。


githubに作成したファイル群をプッシュ

このままでは自分しか使えないため、複数人で開発を進められるようgithubのリモートレポジトリに作成したファイル群をプッシュする。

githubのレポジトリを指定してアップする。

git init
git commit -m "first commit"
git branch -M master
git remote add origin https://github.com/(レポジトリのフルパス)
git push -u origin master

image.png


他のプロジェクトメンバーのローカルで実行する

前提条件として、dockerとdocker-composeが入っていること。

#リモートレポジトリをclone
##クローンした際のフォルダ名をvuecli(任意)としている。
$git clone https://github.com/(レポジトリのフルパス) vuecli

#フォルダ移動
$cd vuecli

aliasファイルの読み込み

作成したaliasが使えるように、bashで読み込む。

terminal
#bash_profileをvimエディタで開く
$vi ~/.bash_profile

▼bash_profileに以下を記述

bash_profile
#作成したファイルを読み込み(フルパスで記述)
source /Users/.../vuecli/aliases.sh 
terminal
#bash_profileのリロード
$source ~/.bash_profile

#aliasの確認
$ alias
alias vue-exec='docker exec -it vuecli sh'
alias vue-pj='docker-compose up --build app'

#イメージとコンテナ作成
$vue-pj

省略
App running at:
  - Local:   http://localhost:8080/

  It seems you are running Vue CLI inside a container.
  Access the dev server via http://localhost:<your container's external mapped port>/

上記が表示されればサーバーの起動完了。

WEBブラウザでページを表示する。
docker-composer.ymlで設定したホスト側のポートを入力。
localhost:18080

image.png

WEBページが表示されれば成功。

以上。

 

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

DockerでFirebase Local Emulator Suiteを起動する。

はじめに

Firebase Local Emulator Suiteはローカル環境でFirestoreやCloud FunctionsといったFirebaseプロジェクトのコンポーネントをエミュレートできる環境です。
https://firebase.google.com/docs/emulator-suite?hl=ja

本記事ではDocker及びDocker Composeを利用して上記の環境を構築したいと思います。

開発環境

  • macOS Catalina 10.15.6
  • Docker Desktop stable 2.3.0.4

なお、本記事で使用したコードはこちらです。

実際に作ってみる。

はじめにFirebaseのプロジェクトを作成しておきましょう。
https://console.firebase.google.com/
後述するEmulator Suite UI(GUI上でエミュレータを管理できるコンソール)を利用するために必要となります。
使用するプロジェクトのIDは.envファイルに控えておきます。

$ mkdir empty_dir && cd empty_dir
$ touch .env
.env
GCP_PROJECT_ID=YOUR_PROJECT_ID

それでは早速Dockerfileから作成していきます。
エミュレータの動作要件を満たすようイメージを作成します。
https://firebase.google.com/docs/emulator-suite/install_and_configure?hl=ja

$ mkdir docker
$ touch ./docker/firebase.dockerfile
docker/firebase.dockerfile
FROM ubuntu:20.04

RUN apt-get update -y

RUN apt-get install -y curl openjdk-11-jre-headless

RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs

RUN npm install -g firebase-tools

つづいてDocker Composeの構成ファイルを作成します。
ボリュームのマウントも行うため適宜ディレクトリも作成しておきます。

$ mkdir firebase
$ touch docker-compose.yaml
docker-compose.yaml
version: "3"

networks:
    backend:

services:
    workspace:
        image: golang:1.15
        environment:
            FIRESTORE_EMULATOR_HOST: "firebase:8080"
            GCP_PROJECT_ID: "${GCP_PROJECT_ID}"
        volumes:
            - ./gopath/:/go:cached
            - ./workspace/:/opt/workspace:cached
        ports:
            - 8000:8000
        working_dir: /opt/workspace
        networks:
            - backend
        command: bash
        tty: true
    firebase:
        build:
            context: ./docker
            dockerfile: firebase.dockerfile
        volumes:
            - ./firebase/emulators/:/opt/workspace:cached
            - ./firebase/bin/:/root/.cache:cached
            - ./firebase/config/:/root/.config:cached
        ports:
            - 4000:4000 # Emulator Suite UI
            - 5000:5000 # Firebase Hosting
            - 5001:5001 # Clound Functions
            - 9000:9000 # Realtime Database
            - 8080:8080 # Cloud Firestore
            - 8085:8085 # Cloud Pub/Sub
        working_dir: /opt/workspace
        networks:
            - backend
        command: bash
        tty: true

今回はGo言語からFirestoreのAPIを叩いてみたいと思います。

./workspace/go.mod
module github.com/kyhei/firebase_emu_sample

go 1.15

require (
    cloud.google.com/go/firestore v1.3.0
    golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
    golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
    golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f // indirect
    golang.org/x/tools v0.0.0-20200904185747-39188db58858 // indirect
    google.golang.org/api v0.31.0 // indirect
    google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d // indirect
)
./workspace/main.go
package main

import (
    "context"
    "log"
    "os"

    "cloud.google.com/go/firestore"
)

func main() {
    ctx := context.Background()
    client, err := firestore.NewClient(ctx, os.Getenv("GCP_PROJECT_ID"))
    defer client.Close()
    if err != nil {
        log.Fatal(err.Error())
    }

    doc, _, err := client.Collection("users").Add(ctx, map[string]interface{}{
        "name": "kyhei",
        "age":  123,
    })
    if err != nil {
        log.Fatal(err.Error())
    }

    log.Println(doc.ID)

    q := client.Collection("users").Select("name", "age")
    docs, err := q.Documents(ctx).GetAll()
    if err != nil {
        log.Fatal(err.Error())
    }

    for _, doc := range docs {
        log.Println(doc.Data())
    }

}

ここまでの内容でDocker Composeを実行してみましょう。

$ docker-compose up -d
$ docker-compose ps

2つのコンテナが起動していればOKです。

エミュレータの起動と設定

firebaseコンテナにログインし、Firebaseプロジェクトの初期化を行います。

$ docker-compose exec firebase bash
root@da35c7925947:/opt/workspace# firebase login --no-localhost
root@da35c7925947:/opt/workspace# firebase init

firebase initでは、プロジェクトを既存のものを選択し、
利用サービスの選択肢では、Emulatorsを選びます。(他はなんでもOKです。)

Emulators Setupでは全てのエミュレータにチェックを入れましょう!
その後それぞれに関する設定が聞かれますが全てデフォルトで大丈夫です。

初期化が完了したら、firebase.jsonを編集します。

./firebase/emulators/firebase.json
{
  "emulators": {
    "functions": {
      "host": "0.0.0.0",
      "port": 5001
    },
    "firestore": {
      "host": "0.0.0.0",
      "port": 8080
    },
    "database": {
      "host": "0.0.0.0",
      "port": 9000
    },
    "hosting": {
      "host": "0.0.0.0",
      "port": 5000
    },
    "pubsub": {
      "host": "0.0.0.0",
      "port": 8085
    },
    "ui": {
      "enabled": true,
      "host": "0.0.0.0",
      "port": 4000
    }
  }
}

それでは次のコマンドで実際にエミュレータを起動しましょう。

root@da35c7925947:/opt/workspace# firebase emulators:start

初回は実行ファイルがダウンロードされます。
エミュレータが立ち上がったらhttp://localhost:4000でコンソールにアクセスできればOKです!

スクリーンショット 2020-09-09 16.11.06.png

Firestoreエミュレータの確認

前項で作成したスクリプトを実行して、Firestoreへの接続を確認してみましょう。

$ docker-compose exec workspace bash
root@c64fed9c2890:/opt/workspace# go run main.go
2020/09/09 07:17:08 6WQVScx2NGm4oli8f7iw
2020/09/09 07:17:08 map[age:123 name:kyhei]

コンソールを確認すると無事ドキュメントが追加されているのが確認できます。

スクリーンショット 2020-09-09 18.58.37.png

お疲れ様でした!

Cloud FunctionsやHostingを起動するためにはそれぞれの初期化が必要となります。
エミュレータ起動時のログから初期化のコマンド等が指示されますので、そちらを実行していけばOKです。

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

Dockerでflask+Herokuのための環境構築からデプロイまで

はじめに

およそ1年前にDjangoを使って簡単なWebアプリを開発した。

データ収集からAI開発、Webアプリ公開まで全てPythonで済ませた話

入力されたURLからスクレイピングでデータ取得→学習済み機械学習モデルで推論→答えを返す
という非常にシンプルなものである。アプリはこちら↓
キー判別AI

久しぶりに使ってみたところ、スクレイピング先のサイトの仕様変更により、正しい結果を得られなくなってしまった。これはマズイと思い改修することにした。

久しぶりにコードを覗いてみたが、自分でもよくわからない…開発当時はとにかく動かすことを目標にしていたこともあり、コードも汚いし、デプロイ方法もすっかり分からなくなっている…

というわけで、今後も不定期的に改修することを考え、開発やデプロイをしやすくするためにDockerでの環境構築を実施した。クローンしてdocker-composeすれば開発できて、なおかつコンテナからherokuにデプロイできるようにするのを目標とする。

また、このアプリ自体がDBも使わず非常にシンプルなので、明らかにDjangoを使う必要もないので、この機会にflaskに書き換えちゃいます。

Githubにコードを公開しています。
https://github.com/hatena-hanata/KJA_app

ディレクトリ構造

最終的なディレクトリ構造はこちらです。

KJA_APP
├── Dockerfile
├── Procfile
├── app.py
├── docker-compose.yml
├── requirements.txt
└── src
    ├── modules
    │   ├── module.py
    │   └── music_class.py
    ├── static
    │   └── model
    │       ├── le.pkl
    │       └── model.pkl
    └── templates

環境構築

docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - .:/home/KJA_APP
    tty: true
    environment:
      TZ: Asia/Tokyo
    command: flask run --host 0.0.0.0 --port 8080

Dockerfile
FROM python:3.8.0
USER root

# install google chrome
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN apt-get -y update && apt-get install -y google-chrome-stable && apt-get install -yqq unzip

# install chromedriver
RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip
RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/

# install heroku cli
RUN curl https://cli-assets.heroku.com/install.sh | sh

# set display port to avoid crash
ENV DISPLAY=:99

# upgrade pip
RUN apt-get update && apt-get install -y \
    && pip install --upgrade pip

# change dir
WORKDIR /home/KJA_APP

# install module
COPY requirements.txt /home
RUN pip install -r /home/requirements.txt

# flask setting
ENV FLASK_APP '/home/KJA_APP/app.py'
ENV FLASK_DEBUG 1

今回、seleniumでchromeを動かしてスクレイピングするため、最初にchromeとchrome driverをインストールしています。こちらのdockerfileを参考にしました。
また、herokuへのデプロイのために、heroku cliもインストールしています。

最後の2行flask settingでは、flaskに関する設定を行っています。
FLASK_APPでは、flaskのメイン関数のあるpyファイルを指定することで、flask runコマンドでそのファイルが実行されるようになります。
FLASK_DEBUGを1にすることでデバッグモードになり、ファイルの更新がリアルタイムで反映されるようになります。

これにて、git clone→docker-composeですぐに開発ができるようになりました。docker-composeの際にflask runコマンドを実行しているので、http://localhost:8080/ にアクセスすればアプリが走っていることが分かります。
image.png

Herokuにデプロイ

Herokuへの会員登録は済ませているものとします。

準備

  1. requirements.txt
    必要なライブラリをrequirements.txtに書き込みます。デプロイのためにgunicornが必要なので、pipで忘れずにインストールしておきましょう。
  2. Procfile
    プロジェクト直下に作成します。以下のように書きます。
    左のappがプロジェクト直下のapp.pyのことで、右のappはapp.pyで定義したFlaskインスタンスの変数名?です。 ちょっと何言ってるか分かりづらいと思うので、こちらを読んでください。
    https://stackoverflow.com/questions/19352923/gunicorn-causing-errors-in-heroku
Procfile
web: gunicorn app:app --log-file -

アプリ作成

ターミナルからでもできますが、ブラウザからの方が分かりやすいので、ブラウザでやります。

  1. ブラウザからHerokuにログイン
    https://id.heroku.com/login
  2. New -> Create new app でアプリを作成
    適当に名前をつけます。
  3. ビルドパックの追加
    今回のアプリがpythonであることを明示するために、作成したアプリのページで Settings -> Buildpacks から heroku/python を追加します。 (デプロイ時に自動でpythonを追加してくれる場合もあるそうですが、自分のディレクトリ構造が悪かったせいか、pythonプロジェクトと認識されず困ったので、予め手動で追加しておくことをオススメします。)
    また、今回はseleniumとchromeを利用したスクレイピングをするため、chromeとchrome driverが必要になります。これもビルドパックの追加で対応できます。
    https://qiita.com/nsuhara/items/76ae132734b7e2b352dd#chrome%E3%81%A8driver%E3%81%AE%E8%A8%AD%E5%AE%9A

デプロイ

ここからはDockerのコンテナに入ってデプロイします。
1. herokuにログイン
リンクが出てくると思うので、それをクリックして認証する。

root@a59194fe1893:/home/KJA_APP# heroku login
  1. herokuのアプリ用リポジトリにpushする。 urlは https://git.heroku.com/[上の2.で作成したアプリ名].git です。(ブラウザのSettingsでも確認できます)。
    下のコマンドは、今のブランチの内容をherokuのリポジトリのmasterブランチにpushする、という意味です。
root@a59194fe1893:/home/KJA_APP# git push https://git.heroku.com/[上の2.で作成したアプリ名].git master

エラーがでなければこれにてデプロイ完了となります。

最後に

docker-compose便利ですね。

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

【MySQL】dockerで構築したデータベースサーバが日本語対応していないかも、、、

環境

$ docker -v
Docker version 19.03.12

$ rails -v
Rails 6.0.3.2

$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for osx10.15 (x86_64) using  EditLine wrapper

データベースに日本語でユーザー名を登録しようとすると、、、、

エラー内容
ActiveRecord::StatementInvalid (Mysql2::Error: Incorrect string value: '\xE3\x83\x8F\xE3\x83\xAA...' for column 'name' at row 1):

あらら、日本語として認識されてない模様
ここは、データベースのcharasetでも見て設定確認しますか。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
f51c4b953b05        feeder-in_back      "rails server -b 0.0…"   About an hour ago   Up About an hour    0.0.0.0:3000->3000/tcp              back
925b28f3b58d        mysql:5.7           "docker-entrypoint.s…"   About an hour ago   Up About an hour    33060/tcp, 0.0.0.0:3308->3306/tcp   database
ab6efeba59a1        feeder-in_web       "docker-entrypoint.s…"   About an hour ago   Up About an hour    0.0.0.0:8080->3000/tcp              web
$ docker exec -it 925b28f3b58d mysql -u root -p

mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.03 sec)

character_set_database | latin1
これを見る限り、MySQLのデフォルトのcharasetになっており、日本語対応になっていない。

MySQLデータベースサーバを日本語対応にする

docker-compose.yml
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
$ docker-compose down

$ docker-compose up -d --build

データベースの再構築

database.yml
default: &default
  charset: utf8mb4   #追記
  encoding: utf8mb4  
$ docker-compose exec back sh
> rake db:drop

> rake db:create
> rails db:migrate

これで日本語対応のデータベースになった!

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

DockerfileにShell関数を書く方法

概要

dockerfileにshell関数を書きたいシュチュエーションがあったのでメモ

エラーの発生したソースコード

RUN function sample(){
    yum install -y git \
    yum install -y httpd\
}

原因

;がない

対処したソースコード

RUN function sample(){
    yum install -y git; \
    yum install -y httpd;\
}

結論

一つ一つのコマンドを終了させる必要がある。

参考文献

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

DockerでRuby on rails6のアプリケーションを環境構築

目標

  • ruby on rails6 のアプリケーションをdockerで新規にアプリを立ち上げたい
  • DBはMySQLで設定

前提

  • Docker on mac
  • Rails tutorial完了などruby on rails に関する基礎知識

1.作業ディレクトを作成し、移動する

MacBook-Air ~ % mkdir アプリ名
MacBook-Air ~ % cd アプリ名
MacBook-Air アプリ名 %

2.Dockerfileを定義する

FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y nodejs

# yarnパッケージ管理ツールをインストール
# https://classic.yarnpkg.com/en/docs/install/#debian-stable
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn

WORKDIR /アプリ名
COPY Gemfile /アプリ名/Gemfile
COPY Gemfile.lock /アプリ名/Gemfile.lock
RUN bundle install
COPY . /アプリ名

# 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"]

3.Gemfileを作成する

source 'https://rubygems.org'
gem 'rails', '~>6'

4.空のGemfile.lockを生成する

MacBook-Air アプリ名 % touch Gemfile.lock

5.entrypoint.shを作成する

2つ目のところ、自身のアプリ名を入れることに気をつける

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /アプリ名/tmp/pids/server.pid

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

6.docker-compose.ymlを作成する

webのvolumesのところを自分のアプリ名を入れる

docker-compose.yml
version: "3"

services:
  db:
    image: mysql:8.0
    command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: root
    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'"
    environment:
      MYSQL_HOST: db
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    depends_on:
      - db

7.Rails newをする

ここではオプションとして、オプションでリンクしたサービスを起動しない設定、DBをmysqlにする設定を追加

MacBook-Air アプリ名 % docker-compose run web rails new . --force --no-deps --database=mysql
~
Starting アプリ名_db_1 ... done
Building web
~
Successfully built 36d2fef9a8a6
Successfully tagged アプリ名_web:latest

8. DBと接続する

passwordとhostに環境変数を設定する

database.yml
~
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV.fetch("MYSQL_ROOT_PASSWORD", "root") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>
~

9.コンテナを起動する

MacBook-Air アプリ名 % docker-compose up
~
web_1  | => Booting Puma
web_1  | => Rails 6.0.3.2 application starting in development 
web_1  | => Run `rails server --help` for more startup options
web_1  | Puma starting in single mode...
web_1  | * Version 3.12.6 (ruby 2.6.3-p62), codename: Llamas in Pajamas
web_1  | * Min threads: 5, max threads: 5
web_1  | * Environment: development
web_1  | * Listening on tcp://0.0.0.0:3000
web_1  | Use Ctrl-C to stop

この表示がでたらブラウザで http://localhost:3000/ にアクセスする
Yay! You’re on Rails! と表示がでたらコンテナ起動成功

エラー: No such file or directory @ rb_sysopen - /アプリ名/config/webpacker.yml Errno::ENOENT)発生時

MacBook-Air アプリ名 % docker-compose run web rails webpacker:install
~
Webpacker successfully installed ? ?

参考文献

https://docs.docker.com/compose/rails/
https://railsdoc.com/rails

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

DockerでRuby on rails6のアプリケーションを環境構築したメモ

目標

  • Ruby on Rails6 のアプリケーションをDockerで新規にアプリを立ち上げたい
  • DBはMySQL

前提知識

  • Docker on mac
  • Rails tutorial完了などRuby on rails に関する基礎知識

1.作業ディレクトを作成し、移動する

MacBook-Air ~ % mkdir アプリ名
MacBook-Air ~ % cd アプリ名
MacBook-Air アプリ名 %

2.Dockerfileを定義する

Dockerfile
FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y nodejs

# yarnパッケージ管理ツールをインストール
# https://classic.yarnpkg.com/en/docs/install/#debian-stable
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn

WORKDIR /アプリ名
COPY Gemfile /アプリ名/Gemfile
COPY Gemfile.lock /アプリ名/Gemfile.lock
RUN bundle install
COPY . /アプリ名

# 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"]

3.Gemfileを作成する

Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

4.空のGemfile.lockを生成する

MacBook-Air アプリ名 % touch Gemfile.lock

5.entrypoint.shを作成する

2つ目のところ、自身のアプリ名を入れることに気をつける

entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /アプリ名/tmp/pids/server.pid

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

6.docker-compose.ymlを作成する

webのvolumesのところを自分のアプリ名を入れる

docker-compose.yml
version: "3"

services:
  db:
    image: mysql:8.0
    command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: root
    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'"
    environment:
      MYSQL_HOST: db
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    depends_on:
      - db

7.Rails newをする

ここではオプションとして、オプションでリンクしたサービスを起動しない設定、DBをmysqlにする設定を追加

MacBook-Air アプリ名 % docker-compose run web rails new . --force --no-deps --database=mysql
~
Starting アプリ名_db_1 ... done
Building web
~
Successfully built 36d2fef9a8a6
Successfully tagged アプリ名_web:latest

8. DBと接続する

passwordとhostに環境変数を設定する

database.yml
~
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV.fetch("MYSQL_ROOT_PASSWORD", "root") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>
~

9.コンテナを起動する

MacBook-Air アプリ名 % docker-compose up
~
web_1  | => Booting Puma
web_1  | => Rails 6.0.3.2 application starting in development 
web_1  | => Run `rails server --help` for more startup options
web_1  | Puma starting in single mode...
web_1  | * Version 3.12.6 (ruby 2.6.3-p62), codename: Llamas in Pajamas
web_1  | * Min threads: 5, max threads: 5
web_1  | * Environment: development
web_1  | * Listening on tcp://0.0.0.0:3000
web_1  | Use Ctrl-C to stop

この表示がでたらブラウザで http://localhost:3000/ にアクセスする
Yay! You’re on Rails! と表示がでたらコンテナ起動成功

エラー: No such file or directory @ rb_sysopen - /アプリ名/config/webpacker.yml Errno::ENOENT)発生時

MacBook-Air アプリ名 % docker-compose run web rails webpacker:install
~
Webpacker successfully installed ? ?

参考文献

https://docs.docker.com/compose/rails/
https://railsdoc.com/rails

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

DockerでRuby on rails6 × MySQLのアプリケーションを環境構築したメモ

目標

  • Ruby on Rails6 のアプリケーションをDockerで新規にアプリを立ち上げたい
  • DBはMySQL

前提知識

  • Docker on mac
  • Rails tutorial完了などRuby on rails に関する基礎知識

1.作業ディレクトを作成し、移動する

MacBook-Air ~ % mkdir アプリ名
MacBook-Air ~ % cd アプリ名
MacBook-Air アプリ名 %

2.Dockerfileを定義する

Dockerfile
FROM ruby:2.6.3
RUN apt-get update -qq && apt-get install -y nodejs

# yarnパッケージ管理ツールをインストール
# https://classic.yarnpkg.com/en/docs/install/#debian-stable
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn

WORKDIR /アプリ名
COPY Gemfile /アプリ名/Gemfile
COPY Gemfile.lock /アプリ名/Gemfile.lock
RUN bundle install
COPY . /アプリ名

# 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"]

3.Gemfileを作成する

Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

4.空のGemfile.lockを生成する

MacBook-Air アプリ名 % touch Gemfile.lock

5.entrypoint.shを作成する

2つ目のところ、自身のアプリ名を入れることに気をつける

entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /アプリ名/tmp/pids/server.pid

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

6.docker-compose.ymlを作成する

webのvolumesのところを自分のアプリ名を入れる

docker-compose.yml
version: "3"

services:
  db:
    image: mysql:8.0
    command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: root
    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'"
    environment:
      MYSQL_HOST: db
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    depends_on:
      - db

7.Rails newをする

ここではオプションとして、オプションでリンクしたサービスを起動しない設定、DBをmysqlにする設定を追加

MacBook-Air アプリ名 % docker-compose run web rails new . --force --no-deps --database=mysql
~
Starting アプリ名_db_1 ... done
Building web
~
Successfully built 36d2fef9a8a6
Successfully tagged アプリ名_web:latest

8. DBと接続する

passwordとhostに環境変数を設定する

database.yml
~
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: <%= ENV.fetch("MYSQL_ROOT_PASSWORD", "root") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>
~

9.コンテナを起動する

MacBook-Air アプリ名 % docker-compose up
~
web_1  | => Booting Puma
web_1  | => Rails 6.0.3.2 application starting in development 
web_1  | => Run `rails server --help` for more startup options
web_1  | Puma starting in single mode...
web_1  | * Version 3.12.6 (ruby 2.6.3-p62), codename: Llamas in Pajamas
web_1  | * Min threads: 5, max threads: 5
web_1  | * Environment: development
web_1  | * Listening on tcp://0.0.0.0:3000
web_1  | Use Ctrl-C to stop

この表示がでたらブラウザで http://localhost:3000/ にアクセスする
Yay! You’re on Rails! と表示がでたらコンテナ起動成功

エラー: No such file or directory @ rb_sysopen - /アプリ名/config/webpacker.yml Errno::ENOENT)発生時

MacBook-Air アプリ名 % docker-compose run web rails webpacker:install
~
Webpacker successfully installed ? ?

参考文献

https://docs.docker.com/compose/rails/
https://railsdoc.com/rails

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

dockerでWebアプリ構築した(1)

自分はdockerを基盤にWebアプリの開発を行っています。
その開発基盤の構築をちょろっとやったので記事に纏めました。
初歩的なものですが、自分の備忘録?的な感じとして記事を書いていきます。

Docker images nginx

まず、nginxのdocker imagesを取ってくる。

$ docker pull docker.io/nginx
Using default tag: latest
latest: Pulling from library/nginx
bf5952930446: Already exists 
cb9a6de05e5a: Pull complete 
9513ea0afb93: Pull complete 
b49ea07d2e93: Pull complete 
a5e4a503d449: Pull complete 
Digest: sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

で取得!
docker imagesで確認します。

$ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
nginx                                  alpine              ecd67fe340f9        2 months ago        21.6MB

docker runしていくぜ!

注意: 以下の操作で一部間違ってやっているものがあります。(docker runしているコマンドにミスがあります。)
images⇨container
をしていきます。

container作成には、docker runが必須です。
では、行っていきます。

$ docker run -d -p 8000:80 --name cesium_nginx -v /マウントするフォルダ:/home ecd67fe340f9 
a115c1e7a815a4856b2b51755e217f2cc1aa856c81489d9ae3020f4fefd0883f

今回は、ポートを立てるだけでなくマウントもしていきます。
使用オプション
-p外部からアクセスされるポート番号:コンテナ側のポート番号を指定。
-dバックグラウンドで実行。
-v マウントするフォルダ:マウント先フォルダのマウントを実行。-v local:cotainer
--nameコンテナ名を決める。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a115c1e7a815        ecd67fe340f9        "/docker-entrypoint.…"   5 seconds ago       Up 4 seconds        0.0.0.0:8000->80/tcp   cesium_nginx

localhost:8000をみにいく

http://localhost:8000/
を開くと...

スクリーンショット 2020-09-09 18.17.36.png

こんなものが...なんだこれ...

これは、nginxが正常に動いた証!!!
つまり、成功?
かと、思ったが、、自分のマウントしたフォルダには既にhtmlファイルがあります。
だから、それが表示されないと成功ではない。

修正

何が間違っていたか...端的に言えば、マウント先が間違っている。
自分は/homeにマウントしました。
理由は、適当...どこでも良いやって思ってました。

そんなあまくなかった...

docker rm や docker stopしました。(そこらへんの処理は省きます)

$ docker run --name cesium_nginx -v /マウントするフォルダ:/usr/share/nginx/html:ro -d -p 8081:80 ecd67fe340f9 
f85c35793c4bb7368af7798db788f707bcbd4278bbcfdf87a360f727e6433c00

/usr/share/nginx/html:roこれが必要でした。

さて、これでlocalhost:8081を開きましょう!

スクリーンショット 2020-09-09 18.25.10.png

きたーーーー

やっと目的の画面が...(この画面はCesium.jsというWebアプリケーションの画面です。ちょっとアレンジ加えていますが...)

まとめ

しっかり仕様書?やしっかり調べてからやっていこう

こっからスタートや!色々いじっていきます。楽しい楽しい開発の始まり~(見ての通り既に開発していましたが...)

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

Dockerコマンド備忘録

現在立ち上がっているdockerをまとめて落とす

docker ps -a | awk -F '  +' 'NR > 1 {print $7}' | xargs _docker_ rm -f

dockerコンテナ内からmacのlocalhostにアクセスしたいとき

host.docker.interna

特定のメソッドのみテスト

gradle test --tests "*HogeTest.testNewInstance" -i

特定のクラスのみテスト

gradle test --tests "*HogeTest" -i

コンテナを一括で消す

docker container list -qf name=zubatoku.*_<name> | xargs docker container rm -f

現在起動中のコンテナに関わるものはそのまま残したい場合

docker system prune -af --volumes

コンテナを全て消す

docker rm -f $(docker ps -aq)

コンテナイメージを全て消す

docker rmi -f $(docker images -q)

docker volumeを全て消す

docker volume rm -f $(docker volume ls -q)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2にdockerコンテナを立ち上げる(個人的備忘録)

EC2にubuntuのインスタンスを作成し、キーペアを作る

インスタンス作成は割愛

-# キーペアの権限を変える
% chmod 400 キーペア.pem
-# ubuntuのインスタンスにssh接続する
% ssh -i キーペア.pem ubuntu@EC2のパブリックDNS
yes

キーペアの権限を変える目的は、間違って書き換えた場合、ssh接続できないので「400」と読み取り専用のキーペアとする。EC2のパブリックDNSはインスタンスを停止起動で変わるので注意!

EC2にdockerをインストール

-# アクセス権限がないので、sudoを使いupdateする。
$ sudo apt-get update
-# dockerのインストール
$ sudo apt-get install docker.io
-# Yを押す
-# dockerのバージョンの確認
$ docker -—version

このままだとubuntuはdockerに権限がないため、コマンドの頭に「sudo」を毎回つけなければならない。なので「docker」というグループを作り、「ubuntu」を入れる。すると「docker」グループに「ubuntu」は属しているため、dockerが使えるようになり、「sudo」なしにコマンドが使えるようになる。

-# 「docker」というグループに「ubuntu」をいれる 
$ sudo glassed -a ubuntu docker
Adding user ubuntu to group docker
-# 一度抜けないと反映されない
$ exit
-# ssh接続する
% ssh -i キーペア.pem ubuntu@EC2のパブリックDNS
-# dockerコマンドの確認
$ docker images

dockerコマンドが使えることが確認できる。

Docker imageをtarに圧縮してEC2に送る

-# EC2に送るDocker imageの作成
% mkdir temp_folder
% cd temp_folder
% vim Dockerfile
Dockerfile
FROM alpine
RUN touch test
% docker build .

軽量のalpineを作成し、そこに「test」というファイルを作成する。

tarファイルに変換

-# docker save イメージ名 > 新しい名前.tar
% docker save b3fc1a6f13e6 > myimage.tar
-# tarファイルの確認
% ls

SFTPを使ってEC2にアクセスする。

ファイルを転送する時に使うコマンド。

-# sftpに入る(ホストとインスタンスが接続している状態)
% sftp -I キーペア.pem ubuntu@EC2のパブリックDNS
-# put 送るファイルのパス 送り先のファイルパス
sftp> put temp_folder /home/ubuntu 
-# 別のターミナルを開き、キーペアがあるディレクトリに移動し、ssh接続する。
% ssh -i mydocker.pem ubuntu@ec2-18-183-94-137.ap-northeast-1.compute.amazonaws.com
-# ファイルがあるか確認
$ ls

ファイルがホストからEC2に転送されていることが確認できる。

EC2からホストへファイルを転送する

-# EC2にファイルの作成
$ touch test
-# 別のターミナルを開き、ホスト側へ移動、sftpに入る
% sftp -I キーペア.pem ubuntu@EC2のパブリックDNS
-# testファイルがあることを確認する
sftp> ls
-# testファイルを取得する
sftp> get test
-# sftpを抜ける
sftp> exit

デスクトップに「test」ファイルがあることを確認する

tatファイルをdockerimageに戻す

# ssh接続する
% ssh -i キーペア.pem ubuntu@EC2のパブリックDNS
# docker load < tarファリルでimageに戻す
$ docker load < my image.tar
# imageの確認
$ docker images
# docker run(alpineはbashがないのでsh)
$ docker run -it イメージID sh
# lsコマンドでtestファイルがあることを確認
ls

DockerfileをEC2に直接送り立ち上げる。

-# sftpに入る
% sftp -I キーペア.pem ubuntu@EC2のパブリックDNS
-# putでDockerfileを送る、送り先を指定しない場合はubuntuのホームディレクトリにputされる
% put Dockerfileの絶対パス
-# ssh接続する
% ssh -i mydocker.pem ubuntu@ec2-18-183-94-137.ap-northeast-1.compute.amazonaws.com
-# Dockerfileの確認
$ ls
-# ビルドコンテキストの作成
$ mkdir dsenv_build
-# Dockerfileの移動
$ mv Dockerfile dsenv_build/
$ cd dsenv_build
-# コンテナを立ち上げる
$ docker build .

しかし、ストレージ(8GB)が足りずビルドすることができない。

コンピュータのディスク要領の確認

# -hでM,Gバイト表示になる
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            476M     0  476M   0% /dev
tmpfs            98M  768K   98M   1% /run
/dev/xvda1      7.7G  5.1G  2.7G  66% /
tmpfs           490M     0  490M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           490M     0  490M   0% /sys/fs/cgroup
/dev/loop0       97M   97M     0 100% /snap/core/9804
/dev/loop1       29M   29M     0 100% /snap/amazon-ssm-agent/2012
tmpfs            98M     0   98M   0% /run/user/1000

8GBで「/」はすでに5.1G使っており、残りは2.7GBしかなくbuildする際に、ストレージが足りずにBuildできない。ちなみにLinuxの場合、Dockerオブジェクトの保存場所は「/var/lib/docker/」にある。

EC2のストレージを変更する。

1.EC2のインスタンスのページで「Elastic Block Store」のボリュームをクリックする。
2.任意のインスタンスにチェックし、「アクション」でボリュームの変更を行う。
3.サイズで20GBと設定する。
4.画面を更新し、サイズが20GBになっていることを確認する。
5.インスタンスに反映されていない可能性があるので、インスタンスを再起動しておく。

再度buildする。

-# ssh接続
% ssh -i mydocker.pem ubuntu@ec2-18-183-94-137.ap-northeast-1.compute.amazonaws.com
-# Dockerfileの場所まで移動する
$ cd dsenv_build
-# 再度build
$ docker build .
-# ストレージが20GBになったので、異常なくbuildできる。
$ docker run -v~:/work -p 8888:8888 イメージID

EC2のパブリックDNS:8888で接続できることが確認できる。

コンテナのアクセス権限

-# $ sudo adduser —uid 任意のID ユーザー名(ユーザーはsudo権限がないと作成できないので注意)
-# いろいろ聞かれるが今回は全てエンターで省略
$ sudo adduser --uid 1111 aaa
-# /home/aaaというディレクトリが作成されているので移動
$ cd /home/aaa
-# もう1人のユーザー作成
$ sudo adduser --uid 2222 bbb
-# ホームディレクトリに戻る
$ cd /home
-# ファイルの権限を確認する。
$ ls -la
-# aaaとbbbのファイルの権限が確認でき、aaaはbbbのディレクトリに書き込みができないことが確認できる。
-# aaaのユーザーで入る
docker run -u 1111 -v /home/aaa:/home/aaa -v /home/bbb:/home/bbb -it ubuntu bash
-# idの確認
1111
aaaのユーザーで入っていることが確認できる。
-# bbbディレクトリに移動
$ cd /home/bbb
-# ファイルを作成
$ touch test

しかし書き込み権限がないため、作成できないことが確認できる。

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

Docker上のRailsをherokuへデプロイする

herokuへデプロイする練習

Dcokerコンテナ上に、Railsアプリを組んでCircleciを使って自動デプロイまでを一気にやろうとしたら
迷宮入りしたので、原点回帰しようと思います。(第2段)

自分の環境

Ruby : 2.6.6
rails : 6.0.3.2
git : 2.23.0
heroku-cli : 7.42.13 darwin-x64 node-v12.16.2
Docker : 19.03.12

開発環境は、MySQLで
本番環境は、PostgreSQLというパターンで組んでみようと思います。

手元のDocker上にRailsアプリを用意する

まずは、アプリを作るディレクトリを作成し、そこにtouchコマンドで必要な諸々を用意します。

terminal
$ touch {Dockerfile,docker-compose.yml,Gemfile,Gemfile.lock,entrypoint.sh}
Dockerfile
FROM ruby:2.6

RUN 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 -qq \
    && apt-get install -y nodejs yarn \
    && mkdir /heroku_app
WORKDIR /heroku_app

COPY Gemfile //Gemfile
COPY Gemfile.lock /heroku_app/Gemfile.lock
RUN bundle install
COPY . /heroku_app

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3006

CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-data:/var/lib/mysql:cached
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3006 -b '0.0.0.0'"
    volumes:
      - .:/heroku_app
    ports:
      - "3006:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
    command: bundle exec rails server -b 0.0.0.0
volumes:
  mysql-data:
    driver: local
Gemfile
source 'https://rubygems.org'
rails ‘6.0.3’
entrypoint.sh
#!/bin/bash
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /heroku_app/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

上記5点を用意できれば、下記コマンドを実行しRailsアプリを作成します。

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

併せて、テキトーな中身を作っておきます。

$ docker-compose run web rails g scaffold blog title:string body:text
$ docker-compose run web rails db:migrate
$ docker-compose up -d

スクリーンショット 2020-09-09 0.00.04.png

herokuへデプロイする準備

続いて、Railsアプリをherokuにデプロイする前に、本番環境用にpostgreSQLを用意します。
- config/database.ymlの設定
- Gemfile にpgを追加
- config/enviroments/deviropment.rbの設定

config/database.ymlの設定

config/database.yml
production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  pool: 5

Gemfileの設定

本番環境用にgemファイルを用意します。
productionのグループにpgを追加します。
また、MySQLは開発環境用として扱う様にするために、group :development, :test doの中へ移動させます。

Gemfile
group :production do
  gem 'pg', '~> 0.19.0'
end

config/enviroments/deviropment.rbの設定

Rails6特有ですが、DNS離バインディング攻撃からの保護が入っているらしく、
hostを入れてあげる必要があります。

config/enviroments/deviropment.rb
config.hosts << "radiant-springs-45017.herokuapp.com"

下記記事を参考にさせていただきました。
https://qiita.com/kodai_0122/items/67c6d390f18698950440

編集を終えたら、ビルドします。

terminal
docker-compose build
$docker-compose run web rails db:create
$docker-compose up -d

あとは、コマンド打って、ルンルンとherokuへデプロイします。

$ docker-compose down #一度落としておかないとエラーになる可能性があるとのこと
$ heroku login
$ heroku create アプリ名もしくは空欄
$ heroku container:login
$ heroku container:push web
$ heroku adding:create heroku-postgresql:hobby-dev
$ heroku container:release web
$ heroku open

スクリーンショット 2020-09-09 10.44.50.png

終わり!

割愛しましたが、herokuへデプロイした際にエラーが発生しました。
その際は、ターミナル上で$ heroku logs --tail等を打ち、エラーを調べて解決させました。
成功された記事を参考した場合でも、環境の違い等でエラーが発生しうるので、理解のために都度調べる癖をつけるのは大事だと思った次第です。

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

Dockerを学んだことまとめ

背景

あの信頼できる勝又さんの、この記事が強烈すぎた。

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

初心者がdocker for macをインストールして起動してみる

インストールまで

対象者

dockerって何?

動機

php5.Xを使う機会がありました。
php5.xはサポート期間が終了しています。
dockerを使うのが分かりやすかったです。

参考記事

DockerをMacにインストールする(更新: 2019/7/13)

アカウント登録

公式サイト

dockerバージョン確認

docker version

Double-click Docker.dmg to start the install process.
When the installation completes and Docker starts, the whale in the top status bar shows that Docker is running, and accessible from a terminal.

gitバージョン確認

git version

dockerとは?

dockerはコンテナ管理ソフトウェア。
installをしたので使ってみましょう。

dockerのコマンドを使ってみる

nginxをpullする

cmd
docker run -d -p 80:80 --name {コンテナ名} nginx

起動しているnginxを止める

cmd
docker container stop {コンテナ名}

起動しているnginxを起動

cmd
docker container start {コンテナ名}

起動しているコンテナのリストを表示

cmd
docker container ls
cmd
docker container ls -a

コンテナの削除

cmd
docker container rm {コンテナ名}

イメージの削除

cmd
docker image rm {ID}

所要時間

30分ぐらいでできると思います。

ここまでの疑問

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