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

React のチュートリアルを Typescript でやってみた【環境構築編】

背景

React 触ってみたい。
Typescript もやってみたい。

作業環境

今回は docker を使用し環境を作る。

開発環境の準備

プロジェクトのディレクトリーを作成

作業するディレクトリを作成します。
ここではreact-tutorialとしておきます。

mkdir react-tutorial
cd react-tutorial

ディレクトリの中に以下のファイルを作成します。

  • Dockerfile
  • docker-compose.yml

以下それぞれのファイルの内容

Dockerfile

Dockerfile
FROM node:13.8.0-alpine3.11

ENV NODE_ENV=development

WORKDIR /app

docker-compose.yml

docker-compose.yml
version: "3"
services:
  webserver:
    container_name: react-tutorial
    image: react
    build: .
    volumes:
      - ./:/app
    tty: true
    ports:
     - 8080:8080

tree はこんな感じ

react-tutorial $tree
.
├── Dockerfile
└── docker-compose.yml

開発環境の作成

とりあえずビルドします。

docker-compose up --build -d

以下のコマンドでコンテナが起動していれば OK

react-tutorial $docker-compose ps

起動している場合以下のように表示される。

react-tutorial $docker-compose ps
     Name                 Command            State           Ports
---------------------------------------------------------------------------
react-tutorial   docker-entrypoint.sh node   Up      0.0.0.0:8080->8080/tcp

コンテナ内に移動する場合は以下

docker exec -it react-tutorial /bin/sh

package.json の作成

まずはコンテナ内に移動

docker exec -it react-tutorial /bin/sh

以下のコマンドで package.json を作成します。

npm init

設定は以下のように設定しました。

package name: (app) react-tutorial
version: (1.0.0)
description:
entry point: (index.js) webpack.config.js
test command:
git repository:
keywords:
author:humi3
license: (ISC)
About to write to /app/package.json:

ワークディレクトリに以下の package.json が以下の内容でされたと思います。

package.json
{
  "name": "react-tutorial",
  "version": "1.0.0",
  "description": "## コンテナビルド `docker-compose up --build`",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "humi",
  "license": "ISC"
}

※今回は 1 から環境を構築しますが、以下のコマンドで React + Typescript の環境できます。
my-appの箇所にプロジェクト名

npx create-react-app my-app --typescript

必要なライブラリのインストール

Webpack

npm install --save-dev webpack webpack-cli

Typescript で必要なライブラリ

npm install --save-dev typescript awesome-typescript-loader source-map-loader

react & react-dom

npm install --save-dev react react-dom @types/react @types/react-dom

ディレクトリとファイルの準備

以下のディレクトリの構成になるようにファイルを作成します。

react-tutorial
├── dist
│   ├── index.html
│   └── bundle.js
├── node_modules
├── src
│   └──index.tsx
├── Dockerfile
├── docker-compose.yml
├── package-lock.json
└── package.json

bundle.js 及び index.tsx はファイル作成だけでいいです。
index.html だけ以下のような内容にしておきます。

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>TypeScript HelloWorld</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

tsconfig.json の作成

以下のコマンドでtsconfig.jsonを作成します。

npx tsc --init

設定は以下のようにしました。

tsconfig.json
{
  "compilerOptions": {
    "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
    "outDir": "./dist/" /* Redirect output structure to the directory. */,
    "strict": true /* Enable all strict type-checking options. */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
    "sourceMap": true /* Emit a single file with source maps instead of having a separate file. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
    "jsx": "react",
    "lib": ["es2015", "dom"]
  }
}

現在のディレクトリ

react-tutorial
├── dist
│   ├── index.html
│   └── bundle.js
├── node_modules
├── src
│   └──index.tsx
├── Dockerfile
├── docker-compose.yml
├── package-lock.json
├── package.json
└── tsconfig.json

webpack.config.js の作成

webpack.config.jsを作成します。

react-tutorial
├── dist
│   ├── index.html
│   └── bundle.js
├── node_modules
├── src
│   └──index.tsx
├── Dockerfile
├── docker-compose.yml
├── package-lock.json
├── package.json
├── tsconfig.json
└── webpack.config.json

webpack.config.jsの内容

webpack.config.js
const path = require("path");

module.exports = {
  entry: path.resolve(__dirname, "./src/index.tsx"),
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js"
  },
  devtool: "source-map",
  target: "node",
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".json"]
  },
  module: {
    rules: [
      { test: /\.tsx?$/, loader: "awesome-typescript-loader" },
      {
        enforce: "pre",
        test: /\.tsx?$/,
        loader: "source-map-loader"
      }
    ]
  }
};

以上でファイルの準備が完成しました。

動作確認

index.tsx の内容を以下へ

index.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";

export default class App extends React.Component<{}, {}> {
  render(): JSX.Element {
    return <div>HelloWorld!</div>;
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

package.json に build 用の script を追加

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack"
  },

以下のコマンドで build を行います。

npm run build

buildがうまく行ったことを確認します。
スクリーンショット 2020-02-16 21.30.12.png

index.html をブラウザで開きHelloWorld!が表示されたら OK です。

index.png

今回は、環境構築の部分をやってみました。
次回は、公式のチュートリアルを Typescript にしてやっていきたいと思います。

参考

https://speakerdeck.com/takepo/reactxreduxniokerutypescriptru-men
https://qiita.com/soarflat/items/28bf799f7e0335b68186
https://qiita.com/one-kelvin/items/b810aafb6b5ef90789a3

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

【Kubernetes】OperatorSDKにサクッと入門

概要

対象読者

  • 基本的なkubernetesの知識がある人
  • operatorとは何か、なんとなく把握しているが、開発を行なったことがない人
  • go言語の基本的な文法が読める人

はじめに

kubernetesの拡張機能の1つに、operatorが存在します。
operatorを利用すれば、運用の自動化を行うことができます。
operatorに関する詳しい説明は、下記リンクをご覧ください。
https://qiita.com/MahoTakara/items/af4ad8ab69c24102bd72

複数人で同一のclusterやnamespace上で開発を行なっている場合に、
誰がいつdeploymentのimageを変更したか分からず困る状況を想定し、
本記事では、deploymentのimageが変更されるたびに、slackに通知する仕組みを作成していきます。

なお、本記事で作成するものは、本来のoperator-sdkの使い方とは言えないため、
あくまでoperator-sdkに触れる目的であることをご留意ください。

環境構築

以下の環境が必要です。

  • go
  • operator-sdk
  • docker
  • kubectl

dockerやkubectlのインストールについては説明を省きます。
下記手順により、goおよびoperator-sdkをインストールします。

brew install go
go version # 筆者はv1.13.3を使用
export Go111MODULE=on # Go Modulesを使用するため
brew install operator-sdk
operator-sdk version # 筆者はv0.15.2を使用

また、kubernetesクラスタやdockerhub、slackapi(botによるメッセージ送信)が利用できる状態としてください。

開発

テンプレート生成

下記手順によりテンプレートを生成します。

operator-sdk new deployment-image-watcher --repo=github.com/<username>/deployment-image-watcher
cd deployment-image-watcher
operator-sdk add controller --api-version=deployment.k8s.io/v1alpha1 --kind=Deployment

通常、operator-sdkを使用する場合、CRD(Custom Resource Definition)を利用するのが一般的ですが、
今回はdeploymentのimageの変更を検知したいだけなので、CRDは生成しません。

controller

さっそく、根幹となるcontrollerを編集していきます。
controllerはpkg/controller/deployment/deployment_controller.goに存在します。
重要な部分は以下の通りです。
またファイル全体は https://github.com/solt9029/deployment-image-watcher/blob/master/pkg/controller/deployment/deployment_controller.go から確認できます。

func add(mgr manager.Manager, r reconcile.Reconciler) error {
    c, err := controller.New("deployment-controller", mgr, controller.Options{Reconciler: r})
    if err != nil {
        return err
    }

    slackClient := slack.New(os.Getenv("SLACK_TOKEN"))

    source := &source.Kind{Type: &appsv1.Deployment{}}
    handler := &handler.EnqueueRequestForObject{}
    predicate := predicate.Funcs{
        UpdateFunc: func(e event.UpdateEvent) bool {
            for _, oldContainer := range e.MetaOld.(*appsv1.Deployment).Spec.Template.Spec.Containers {
                for _, newContainer := range e.MetaNew.(*appsv1.Deployment).Spec.Template.Spec.Containers {
                    if oldContainer.Name == newContainer.Name && oldContainer.Image != newContainer.Image {
                        messageText := createMessage(newContainer.Name, newContainer.Image, oldContainer.Image)
                        slackClient.PostMessage(os.Getenv("SLACK_CHANNEL"), slack.MsgOptionText(messageText, true))
                    }
                }
            }
            return true
        },
    }

    err = c.Watch(source, handler, predicate)
    if err != nil {
        return err
    }

    return nil
}

watch関数のsourceの引数によって、監視対象としてdeploymentを設定します。
predicateは本来、deploymentの変更や追加、削除などのイベントに対して、
reconcileを行うべきかフィルタリングする役割を担っています。
このpredicate内では変更前の状態と変更後の状態を両方取得することができるため、
今回はこの部分でimageが変更されたかどうかを判定し、slack通知を行うロジックを書いています。

e.MetaOld.(*appsv1.Deployment).Spec.Template.Spec.Containers によって変更前のdeployment.spec.template.containersを取得できます。
同様に、変更後のdeployment.spec.template.containersも取得できます。
それらを用いて、imageを比較し、変更があればslack通知を行なっています。

ビルド

これだけで開発は終了です。
下記手順でビルドし、イメージをdocker registryにpushします。

operator-sdk build <username>/deployment-image-watcher:latest
docker push <username>/deployment-image-watcher:latest

マニフェスト

deploy/secret.yaml を追加し、以下のようなsecretのマニフェストを記述します。
SLACK_TOKEN にはslackapiのtokenをbase64化した値を入れてください。

echo -n "<your slack token>" | base64
apiVersion: v1
kind: Secret
metadata:
  name: deployment-image-watcher
type: Opaque
data:
  SLACK_TOKEN: <YOUR_SLACK_TOKEN_BASE64_ENCODED>

次に、deploy/operator.yaml を編集します。
以下の2つの環境変数を追加してください。

            - name: SLACK_TOKEN
              valueFrom:
                secretKeyRef:
                  name: deployment-image-watcher
                  key: SLACK_TOKEN
            - name: SLACK_CHANNEL
              value: "general"

動作確認

下記手順により、deployment-image-watcherをデプロイします。

kubectl apply -f deploy/

なんらかのdeploymentをapplyし、imageを変更してみてください。
slackに通知が届くはずです。

おわりに

本記事では、operator-sdkを利用して、deploymentのimageが変更されるたびに、slackに通知する仕組みを作成しました。
operator-sdkを手軽に使うために、CRDを用いずに簡易的なサンプルを実装しました。
本来のoperator-sdkの利用目的とは若干ずれていましたが、本記事によって基本的な使い方がわかれば幸いです。
ありがとうございました。

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

雑に知ってしまったDockerを知り直す ~アプリケーション持ち込み編~

おさらい

第2回です。
前回の投稿はこちら
前回はnginxのイメージをpullして来てコンテナ起動。
ポートフォワードしてウェルカムページを表示させるまでやりました。

今回やりたいこと

  1. ローカルで適当にアプリケーションを用意する
  2. どうにかしてそのアプリケーションをコンテナの中にぶちこむ
  3. ホスト側から起動したアプリケーションへアクセスできるようにする

アプリケーションを用意

Nodeとgithubを勉強したときに作った、first-stepっていうオシャレ気取った名前のリポジトリが放置されていたので、これを再利用します。
せっかくなので触ったこと無いReactへ転生。

この辺のステップは本題と外れてしまうので割愛。
$ npm start
image.png

これをどうにかしてコンテナへ持っていきたい。

コンテナを用意

前回はnginxのイメージを利用しましたが、今回はnodeのイメージを利用します。
現在のnodeの最新バージョンはv13.8.0なんですが、ホストにインストールしてるのは安定版のv12.16.0なのでこれをインストールしたい。

バージョン指定してイメージをpullするのどうやるんだろう・・と思いつつとりあえずイメージを探します。
コマンドでも探せるみたいなんですが、初めてなのでGUIに頼ります。

https://hub.docker.com/
image.png

nodeのページを見つけた
image.png

下の方にズラーっとなんか並んでる
image.png

試しに検索窓にバージョン情報入れてみた
image.png

なるほどなるほど、なんかそれっぽいですね。

調べてみるとこれはTagと呼ばれるもので、古いのバージョンのイメージが欲しい場合はこのTagを指定してpullする必要があると。ただ、同じバージョン(v12.16.0)でもstretchとかslimとか更に違いがあるのが気になる。。
で更に調べると、例えばnodeの場合だとバージョンは同じでも無駄なファイルを省いて最適化されたslimバージョンがあったり、Debianのバージョンが異なるもの(stretchとかbusterとかはDebianのコードネーム)があったりと結構細かい違いがあるということが判明。
このあたりもちゃんと意識して適切なイメージを選択する必要があるってことか・・
で、更に気になったのがTag指定しない場合はどうなるんだ?とかlatest指定すると結局どれを引っ張ってくるのよとか、そもそもこれ誰が作ったイメージなん?安全なん?とか・・
TODO: これも色々調べてみたんですけど、今回の趣旨からは外れそうなのとボリューム膨らみそうなので別記事でまたやります。

今回はとりあえず名前がかっこいいのでbusterでやります。

$ docker pull node:12.16.0-buster
12.16.0-buster: Pulling from library/node
dc65f448a2e2: Pull complete
346ffb2b67d7: Pull complete
dea4ecac934f: Pull complete
8ac92ddf84b3: Pull complete
a3ca60abc08a: Pull complete
ab849ba5abe0: Pull complete
b9e0c215e971: Pull complete
766774022603: Pull complete
f199c0426b2a: Pull complete
Digest: sha256:66d5994de29952fe982729ef7c7f8d4c50d528279db386efbf373451f534fa16
Status: Downloaded newer image for node:12.16.0-buster

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node                12.16.0-buster      ce43ce61c1de        28 hours ago        882MB

$ docker run [イメージ名:TAG]
$ docker run -d --name node-react node:12.16.0-buster
505ba1fdefd2f705f90b083cee3653445256a0917e054147f8251d4e0eeef122

#前回はrunする前にイメージをpullしてなかったのでこのタイミングで色々ダウンロードしてましたが、
今回は事前にpull済なのでローカルのイメージを利用。カシコイ

$ docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                     PORTS               NAMES
8a126cad2450        node:12.16.0-buster   "docker-entrypoint.s…"   5 seconds ago       Exited (0) 4 seconds ago                       node-react

で、ここで作成したコンテナのSTATUSを見るとUp(起動中)ではなく、Exitedになっちゃってる。
前回のnginxの場合サーバを立ち上げてUp状態になっていたけど、今回のイメージはあくまでnodeの実行環境を用意するだけなのでコンテナが立ち上がりっぱなしにはならないのかな、となんとなく推測。
環境を構築して後続の命令が無いと、プロセスが死ぬようになっているらしい。起動するアプリケーションも無いのに立ち上げておく意味ないもんね。
-itdってオプションつけるとコンテナが立ち上がりっぱなしになるらしいのでお試し。

$ docker run -itd
-i ホストの入力をコンテナの標準出力につなげる。コンテナ側へ正しくコマンドを渡せるようにする。
-t コンテナの標準出力をホストの標準出力につなげる。ttyをコンテナに割り当てて、対話できるようにする。
-d コンテナに入らずバックグランドで起動する

$ docker run -itd --name node-react node:12.16.0-buster
10235f0996b7c1b1e5f47c5b1c36651ff4fe20cd72b14f47dc5a11f0e8607780

$ docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
10235f0996b7        node:12.16.0-buster   "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds                            node-react

うんうん、STATUSがUpになってる。
コンテナに入って作業したい場合は、とりあえず-itdって覚えても良いかもしれない。
TODO: 1個づつオプション外して試してみたけど、ここの挙動が上手く理解できていないので別の機会にちゃんと調べる。

# コンテナの中に入る
$ docker exec -it node-react /bin/bash
root@8bf7a6704bb9:/# node -v
v12.16.0

ちゃんと指定したバージョンで入ってますね

コンテナにアプリケーションをぶちこむ

最初は「ファイル転送でもすれば良いんかなぁ」とかかなり脳筋なこと考えていたんですけど、考えてみたらgithubからcloneしてきて起動すれば良いんじゃね?と思ったのでお試し。

root@8bf7a6704bb9:/# git --version
git version 2.20.1

git入ってる!勝った

# 適当なディレクトリへ移動して
root@8bf7a6704bb9:/# cd /usr/src/

# cloneして
root@8bf7a6704bb9:/usr/src# git clone https://github.com/wol-827/first-step.git
Cloning into 'first-step'...
remote: Enumerating objects: 22, done.
remote: Total 22 (delta 0), reused 0 (delta 0), pack-reused 22
Unpacking objects: 100% (22/22), done.

root@8bf7a6704bb9:/usr/src# cd first-step/

# アプリ起動に必要なモジュールインストールして
root@8bf7a6704bb9:/usr/src/first-step# npm i
found 0 vulnerabilities

# アプリケーション起動
root@8bf7a6704bb9:/usr/src/first-step# npm start
Compiled successfully!

You can now view sample-app in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://172.17.0.2:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.

起動できてそう!良い感じ

コンテナ起動時にポートフォワード設定し忘れてしまったので、改めて設定。
アプリケーションは3000番で起動していて、8080へ飛ばしたいのでこんな感じ。

$ docker run -itd -p 8080:3000  --name node-react node:12.16.0-buster
  • 起動前
    image.png

  • 起動後
    image.png

できた。ウレシイ。

まとめ

Dockerについて調べていると、環境を汚すことなくアプリケーションの実行環境を用意できる、なんでことが書かれているのをよく見るんですが身を持ってそれを実感しました。
ホスト側にDockerイメージだけ用意してあれば、nodeやらReact用のモジュールやらはコンテナの中にだけ入れるのでホスト側はキレイな体を保てると。専用のコンテナを立てるのでnodeのバージョンの切り替えも不要。
イメージはこれで、githubのリポジトリはこれ、コマンド実行手順はこれ、っていう風に準備すれば、とりあえず環境は手に入る。便利便利。

とはいえ今回の場合、コンテナの中に入ってcloneしたり色々コマンド実行しているのが冗長。
次はこの辺りをコマンド1発で出来るようにしたいと思います。たぶん出来る。出来ろ。

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

WSL1を残したまま、WSL2のUbuntuでdockerを動かすまで

tl;dr

WSL1のUbuntu18.04を消したくないので、ストアを使わずにWSL2へUbuntu18.04を手動インストールし、そこにdockerをインストールします。

Windows Insider Program への参加

公式の通りに参加します。
- サイトにてWindows Insider Programへ参加する
- 参加したアカウントとWindows10への紐付け

WSL2の準備

windows updateより、新しいwindowsのビルドを取得します。

新しいビルドがインストールされたら、管理者として起動したpowershell上で以下のコマンドを実行します。
ちなみにWSL1を既に実行している場合は、2行目は不要です。

Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

Ubuntuパッケージのダウンロード

microsoftストアのUbuntu18.04は、既にWSL1にセットアップされているため使えません。
そのため、Ubuntu18.04パッケージをここからダウンロード。
ubuntu-bionic-core-cloudimg-amd64-root.tar.gzというファイルがダウンロードされます。

LxRunOfflineのダウンロード

WSLを管理するためのフル機能のユーティリティであるLxRunOfflineを、ここからダウンロード。LxRunOffline-v3.4.1-msvc.zipです

Ubuntuをインストール

ダウンロードしたLxRunOfflineを適当な場所に解凍します。
ついでにダウンロードしたUbuntuパッケージも同じ場所に配置します。
powsershellを管理者として起動し、カレントをLxRunOfflineに移動後、以下のWSLインストールコマンドを実行します。

LxRunOffline i -n {任意のディストリビューション名} -d {インストールしたい任意のディレクトリ} {パッケージファイル}

私の場合は、「D:\WSL\Ubuntu-18-wsl2」にインストールし、ディストリビューション名(今後、WSLの操作に使用する)を「Ubuntu-18-wsl2」としました。

> .\LxRunOffline i -n Ubuntu-18-wsl2 -d D:\WSL\Ubuntu-18-wsl2 -f ubuntu-bionic-core-cloudimg-amd64-root.tar.gz

Ubuntuの準備

引き続きのLxRunOfflineコマンドを使って、Ubuntuを起動します。まだ、この時点ではWSL2になっていません。
ディストリビューション名は「Ubuntu-18-wsl2」になっていますが、そこは、ご自分のつけたディストリビューション名に読み替えてください。

> .\LxRunOffline run -n {作成したディストリビューション名}

私の場合は、以下のコマンドを実行しました。

> .\LxRunOffline run -n Ubuntu-18-wsl2

起動したUbuntuに対し、以下のコマンドを実行します。
途中で「myuser」というユーザーを作成していますが、そこは任意に変えてください。

# apt update
# apt upgrade
# adduser myuser
# apt install sudo
# gpasswd -a myuser sudo
# login myuser

最後のコマンドで、作成したユーザーでログインしたので、idコマンドを使い、作成したユーザーのuidを確認します。

$ id
uid=1000(myuser) gid=1000(myuser) groups=1000(myuser),27(sudo)

uid(私の場合は1000)を確認したら、一旦Ubuntuからログアウトします。

WSLのデフォルトユーザーの設定

管理者として起動したpowershell上で以下のコマンドを実行します。

> .\LxRunOffline su -n {作成したディストリビューション名} -v {上記で確認したuid}

私の場合は、以下のコマンドを実行しました。

> .\LxRunOffline su -n Ubuntu-18-wsl2 -v 1000

WSL1 から WSL2 へのアップグレード

管理者として起動したpowershell上で以下のコマンドを実行します。

> wsl --set-version {作成したディストリビューション名} 2

私の場合は、以下のコマンドを実行しました。

> wsl --set-version Ubuntu-18-wsl2 2

以下のコマンドで正しくアップグレードされたか確認します。

> wsl -l -v
  NAME              STATE           VERSION
* Ubuntu-18.04      Running         1
  Ubuntu-18-wsl2    Running         2

Ubuntu-18.04がWSL1で実行中であり、Ubuntu-18-wsl2がWSL2で実行中であるのがわかります。

dockerのインストールと確認

powershell上で以下のコマンドを実行し、WSL2のUbuntuにログインします。

> .\LxRunOffline run -n {作成したディストリビューション名}

Ubuntuにログイン後、公式通りの手順でdockerをインストール。

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

? 動作確認

dockerサービスの起動

$ sudo service docker start

hello-world実行

$ sudo docker run hello-world

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

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

以上。

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

docker-compose run web rake db:createできないときにやったこと

エラー文

Starting myapp_db_1 ... done
warning Integrity check: System parameters don't match                                                                                                                                                     
error Integrity check failed                                                                                                                                                                               
error Found 1 errors.                                                                                                                                                                                      


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================

#ここの文章を参照した
To disable this check, please change `check_yarn_integrity`  
to `false` in your webpacker config file (config/webpacker.yml).


yarn check v1.21.1
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.

解決策

「config/webpacker.yml」ファイルのcheck_yarn_integrity: trueの箇所をfalseに変更したら解決した。

check_yarn_integrityって何?

JavaScriptのパッケージをチェックしたり、保全したりする役割があるらしい。。。

参考記事

webpacker の check_yarn_integrity オプションについて調べてみた
yarnが原因でdocker-compose runが実行できないときの対処法
上記記事を参考にしたらできたので執筆者には感謝です。

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

Railsチュートリアルの開発環境を Docker にしてみなイカ?

【概要】

Railsチュートリアルで作成する Sample App の開発環境を Docker でコンテナ化しました。

細かい用語の勉強はおいといて、とりあえず動くものを作ってみましょう。



【本文】

□ 事前準備

※ 準備済みの場合は省略可能

■ Docker 準備

インストール方法については、検索したら大量に出てくることから、本記事では詳細を記述しないため、ご了承ください。以下のURLが参考になるかと思います。
- Mac OS X に Docker Toolbox のインストール — Docker-docs-ja 1.10.0 ドキュメント

■ Sample App 準備

 ご存知の通り、Railsチュートリアルでは、Ruby on Rails を使用してSample App という名称のアプリケーションを作成します。しかし、一から作成するのは手間でしたので、本記事では、YassLab(株)がGitHubに公開しているサンプルコードを使用しました。
 なお、サンプルコードを使用する手順は、以下の通りです。

○ 1: GitHubから自分のPCにダウンロード

bash
 $ git clone https://github.com/yasslab/sample_apps.git

○ 2: 使用するプロジェクトのディレクトリ準備

bash
 $ mkdir sample_app
 $ cp -rp sample_apps/5_1_2/ch14/* sample_app/
 $ cd sample_app

□ 1: Dockerfile

  • プロジェクトのルートディレクトリからの操作を想定します。

○ 1: Dockerfile生成

bash
 $ mkdir docker
 $ touch docker/Dockerfile

○ 2: Dockerfileの編集

Dockerfile
FROM ruby:2.4.9-alpine3.11

ENV LANG C.UTF-8 \
    TZ Asia/Tokyo

ENV BUILD_PACKAGES="build-base" \
    DB_PACKAGES="sqlite-dev postgresql-dev" \
    RAILS_PACKAGES="tzdata nodejs imagemagick" \
    FAVORITE_PACKAGES="less"

RUN apk update && \
    apk upgrade && \
    apk --update --no-cache add \
        ${BUILD_PACKAGES} \
        ${DB_PACKAGES} \
        ${RAILS_PACKAGES} \
        ${FAVORITE_PACKAGES}

WORKDIR /app

COPY Gemfile \
     Gemfile.lock \
     /app/

RUN bundle install --jobs=4

# 下記のコードは、頻繁に Gemfile を変更する場合、コメントアウトを推奨します。
# RUN apk del ${BUILD_PACKAGES}

# https://github.com/bundler/bundler/issues/6154
ENV BUNDLE_GEMFILE='/app/Gemfile'

□ 2: docker-compose.yml

○ 1: Dockerfile生成

bash
 $ touch docker-compose.yml

○ 2: docker-compose.ymlの編集

docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      dockerfile: ./docker/Dockerfile
    ports:
      - 3000:3000
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    volumes:
      - ./:/app:cached
    stdin_open: true
    tty: true     

□ 3: コンテナ生成

○ 1: docker-compose.yml を元にコンテナに必要なイメージを構築

bash
 $ docker-compose build

○ 2: 構築したイメージを元にコンテナを構築して起動

bash
 $ docker-compose up -d

□ 4: Sample App の準備

  • ここまでの操作により、Docker によるコンテナ化は終了といって差し支えありません。
  • ここからは、通常の Rails アプリケーションに必要な操作と同じです(Heroku の操作感に似てるかと)。

○ 1: コンテナ環境に入る

  • Alpine Linux のデフォルトのログインシェルは、ashになります。
  • bashで操作したい方は、拡張機能に適宜追加してください。
bash
 $ docker-compose exec app ash

○ 2: データベース関係の準備

  • ご存知の通りデータベースがない状態では、 http://localhost:3000 にアクセスしてもアプリケーションは動きません。
  • コンテナ内で rails コマンドを試してみましょう。
ash(コンテナ内)
 $ rails db:create
 $ rails db:migrate
 $ rails db:seed

○ 3: 作業完了

  • これで、開発環境のコンテナ化が完了しました。
  • http://localhost:3000 にアクセスして、試しに操作してみてください。
  • 終了時は、以下のコマンドとなります。
bash
 # 一時停止
 $ docker-compose stop
 # 再起動
 $ docker-compose start
 # コンテナ削除
 $ docker-compose down

□ ※ 注意事項等

■ 注意事項

※ 1: 新たにGemを追加する場合

  • bundle install が以下のように失敗する可能性があります。
    • Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
  • 原因として、コンテナ環境の OS である Alpine Linux において、導入したい Gem に必要となる OS の拡張機能(=package)がインストールされていないことが多くの理由になるかと思われます。
  • 解決策として、エラー文中に記載されているログを$ cat 〜色々path〜/mkmf.logで内容を確認して、必要な拡張機能を$ apk add 〜拡張機能〜で逐一インストールしていけば、解決されるはずです。
  • 本法で解決した場合は、$ docker-compose build --no-cacheの際に追加でインストールした拡張機能がリセットされるため、 Dockerfile にも必ず追加しておいてください。
  • 大元の原因は、本記事で使用した Dockerfile は、限られた拡張機能しかインストールしていないことです。もし、不便に感じる場合は、別のイメージを使用して、自分だけのコンテナ環境の作成に挑戦してみると良いでしょう。Docker 及び Linux の学習に繋がります。
  • また、他のエラーとして、 Gem はインストールされるが正常に動作しないこともあります。気が向いたら別記事で簡単に説明します。

※ 思いつき次第追加

■ あとがき

プログラマへの転職前、駆け出しエンジニアで Docker を勉強してる人を散見して、正直焦ってました。入門用の記事や動画を見ても、訳の分からない Dockerfile にコマンドの数々...しかし、実際に転職してからDockerfile の中身を理解してなくても、コンテナ作って作業ができれば十分でした。

この経験から、初期段階ではコマンドが扱えてコンテナを立ち上げられる程度の理解で十分と考えたため、コピペでファイルを作成して、コマンド打つだけの構成にして、簡単に Docker の世界を体験できるようにしてみました。

もちろん、Dockerfile から考えて作成するのも良い勉強になりますが、入社初期にインフラ周りを触らせることも少ないと思うので、コーディングに直接関係する学習を優先した方がよいでしょう(DBとかSQLとかActiveRecordとか...)。

Docker への入門にあたり参考になりましたら幸いです。


  1. Railsチュートリアル公式では、Rubyのバージョンが2.4.0でしたが、当該バージョンのDockerfileがサポートされていないため、サポート中で同じマイナーバージョンである2.4.9を選択しています。2.4.0を使用したい場合は、Dockerfile中の FROM部分をFROM ruby:2.4.0-alpineに置換してください。 

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

Docker Desktop for Mac/Win (Docker for Mac/Win) が遅くて困っているあなたへ

はじめに

Docker Desktopを使用していて動作が重い、CPU負荷が凄いことになっている、volume mountするとIOがとても遅いといった事象で困っている方は沢山いらっしゃるかと思います。

私も同じく、Docker for Macを使用していてDocker(Daemon)の立ち上がりが遅かったり、暴走してDockerのプロセスをkillしたりすることが多々ありました。

しかし、諸々の事情でDockerで開発しなければならない場合もあると思います。
そんな方は是非、こちらの記事を参考にVagrant on Dockerへの乗り換えを検討してみてください!

メリット

  • Docker Desktop特有のVolume mount遅い問題が解決できる
  • Windows 10ユーザーはProじゃなくても大丈夫
  • CPU暴走しなくなる?(体感の問題かも)
  • ローカルに複数のDocker Daemonを建てられる
    • Kubernetesのクラスタも作れます
  • VMのイメージを他の人に渡せば開発環境ごと共有できる
  • ホストOSが変わってもそのまま使える
    • PCのお引っ越しも楽々!
    • 開発ツールのインストール用shell(tigなど)を作ってしまえば開発環境も一発で構築!

デメリット

  • Linuxの知識が必要(Docker使いなら大丈夫かと思います)
  • コンテナ内で生成したファイルはPermission変更が必要
    rails generatephp artisanのようなコマンドでソースの雛形を生成する際には毎回権限付与が必要

Permissionは以下のコマンドで対応可能です。
LinuxでDocker運用している方で簡単な回避方法があれば教えていただきたいです。
(Dockerfileでadduserする方法以外)

# ホストではなく、VM上で実行(Dockerコンテナ外)
sudo chmod 777 <対象のファイル>
# または
sudo chmod -R 777 <対象のディレクトリ>

開発環境

  • macOS (Windowsでも大丈夫なはず)
  • VirtualBox
  • Vagrant
    • Ubuntu 18.04 LTS
      • Docker
      • Docker Compose

※階層で仮想環境の中身を表現しています

セットアップ

VirtualBox/Vagrantインストール

以下、Macの場合で記載します。
Windowsの方は以下からダウンロードしてください。
https://www.vagrantup.com/downloads.html

# 前提:Homebrew, hobebrew-caskが使用できること
brew cask install virtualbox
brew cask install vagrant

VMのセットアップ

私はUbuntu大好きっ子なので、Ubuntuを対象に構築します。

楽をしたい方は以下のリポジトリをgit cloneしてください。
https://github.com/MasanoriIwakura/vagrant-docker.git

# Vagrantの設置を保持するディレクトリを作成
mkdir vagrant-docker
cd vagrant-docker

# Vagrantfile作成
vagrant init ubuntu/bionic64

VM内にDockerをインストール

Vagrantfileを編集し、初期起動時に自動でDockerをインストールされるようにします。

今回は記載しませんが、vimを使用されている方はvimrcの設定、
gitの初期設定、tigのインストールなど、開発で使用するツールの設定もこのタイミングで行っておくと便利です。

# インストール用のshellを作成
touch dockerinstall.sh

中身はこんなかんじです。

#!/bin/bash

sudo apt update
sudo apt -y install \
        apt-transport-https \
        ca-certificates \
        curl \
        gnupg-agent \
        software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

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

sudo apt update
sudo apt -y install docker-ce docker-ce-cli containerd.io

# permission settings(sudoなしでdockerコマンドを使用する設定)
sudo usermod -aG docker vagrant
sudo systemctl restart docker

exit 0

直接Vagrantfileにインストール用のコマンドを記載することもできますが、
可読性と管理のし易さを考慮してshellに分けました。

Vagrantfileの修正

上記のshellを実行したり、開発環境を整えるためにVagrantfileに修正を加えます。

# config.vm.box = "ubuntu/bionic64" の下あたりに追記
config.vm.provision :shell, path: "dockerinstall.sh"

# docker-compose.ymlでportsを記載する場合、ホストとポートフォワードするには以下を追記
# これを記載するとhttp://localhost:8080 でアクセスできる
config.vm.network "forwarded_port", guest: 8080, host: 8080

# ホストのフォルダをマウントしたい場合
# 注意:docker, docker-composeのvolumeと同じにすると遅くなるのであくまでもホストからデータを移動したい時用
config.vm.synced_folder "./mnt", "/host_data"

# VMのスペック調整
# config.vm.provider "virtualbox" do |vb| のコメントを解除
# 対応するend のコメントも解除
config.vm.provider "virtualbox" do |vb|
  # CPUのコア数設定
  vb.cpus = "2"

  # メモリ設定
  # 私はホストが16GBなので8192に設定しています
  vb.memory = "4096"
end

いざ、実行

# config.vm.synced_folderを設定している場合は先にフォルダを作成しないとエラーになります
mkir ./mnt

# VM立ち上げ
vagrant up

# VMにssh
# VMから抜ける時はexit
vagrant ssh

# VM終了(ホスト側で実行)
vagrant halt

ここで一点注意
vagrant haltをすると起動中のコンテナも問答無用で停止します。(シャットダウンと同じイメージ)

その他

私はVisual Studio Code(VSCode)を使用して開発しているのですが、Intellij IDEAやVSCodeを使用している場合は
リモート設定を行うとローカルで開発している感覚でコーディングができるのでおすすめです!

VimやEmacs派の方はそのままsshで開発できちゃいますね。

VSCodeでの設定例は割愛しますが、私は以下のリンクを参考に設定しました。
Remote-SSHという拡張機能を使用します。
https://qiita.com/hppRC/items/9a46fdb4af792a454921

Intellij IDEAはこのへん??
https://pleiades.io/help/idea/editing-individual-files-on-remote-hosts.html

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

reCAPTCHAのサイトを毎日自動スクレイピングする (6/7: コンテナ化)

  1. 要件定義〜python環境構築
  2. サイトのスクレイピング機構を作る
  3. ダウンロードしたファイル(xls)を加工し、最終成果物(csv)を作成するようにする
  4. S3からのファイルダウンロード / S3へのファイルアップロードをつくる
  5. 2captchaを実装
  6. Dockerコンテナで起動できるようにする
  7. AWS batchに登録

サーバ上で動くようにする

前回までで、一度起動させれば、あとは何もせず自動で動くようになりました。
cronでも設定すれば毎日の実行でもできますが、このままだと 自分のPCをずっと起動させることになってしまいます。
なんとかサーバ上で起動するようにしたいところです。

ここで壁になるのが、今回のスクレイピングは、Displayが必須になること
Chromeのheadlessモードなども試したのですが、うまくいきませんでした。

というわけで今回は、少し古い技術ではあるもののXvfbという仮想ディスプレイを作成できる仕組みを使って実装することに。

Xvfbは、Linux上で動くアプリケーションです。
ので、LinuxのDockerコンテナを使って実装し、最終的に AWS batchを使ってバッチ実行する方針でいくことにしました。

Docker image作成

作成のための検証

※Dockerのダウンロードやインストールは割愛します

まずは、自分の使うDocker imageを作っていきます。
Xvfbを調べていたら利用実績が多そうだった、CentOSを使っていきます。

まずは既存のcentOS imageから起動させ、必要なアプリケーションを実際にインストールしてみます。

mac(host)
docker pull centos          #DockerHubからcentOSのimageを引っ張ってくる
docker run -it -d centos    #起動させる
docker ps                   #起動を確認&コンテナIDを取得
docker exec -it b7948c7802eb /bin/bash  #コンテナ側のターミナルに入る

必要なのは

  • python
  • pythonパッケージそれぞれ
  • Xvfb
  • firefox

なのでそれぞれインストールしてみます。

container内でいろいろ試す
yum install -y python36 #python入れる
python3 -m pip install --upgrade pip #pip入れる
pip install requests #必要なパッケージ入れてみる
...
yum -y install xorg-x11-server-Xvfb  #Xvfbのインストール
yum -y install firefox  #firefoxのインストール
Xvfb :1 -screen 0 1600x1200x16 & #Xvfbの起動
export DISPLAY=:1 #:1と定義したディスプレイを使う
firefox #firefoxを起動

お。画面がよく見えないのですが、firefox起動してるぽい…?
というわけで次は、ここで自分のプログラムを実行させてみます。

ここで私はDockerfileの作成に入りました。
本当はdocker cpコマンドとかを使って入れてみて試すほうが効率がいいのかも。

Dockerfileの作成

FROM centos
ENV TZ JST-9  #(1)

#ホームディレクトリを設定
ENV HOME=/home
WORKDIR $HOME

#自分のアプリ(app以下)をhome以下に移す
COPY .  $HOME/

RUN yum install -y python36
RUN python3 -m pip install --upgrade pip
RUN pip install -r app/requirements.txt #(2)
RUN yum -y install xorg-x11-server-Xvfb
RUN yum -y install firefox

RUN chmod 744 startup.sh
CMD ["./startup.sh"]  #(3)

(1) どうやらタイムゾーンはUTCになってしまう模様。今回のバッチは時間が重要なのでタイムゾーンを変更しています
(2) 最初は一行ずつ書いていたのですが、まとめたほうがきれいだったのでrequirements.txtに必要パッケージをまとめました。必要パッケージはpip freezeコマンドで出てきたものをそのまま記載。
(3) Xvfbの起動コマンドは、docker runのタイミングですることが必要だとわかったので、shellを作成してまとめました。

startup.sh
#!/usr/bin/env bash
Xvfb :1 -screen 0 1600x1200x16 &
export DISPLAY=:1
python3 app/source/run.py --run_mode test #最後はnormalにするが

linuxで動くために少々変更

  • geckodriverはlinux用のものをダウンロード
  • OSを判断し、どのdriverを使うのか、で分岐するように変更

最終的なファイル構成はこうなります。

├── Dockerfile
├── README.md
├── app
│   ├── drivers
│   │   ├── geckodriver
│   │   └── geckodriver_linux
│   ├── requirements.txt
│   └── source
│       ├── run.py
│       ├── scraping.py
│       ├── make_outputs.py
│       ├── s3_operator.py
│       └── configs.py
├── startup.sh
└── tmp
    ├── files
    │   ├── download
    │   ├── fromS3
    │   └── toS3
    └── logs

起動してみる

下記のコマンドで実行できます。

docker build -t myapp .
docker run -it myapp

本当はこんなスラスラといかなかったですけどね…。上のコマンドは40回くらい打った気がします。

しかし、うまく行ったときは感動モノです!
画面は全く見えないけど、コンソールは出ているし、S3にファイルができているのですから。

最後は、AWS上で実行させるだけ…。ゴールが見えてきました。

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

Swaggerを管理しつつ、スタブを自動生成する環境をDockerを使って構築する

APIドキュメントとスタブをまとめて管理できる環境を作りました。

やりたいこと

フロントエンドとバックエンドの認識合わせ、及び開発のため、APIの定義が存在するファイルはフロントエンドとバックエンドが共有するリポジトリに載せておきたいです。
そこで、APIの定義にはSwaggerを使うとします。
この場合、下記を全て実現できると幸せになれると感じました。

  • SwaggerをSwagger Editorを使ってAPI定義を書きたい
  • Swagger UIでAPI定義を見たい
  • 作ったSwaggerファイルから、自動生成されたレスポンスを返してくれるスタブが欲しい

ということで、これらを実現する環境をDockerを使って構築していきたいと思います。
Dockerを使えば環境構築も一瞬で終わりますし、スタブの再生成もコンテナをビルドするだけで行えるので、それぞれ相性が良いです。

構成

ソース

ディレクトリ構成

.
├── docker/
│   └── stub/
│       └── Dockerfile  # スタブ用Dockerfile
├── swagger/            # swagger関連のソース用ディレクトリ
│   ├── stub/           # swagger.yamlから自動生成されたスタブのソース
│   │   ├── index.js
│   │   ├── ...
│   │   └── ...
│   └── swagger.yaml    # API定義ファイル
└── Makefile            # 各種コマンド管理

Swagger Editorを使ってAPI定義ファイルであるswagger.yamlを生成し、そのファイルを元にスタブに設置するファイル及び、スタブコンテナをビルドします。

Makefile

ビルドコマンドや各種サーバー起動コマンドの定義です。

IMAGE_STUB=api_stub
PORT_SWAGGER_EDITOR=8081
PORT_SWAGGER_UI=8082
PORT_STUB=8080
SWAGGER_DIR_PATH=$(PWD)/swagger
SWAGGER_YAML_PATH=${SWAGGER_DIR_PATH}/swagger.yaml

# swagger.yamlからスタブ用ソース及びスタブコンテナをビルドする
.PHONY: build_stub
build_stub:
    @echo "=== Generating stub file from swagger.yaml is running... ==="
    docker run --rm \
        -v ${SWAGGER_DIR_PATH}:/swagger \
        swaggerapi/swagger-codegen-cli generate \
        -l nodejs-server \
        -i /swagger/swagger.yaml \
        -o /swagger/stub
    @echo "=== Generating stub file is completed. ===\n"
    @echo "=== Building new container... ==="
    docker build -f docker/stub/Dockerfile -t ${IMAGE_STUB} .
    @echo "=== Building container is completed. ==="

# スタブを起動
.PHONY: run_stub
run_stub:
    docker run --rm -p ${PORT_STUB}:8000 ${IMAGE_STUB}

# Swagger Editor用サーバーを起動
.PHONY: run_swagger_editor
run_swagger_editor:
    docker run --rm -p ${PORT_SWAGGER_EDITOR}:8080 swaggerapi/swagger-editor

# Swagger UI用サーバーを起動
.PHONY: run_swagger_ui
run_swagger_ui:
    docker run --rm -p ${PORT_SWAGGER_UI}:8080 \
        -v ${SWAGGER_YAML_PATH}:/usr/share/nginx/html/api/swagger.yaml \
        -e API_URL=http://localhost:${PORT_SWAGGER_UI}/api/swagger.yaml \
        swaggerapi/swagger-ui

docker/stub/Dockerfile

Node.jsでホスティングをするだけのシンプルなサーバーです。

FROM node:13.7.0-alpine3.10

ENV APP_HOME /usr/src/app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# スタブ用ソースをコンテナにコピー
COPY swagger/stub/ $APP_HOME

EXPOSE 8000
RUN npm install

ENTRYPOINT ["npm", "start"]

使ってみる

ステップ1: Swagger Editor

まずは、$ make run_swagger_editor コマンドでSwagger Editorを起動します。
http://localhost:8081 にアクセス。
スクリーンショット 2020-02-16 14.57.46.png

Swagger Editor上で、 GET /persons APIを定義。

swagger.yaml
swagger: '2.0'
info:
  version: 1.0.0
  title: Swagger-sample
  description: |
    #### サンプル
schemes:
  - http
host: localhost:8080
basePath: /api/v1
paths:
  /persons:
    get:
      summary: Get all persons.
      parameters: []
      responses:
        200:
          description: A JSON array of person model
          schema: 
            type: array
            items:
              $ref: '#/definitions/Person'
            example:
              - id: 1
                name: Mike
                age: 23
              - id: 2
                name: Jun
                age: 20
              - id: 3
                name: Jack
                age: 26

definitions:
  Person:
    type: object
    properties:
      id:
        type: integer
      name:
        type: string
      age:
        type: integer

Swagger Editor上の Save as YAML をクリックし、ダウンロードされたswagger.yamlをswaggerディレクトリ配下へ移動。
スクリーンショット 2020-02-16 15.19.52.png

$ cp ~/Download/swagger.yaml ./swagger

ステープ2: Swagger UIでAPIを確認

$ make run_swagger_ui コマンドで、Swagger UIを起動します。
http://localhost:8082 にアクセス。
すると、先ほど作成したAPIがSwagger UI上で表示されることを確認できます。
スクリーンショット 2020-02-16 15.23.14.png

ここまでで、Swaggerを管理する環境はできました。
それでは、本題のスタブの用意へと移りましょう。

ステップ3: スタブコンテナビルド

$ make build_stub でスタブコンテナをビルド。
Building container is completed. が表示されれば完了です。

なお、ここでは下記の順でビルドが行われます。
1. スタブ用ソースを自動生成
2. 自動生成されたソースがパッケージングされたコンテナをビルド

ステップ4: スタブを使用してAPIを呼び出す

$ make run_stub でスタブコンテナを起動。
まず、http://localhost:8080/docs へアクセスすると、先ほど定義したAPIがドキュメントとして表示されます。
スクリーンショット 2020-02-16 15.28.35.png

では、http://localhost:8080/api/v1/persons へアクセスしてみましょう。
すると、SwaggerファイルにてExampleで定義したレスポンスが返ってくることが確認できます。
スクリーンショット 2020-02-16 15.29.27.png

これで、Swaggerファイルで定義したレスポンスからスタブを自動生成し、呼び出せることが確認できました!

まとめ

Swagger Editorでswagger.yamlを作成し、それをSwagger UIで確認、及び定義したAPIのレスポンスを返すスタブに変換し呼び出せる環境を構築しました。
APIを開発するのであればAPIドキュメントは必須ですし、さらにそのAPIを開発中にフロントエンド側で使いたいとなるとスタブの開発は不可欠です。
スタブの自動生成を使用すれば、APIとスタブの二重管理などの手間も省けます。

しばらく使ってみて、また知見があれば記録を残そうと思います。

補足

Swagger Editorで編集したファイルをダウンロードしてswaggerディレクトリ配下に設置するところのみ、手動のオペレーションが発生してしまっています。
ここに関して自動化させられるやり方をご存じの方がいらっしゃいましたら、アドバイスをいただけますと嬉しいです m(__)m

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

コンテナからイメージを作成してdocker hubにpushする

目的

dockerコンテナにriscvのクロスコンパイラ環境を構築する際にriscv-toolchainのbuildに想像以上に時間が掛かり、また同じように環境作成を行うのはしんどいと思ったので環境作成中に一旦commitしてイメージを作成しようと考えた。ついでにdocker hubへのpushも行っておく。

参考記事

https://qiita.com/tubone/items/a3bad04abf4c700cae3d
https://www.memotansu.jp/docker/626/
http://docs.docker.jp/engine/reference/commandline/commit.html

作業環境

  • Windows10 Home Insider Preview
    • バージョン:2004
    • OSビルドバージョン:19564
  • WSL2 Ubuntu18.04
    • Remote-WSL(VSCode)

手順

稼働中のコンテナの停止

まずは稼働中のコンテナを停止するので、停止するコンテナを調べる。

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
e21a09577ff9        rust-env            "/bin/bash"         10 hours ago        Up 10 minutes                           rust-env

調べて停止したいコンテナがあったら停止する。
(commitする際にコンテナが一時停止するようなのでこの手順はなくていいかも)

$ sudo docker stop

dockerコンテナのイメージ作成

docker commitで以下のように作成する。
docker commit [コンテナ名] [リポジトリ名]:[tag名]

$ sudo docker commit rust-env chilchil/rust-env:latest
sha256:1cd5668d157123abe7b3422623c21f96766df0df7e9c2a850e1d28aa488dd1fe

イメージが作成されたかどうか確認する。

$ sudo docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
chilchil/rust-env      latest              1cd5668d1571        53 seconds ago      14.3GB

docker hubにpush

作成したイメージをdocker hubにpushする。docker hubへのリポジトリの作成とかは以下を参照。
https://qiita.com/umi/items/d4b5a68263ad0444693b

$ sudo docker login
Authenticating with existing credentials...
~省略~
Login Succeeded
$ sudo docker push chilchil/rust-env
The push refers to repository [docker.io/chilchil/rust-env]
~省略~
latest: digest: sha256:175c3dadc63c15f5a3c369078999722553b9200158028cf97685baa911d0e168 size: 2624

pushしたdockerイメージを確認する。(publicである場合)

takayama@DESKTOP-MO8SE8A:~$ sudo docker search chilchil
NAME                   DESCRIPTION         STARS               OFFICIAL            AUTOMATED
chilchil/rust-env                          0               

以上になります。

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

docker runがエラー(Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use)

docker run -p 80:80 -p 443:443 -d --privileged centos:latest /sbin/init

を行うと下記エラーとなる。

docker: Error response from daemon: driver failed programming external
 connectivity on endpoint amazing_proskuriakova 
(65b0d6d847914cee8f6129bd36fed4d0a1c67843be6413d238f0c376af150950): Error 
starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

結論

80番ポートであるapacheが起動していたから起こったエラー

解決策

1.ポート番号をずらしてコマンドを実行してみる。

(sudo)docker run -p 88:88 -p 443:443 -d --privileged centos:latest /sbin/init

このようにポート番号を80ではなく88にずらして実行

2.すでに80番ポートで起動しているプロセスを終了する

sudo lsof -i -P | grep "LISTEN"

[root@ip-172-31-28-29 ~]# lsof -i -P | grep "LISTEN"
rpcbind   2677      rpc    8u  IPv4  16507      0t0  TCP *:111 (LISTEN)
rpcbind   2677      rpc   11u  IPv6  16510      0t0  TCP *:111 (LISTEN)
httpd     3057     root    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
httpd     3093   apache    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
httpd     3094   apache    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
httpd     3095   apache    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
httpd     3096   apache    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
httpd     3097   apache    4u  IPv6  18359      0t0  TCP *:80 (LISTEN)
master    3200     root   13u  IPv4  18805      0t0  TCP localhost:25 (LISTEN)
sshd      3364     root    3u  IPv4  20172      0t0  TCP *:22 (LISTEN)
sshd      3364     root    4u  IPv6  20174      0t0  TCP *:22 (LISTEN)
container 3502     root    7u  IPv4  21589      0t0  TCP localhost:34781 (LISTE )

apacheが起動していました。

さっそく終了させます。

sudo apachectl stop

今思えば、以前にシステムがブートするたびに Apache ウェブサーバーが起動するように下記コマンドで設定していました。

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

Dockerで起動したJupyter Notebookでvimキーバインドを使う

概要

最近はデータサイエンスの勉強で統計学の本を読んでいるのですが、本を読んでいるだけだとなかなかイメージしにくいこともあるので、Jupyter Notebookを使って手元でコードを書きながらやりたいなと思いました。
Jupyter Notebookでコード書くならvimのキーバインドが使えないとテンションが上がらないのでvimが使えるようにしたいと思いましたが、多少ハマった部分などあったのでやり方をまとめました。

環境

バージョン
Mac 10.15.3
Docker 19.03.4
docker-compose 1.24.1

環境構築手順

Dockerfileとdocker-composeを使ってvimのキーバインドが使えるJupyter Notebookを起動します。
※以下ファイルはGitHubにもまとめているのでご参考ください。
https://github.com/hikarut/Data-Science

1. notebook保存用のディレクトリ作成
$ mkdir notebooks
2. Dockerfileの作成
Dockerfile
FROM jupyter/minimal-notebook:latest

USER root

RUN pip install jupyter_contrib_nbextensions && \
    jupyter contrib nbextension install --user && \
    git clone https://github.com/lambdalisue/jupyter-vim-binding /home/jovyan/.local/share/jupyter/nbextensions/vim_binding && \
    jupyter nbextension enable vim_binding/vim_binding

EXPOSE 10000
CMD ["bash"]

jupyter-vim-bindingレポジトリのクローン先はコマンドjupyterのpathと合わせる必要があります。(jupyter --pathコマンドで確認出来ます)

3. docker-compose.ymlの作成
docker-compose.yml
version: '3'
services:
  data-science:
    restart: always
    build: .
    container_name: 'data-science'
    ports:
      - "10000:10000"
    working_dir: '/root/'
    tty: true
    volumes:
      - ./notebooks:/root/notebooks/
4. コンテナのビルド
$ docker-compose up -d --build
5. コンテナにログイン
$ docker-compose exec data-science bash
6. Jupyter Notebookの起動
/root# jupyter notebook --port 10000 --allow-root

表示されるhttp://127.0.0.1:10000/?token=xxxxxxxxxxxxxxxxにアクセスします。

7. VIM bindingのエクステンションを有効にする

デフォルトだとエクステンションの設定にdisableにチェックが入っているのでチェックを外して有効にします。
スクリーンショット 2020-02-16 9.41.55.png

これでnotebook上でvimが使えるようになります
スクリーンショット 2020-02-16 9.47.41.png

最後に

Jupyter Notebookでvimのキーバインドを使えるようにするやり方は結構まとまっていたのですが、色々試していたら以外とハマった部分もあったので自分なりにまとめてみました。
これで快適なNotebookが書けそうです!
(ただ今回はユーザーを全てrootにしちゃったのでその辺は変えた方が良いかもです。。)

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

【Docker入門①】そもそも『Docker』とは…?

この記事では、《Docker や コンテナ》について、
僕が学習した内容をまとめています。

  • 『Docker』とは…?
  • 『Docker』って何が良いの…?
  • 『Docker』のアーキテクチャ(構成)

こういった疑問についてまとめています。

※本記事は、自分で学習したことのまとめ用として書いています。
尚、解説で誤った点があれば、スローして頂ければ喜んでキャッチしますのでお願い致します。

『Docker』とは…?

docker.jpg

『Docker』とは・・・

Linux上でコンテナを作成・管理・実行するためのプラットフォームです。

Docker社(旧dotCloud社)によって、2013年3月に初版がリリースされ、現在ではインフラ関係やDevOps界隈で注目されている技術の一つです。

Windowでも・・・
Windows Server 2016 からはWindowsコンテナが利用できるようになりました。
※Windowsコンテナは、Windows上でのみ実行可能です

『Docker』を利用すると何がメリットなの…?

『Docker』はLinuxのコンテナ技術を使ったもので、よく『仮想マシン』と比較されます。

なので、まずは・・・

『仮想マシン』と『コンテナ』の違い

について簡単に見ていきましょう。

『仮想マシン』と『コンテナ』について

virtual_machine_and_container.png

『仮想マシン』は・・・

ホストOS上で『VirtualBox』や『VMware』などのハイパーバイザー(仮想化ソフトウェア)を利用して仮想マシンを作成し、その仮想マシンのゲストOS上でアプリやミドルウェアを動かします。

そのため・・・

起動に時間がかかるというデメリットがあります。
(もちろん、完璧に環境を分離できるというメリットもありますが…)

それに対し、『Docker』は・・・

ホストOSのみの使用でプロセスやユーザなどを隔離することで、ホストOS上にあたかも別のマシンが動いているかのような環境を作ります。

そのため・・・

軽量で、且つ高速に起動・停止することが可能になります。

『Docker』を利用するメリット【5つ紹介】

point-1.jpg

『Docker』では、開発環境の構築(ミドルウェアのインストールや各種環境設定)をコード化して管理します。

そのため・・・

『Docker』を利用することで、以下のようなメリットがあります。

  • コード化して管理することで、
    誰でも、どこでも同じ開発環境が構築できる
  • 構築した開発環境を簡単に配布できる

例えば・・・

"開発環境(Windows上)では正常に動作したけど、Linuxでは動作しなかった"

なんて経験がある方もいるかと思いますが…

このケースの場合、開発工程から『Docker』を利用することで防ぐことができます。

さらには・・・

『開発工程の中で使っていた環境をそのまま本番環境に持っていく』

なんてことも可能なので、差分の発生がなくなり、環境差分によるトラブルも防ぐことができます。

また・・・

作成したDocker イメージは他の開発メンバーにも渡せるので、それを使ってもらうことで…

  • メンバー間での開発環境のバージョンずれ防止
  • 準備時間(開発環境を準備する時間)の短縮

にもつながります。

実際・・・

"資料の不備や手順ミスが原因で、開発環境の準備に丸一日かかってしまった"

なんて経験がある方も多いんではないでしょうか…苦笑

そんなところで、メリットをまとめると下記の5つのようなモノが挙げられます。

  1. 起動が速い
  2. コード化して管理することで、
     誰でも、どこでも同じ開発環境が構築できる
  3. 構築した開発環境を簡単に配布できる
  4. メンバー間での開発環境のバージョンずれ防止
  5. 準備時間(開発環境を準備する時間)を短縮できる

※あくまで一部なので、他にもたくさんあると思います

『Docker』のアーキテクチャ(構成)

school-1.jpg

『Docker』のシステム構成に関してのお話で、要は…

『コンテナをどうやって動かすか』

ってことについてです。

具体的には、『Docker』は下記の4つで構成され、サービスを提供しています。

  1. Docker デーモン
  2. Docker クライアント
  3. Docker イメージ
  4. Docker コンテナ

それでは、ひとつずつ見ていきましょう。

①:Docker デーモン

docker_daemon.png

Docker デーモンは・・・

コンテナの管理・実行を行います。

Docker デーモンはイメージからコンテナを作成したり、実行したりするだけの存在なので・・・

実際は、Docker デーモンに対して指示を出すシステムが必要です。

それが、お次に紹介する『Docker クライアント』です。

②:Docker クライアント

docker_client.png

Docker クライアントは・・・

『Docker』を操作するためのアプリケーションです。

管理者からのコマンドを受け付けたら、その先にあるDocker デーモンへ指示を飛ばし、それによってコンテナが動いたり止まったりする訳です。

③:Docker イメージ

docker_image.png

Docker イメージは・・・

コンテナの元になるひな形で、Docker レジストリに保管されます。

Docker レジストリとしては、Docker Hubと呼ばれるオンラインサービスが提供されており、そこではイメージの共有やダウンロードが可能です。

④:Docker コンテナ

docker_container.png

Docker コンテナは・・・

Docker イメージを元にして実行されたプロセスです。

各コンテナは分離されているので、独立したホストの同じように扱うことが可能です。

まとめ・感想

surfing-1.jpg

『Docker』に関しても『業務のなかでもやってみたい!』と思ってますが、なかなかチャンスがなさそう…。
(待っててもチャンス来ないので、行動するしかないですね笑)

今後は…

『Dockernのセットアップやコンテナの起動方法』

についてもまとめる予定です。

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

Rails Tutorialの知識から【ポートフォリオ】を作って勉強する話 #19 Docker編

こんな人におすすめ

  • プログラミング初心者でポートフォリオの作り方が分からない
  • Rails Tutorialをやってみたが理解することが難しい

前回:#18 EC2環境構築, Nginx+Puma+Capistrano編
番外:#18.5 環境変数, Gmail送信設定編
次回:準備中

今回の流れ

  1. 完成のイメージを理解する
  2. Dockerを導入する理由を知る
  3. RailsアプリをGitHubからクローンする
  4. ローカルの開発環境を整える
  5. Dockerをインストールする
  6. Dockerの仕組みを理解する
  7. Dockerのファイルを作成する
  8. Dockerを起動する
  9. トラブルシューティング

この記事は、動画を観た時間を記録するアプリのポートフォリオです。
今回は、Railsアプリの開発環境にDockerを組み込みます。
ローカル(ホスト)にはMacを使います。

完成のイメージを理解する

はじめにDockerの必要性を知ります。
ローカル(Mac)にRailsアプリがない、動く環境にない方は先に環境を整えます。

次にDockerを構成します。
具体的には、プロセスをapp(RailsやPumaなど)db(MySQL)nginx(Nginx)の3つに分け、Docker Composeで定義します。
ここでDockerを構成しながら、Dockerの理解を深めます。

最後にDockerを起動します。
起動がスムーズに行くことは稀で、何らかのエラーが発生します。
トラブルシューティングを活用しながら、起動を成功させます。

以上です。

Dockerを導入する理由を知る

Dockerは、軽くてポータビリティのある開発環境ツールです。
Dockerは、モダンな企業のほとんどが使うツールです。
Dockerを、ポートフォリオに組み込むことで、転職先の企業とのマッチング率を高めるという狙いがあります。

さてDockerの動作については、こちらの記事が分かりやすいので、一読します。
いまさらだけどDockerに入門したので分かりやすくまとめてみた

RailsアプリをGitHubからクローンする

RailsアプリをローカルであるMacにクローンします。
※ すでにローカルでRailsアプリを開発している方は飛ばしてください。

local(自分のMacターミナル)
$ vi ~/.gitconfig
.gitconfig
[user]
  name = Gitに登録している名前
  email = Gitに登録しているメールアドレス

[url "github:"]
  InsteadOf = https://github.com/
  InsteadOf = git@github.com:
local
$ cd ~/.ssh
$ ssh-keygen -t rsa
Enter file in which to save the key ():git_rsa
Enter passphrase (empty for no passphrase): 
# 何もせずエンター
Enter same passphrase again: 
# 何もせずエンター
$ vi config
.ssh/config
# 以下を追加
Host github
  Hostname github.com
  User git
  IdentityFile ~/.ssh/git_rsa
local
$ cat git_rsa.pub
# 中身をコピー

GitHubにログイン
右上アイコン『Settings』 → 『SSH and GPG keys』 → 『New SSH key』

Title:任意
Key:コピーした公開鍵をペースト
local
$ cd ~
$ git clone -b ブランチ名 git@
github.com:GitHubのユーザー名/アプリ名.git

以上でRailsアプリのクローンは完了です。

参考になりました↓
リモートから特定のブランチを指定してcloneする

ローカルの開発環境を整える

ローカル(Mac)の開発環境を整えます。
ここでの手順は以下の通りです。
※ すでにローカルでRailsアプリを開発している方は飛ばしてください。

  • Homebrewをインストールする
  • Rubyをインストールする
  • Bundlerをインストールする
  • MySQLをインストールする

Homebrewをインストールする

Homebrew(公式)をインストールします。
HomebrewはMacでよく利用されるパッケージ管理です。

local(Mac)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Rubyをインストールする

Rubyをインストールします。
RubyはMacに標準で入っていますが、バージョン管理のためにrbenvを使います。

local(Mac)
$ brew install rbenv ruby-build
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source .bash_profile
$ rbenv install 使いたいバージョン
$ rbenv global 使いたいバージョン
$ rbenv rehash

Bundlerをインストールする

Bundlerをインストールします。

$ gem install bundler

MySQLをインストールする

MySQLをインストールします。

$ brew install mysql

参考になりました↓
Ruby初学者のRuby On Rails 環境構築【Mac】

Dockerをインストールする

Docker Desktop for Macからアカウントを作成し、インストールします。
手順は以下の通りです。

  1. 『Get Started』からDcokerHubアカウントを作成する
  2. 『Get Docker』からDockerをインストールする

参考になりました↓
DockerをMacにインストールする

Dockerの仕組みを理解する

それではDockerを使って、環境を構築します。
仕組みとしては、app(RailsとPuma)db(MySQL)nginx(Nginx)のイメージをDockerfileなどで用意し、Docker Composeでプロセスを起動させます。

早速、以下のようにホスト側のディレクトリを構成します。
Dockerの各ファイル、用語は後述します。

lantern_app
├── config
│   ├── database.yml(既存)
│   └── puma.rb(既存)
├── containers
│   └── nginx
│       ├── Dockerfile
│       └── nginx.conf
├── docker-compose.yml
├── Dockerfile
├── environments
│   └── db.env
├── Gemfile(既存)
├── Gemfile.lock(既存)
└── 他

用語を説明します。

Image
色々な環境を提供してくれる入れ物のことです。
イメージからRubyやNginxなどを取得します。

Dockerfile
イメージを作るためのファイルです。
イメージを元に機能を拡張するなどの用途があります。

Volume
データ永続のための保存場所です。
Dockerのデータはコンテナの終了とともに消えるため、必要に応じて設定します。

Container
イメージを元に作られたプロセスのことです。
イメージを起動すると、環境がプロセスとしてコンテナに隔離されます。

Docker Compose
複数のコンテナを定義・実行するツールです。

Dockerのファイルを作成する

それではDockerのディレクトリとファイルを作成します。

local(Mac)
$ touch Dockerfile docker-compose.yml
$ mkdir containers containers/nginx environments
$ cd containers/nginx
$ touch Dockerfile nginx.conf
$ cd ../..
$ touch environments/db.env

各ファイルを編集します。
各ファイルの詳細は、後述します。

Dockerfile
# 元にするイメージ
FROM ruby:2.6.3
# コンテナを機能させるまでの準備のコマンドを実行する
RUN apt update -qq && \
    apt install -y build-essential nodejs
RUN mkdir /lantern_docker
# 環境変数を設定する
ENV APP_ROOT /lantern_docker
# コマンドを実行するディレクトリを設定する
WORKDIR $APP_ROOT
# ホストのファイルをコンテナにコピーする
ADD Gemfile $APP_ROOT/Gemfile
ADD Gemfile.lock $APP_ROOT/Gemfile.lock
# 既出
RUN gem install bundler
RUN bundle install
ADD . $APP_ROOT
RUN mkdir -p tmp/sockets
# コンテナ起動時のポートを設定する
EXPOSE 3000

RailsアプリはRubyイメージを元にして作成します。
RUN apt ...でRailsが動く環境をインストールし、ADD . $APP_ROOTでGemfileなどをコンテナにコピーし、RailsやPumaなどを動作させます。

docker-compose.yml
# Docker Composeのバージョン
version: '3'

# Docker Composeではコンテナをサービスとして扱う
services:
  # サービス名をappとして定義
  app:
    # 参照するDockerfileを指定(docker-compose.ymlから基準)
    build: .
    # 環境変数が設定されているファイルを指定
    env_file:
      - ./environments/db.env
    # ボリュームをマウント(後述)
    volumes:
      - .:/lantern_docker
    # サービス名dbが作成されたらappを作成
    depends_on:
      - db
    # コンテナを起動させ続ける際に使用
    tty: true
    # コマンドを実行
    command: bundle exec puma -C config/puma.rb

  db:
    # イメージを指定(後述)
    image: mysql
    env_file:
      - ./environments/db.env
    # ボリュームをマウント(後述)
    volumes:
      - db-data:/var/lib/mysql

  nginx:
    build: containers/nginx
    # ホスト:コンテナのポートを指定
    ports:
      - "80:80"
    depends_on:
      - app

# ボリュームとして扱うボリューム名
volumes:
  db-data:

Docker Composeの各サービスは、DockerfileまたはDockerHubのイメージを参照します。
ここでは、appとnginxがDockerfile、dbがイメージを参照しています。

appのボリュームは、ホスト側のホームディレクトリ全てをボリューム化しています。
dbのボリュームは、コンテナ側のディレクトリ/var/lib/mysqlをdb-dataというボリューム名でボリュームをマウントしています。

この辺りはややこしく、参考記事を読むことをおすすめします。

参考になりました↓
Docker、ボリューム(Volume)について真面目に調べた
Dockerの-vや--volumeオプションはわかりづらいから、--mountを使おう
バインドマウント | Docker docs(日本語)
Pumaの起動におけるpumaコマンドとpumactlコマンドの違い

containers/nginx/Dockerfile
FROM nginx
RUN rm -f /etc/nginx/conf.d/*
ADD nginx.conf /etc/nginx/conf.d/lantern_docker.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

Nginxはフォアグラウンドでの動作を期待しているので、'deamon off;'とします。
フォアグラウンドとバックグラウンドの違いは、PCで表すとこんな感じです。

  • フォアグラウンド:一番上のウインドウ
  • バックグラウンド:それ以外のウインドウ

参考になりました↓
フォアグラウンド(foreground)とは | 「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

containers/nginx/nginx.conf
# Pumaとやり取りするための通信路
upstream lantern_docker {
  server unix:///lantern_docker/tmp/sockets/puma.sock;
}
# サーバーに関する情報
server {
  # ポート
  listen 80;
  # 処理するサーバー名
  server_name localhost;
  # ログに関するファイルの場所
  access_log /var/log/nginx/access_log;
  error_log /var/log/nginx/error_log;
  # ドキュメントルートの設定
  root /lantern_docker/public;
  try_files $uri/index.html $uri @app;

  # 内部リダイレクトの処理
  location @app {
    # バックエンドサーバーに送信するヘッダーを定義し直す
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    # プロキシのパス(Pumaに渡す)
    proxy_pass http://lantern_docker;
    proxy_redirect off;
  }
}

アプリ名を自分のものに変更します。
Nginxの設定は#18で説明済みなので、省略します。

environments/db.env
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント

環境変数の設定です。
エンドポイントが分からない場合、#17.5をご覧ください。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  timeout: 5000
  reconnect: false
  pool: 5
  socket: /var/lib/mysql/mysql.sock
  username: <%= Rails.application.credentials.mysql[:user_name] %>
  password: <%= Rails.application.credentials.mysql[:password] %>
  host: <%= Rails.application.credentials.mysql[:host] %>

development:
  <<: *default
  database: lantern_development

test:
  <<: *default
  database: lantern_test

production:
  <<: *default
  database: lantern_production

MySQLの設定です。
credentailsが未設定の場合は、#18.5をご覧ください。

config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  ActiveRecord::Base.establish_connection
end

plugin :tmp_restart

app_dir = File.expand_path("../..", __FILE__)
bind "unix://#{app_dir}/tmp/sockets/puma.sock"
pidfile "#{app_dir}/tmp/pids/puma.pid"
stdout_redirect "#{app_dir}/log/puma.stdout.log", "#{app_dir}/log/puma.stderr.log", true

Pumaの設定です。
ここも#18で説明済みなので、省略します。

以上で、Dockerのファイル編集は完了です。

Dockerを起動する

Docker Composeを使ってDockerコンテナを起動します。

local(Mac)
# Dockerfileからイメージをビルド
$ docker-compose build
# Docker Composeのコンテナを起動(-dでバックグラウンド起動)
$ docker-compose up -d
# Docker Composeのコンテナのプロセスを確認
$ docker-compose ps

以上でDockerの組み込みは完了です。
後は各コンテナに入り、開発を進めてください。

shell
# appのbashに入る
$ docker-compose exec app bash
# 例
$ rails db:migrate

参考になりました↓
Docker + Rails + Puma + Nginx + MySQL
丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
既存のRailsアプリにDockerを導入する手順
Nginx + Rails (Puma) on Docker のいくつかの実用パターン
Docker + Rails + Puma + Nginx + Postgres
Docker ComposeでNginx Rails MySQL環境を構築してみる

トラブルシューティング

Dockerで起動する際、様々なエラーが発生します。
一例ですが、私が見舞ったトラブルの解決策を書き残します。

よく使うスクリプトを確認する

先によく使うスクリプトを紹介します。
まずはDockerやDocker Composeのコマンドを紹介します。

shell
# ログの確認
$ docker-compose logs
# サービスの確認
$ docker-compose ps -a
# コンテナの確認
$ docker ps -a
# コンテナとネットワークの停止と削除
$ docker-compose down --rmi all
# コンテナの削除
$ docker rm ID名
# イメージの削除
$ docker rmi ID名
# コンテナのbash内に入る
$ docker-compose exec サービス名 bash

続いてbashを紹介します。

bash
# ディレクトリの有無を確認する(出力0=有、出力1=無)
$ test -f パス;echo $?
# プロセスが使用しているポートを確認する
$ lsof -i
# ポートを指定してプロセスを確認する
$ lsof -i:ポート番号

以上です。
以降から、具体的なトラブルシューティングに入ります。

参考になりました↓
Docker実践〜dockerのコンテナ環境をきれいに消す
docker-compose up したコンテナを起動させ続ける方法
Linux/UNIXでファイル・ディレクトリの存在確認をする
Linuxでプロセスが何のポート使っているかを調べる

/usr/local/lib/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': Could not find 'bundler' (2.1.4) (Gem::GemNotFoundException)

Bundlerが見当たらないのでエラーが発生します。
GemからBundlerをインストールします。

Dockerfile
# 以下を追加
RUN gem install bundler

参考になりました↓
Docker + Rails のdocker-compose build でGemNotFoundExceptionの時の対処

mysql client is missing.

MacにMySQLがないためにエラーが発生します。
HomebrewでMySQLをインストールします。

local(Mac)
$ brew install mysql

参考になりました↓
mysql2 が原因でbundle installにてエラーを吐く(Mac OS X)

uses an image, skipping

こちらはエラーではありません。
すでにビルドが済んだイメージをリモートで取得するので、upすれば問題ありません。

local(Mac)
$ docker-compose up -d

参考になりました↓
docker-compose.yml起動時にuses an image, skippingされる現象
docker-compose `up` とか `build` とか `start` とかの違いを理解できていなかったのでまとめてみた。

error: database is uninitialized and password option is not specified

データベースのエラーです。
データベースが初期化されていない、パスワードがないため発生します。
環境変数のあたりを確認します。

environments/db.env
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント
docker-compose.yml
# 中略
  db:
    image: mysql
    env_file:
      - ./environments/db.env
# 中略

参考になりました↓
docker, docker-composeでmysqlが起動しない
docker-compose.ymlで.envファイルに定義した環境変数を使う
How to link MySQL RDS in docker-compose.yml file?

NoMethodError: Cannot load database configuration:

データベースのエラーです。
データベースに関する設定に問題があります。

解決策1:ttyをtrueにする

ttyをtrueにすると解決するかもしれません。

docker-compose.yml
app:
# 中略
    tty: true
# 中略

参考になりました↓
docker-compose up したコンテナを起動させ続ける方法
docker-composで起動したコンテナがすぐに停止する

解決策2:database.ymlのERbを削除する

コメントアウトしていてもERbは評価されます(恐らく)。
database.yml内のERbは削除します。

config/database.yml
# 以下で書かれた必要ない箇所を削除する
<%= %>

参考になりました↓
Rails を起動したら Cannot load `Rails.application.database_configuration`: (NoMethodError) が出てハマった

502 Bad Gateway

何らかのサーバーに関するエラーです。
私の場合は、以下のように変更すると解決しました。

nginx.conf
upstream lantern_docker {
  # ソケットからサービス名に変更
  # server unix:///lantern_docker/tmp/sockets/puma.sock;
  server app:3000;
}
# 中略

参考になりました↓
Docker Compose と nginx でリバースプロキシを作ろうとしたお話(出題編)


前回:#18 EC2環境構築, Nginx+Puma+Capistrano編
番外:#18.5 環境変数, Gmail送信設定編
次回:準備中

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

(ドラフト/メモ)Dockerコンテナベースで動作するメールサーバ

1.Mailu
https://github.com/Mailu/Mailu

・Mailuで簡単にWebUI付きのメールサーバを立てる
https://qiita.com/kter/items/7cad987794b6610e4983

2.mailcow
https://mailcow.email/

3.tomav/docker-mailserver
https://github.com/tomav/docker-mailserver

    Postfix with smtp or ldap auth
    Dovecot for sasl, imap (and optional pop3) with ssl support, with ldap auth
        Dovecot is installed from the Dovecot Community Repo
    saslauthd with ldap auth
    Amavis
    Spamassasin supporting custom rules
    ClamAV with automatic updates
    OpenDKIM
    OpenDMARC
    Fail2ban
    Fetchmail
    Postscreen
    Postgrey
    basic Sieve support using dovecot
    LetsEncrypt and self-signed certificates
    Setup script to easily configure and maintain your mailserver
    persistent data and state (but think about backups!)
    Integration tests
    Automated builds on docker hub
    Plus addressing (a.k.a. extension delimiters) works out of the box: email for you+extension@example.com go to you@example.com

Why I created this image: Simple mail server with Docker

Before you open an issue, please have a look this README, the Wiki and Postfix/Dovecot documentation.
Requirements

Recommended:

    1 CPU
    1-2GB RAM
    Swap enabled for the container

Minimum:

    1 CPU
    512MB RAM

Note: You'll need to deactivate some services like ClamAV to be able to run on a host with 512MB of RAM. Even with 1G RAM you may run into problems without swap, see FAQ.

・Dockerでメールサーバーを建てたときのメモ
https://blog.netaka.net/mailserver_on_docker/

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