20200112のdockerに関する記事は18件です。

Ruby on Rails APIモードのCRUD実装 【初学者のReact✗Railsアプリ開発 第5回】

やったこと

  • Ruby on RailsのAPIモードでCRUDを実装する(ただし、更新(U)はなし)

前回の記事

Reactのreduxを用いたログイン処理周りの実装【初学者のReact✗Railsアプリ開発第4回】

参考にさせていただいた記事

https://qiita.com/k-penguin-sato/items/adba7a1a1ecc3582a9c9

実装手順

モデルとコントローラーの作成

$ docker-compose run api rails g model post content:string
$ docker-compose run api rails g controller api/v1/posts

生成されたマイグレーションファイルを編集します。

db/migrate/XXX_create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.string :content
      t.references :user, foreign_key: true

      t.timestamps
    end
    add_index :posts, [:user_id, :created_at]
  end
end
$ docker-compose run api rake db:migrate 

route.rb

route.rb
Rails.application.routes.draw do
 namespace :api, defaults: { format: :json } do
    namespace :v1 do
      ##省略##
      resources :posts
    end
 end
end

  • resourcesで、GET, POSTなど複数のルーティングを一気に設定できる。resourceとの違いに注意。

posts_controller

posts_controller
module Api
  module V1
    class PostsController < ApplicationController
      before_action :set_post, only: [:index, :show, :update, :destroy]
      before_action :authenticate_api_v1_user!

      def index
        posts = Post.all
        render json: { status: 'SUCCESS', message: 'Loaded posts', data: posts}
      end

      def show
        @user = @post.user
        json_data = {
          'post': @post,
          'user': {
            'name': @user.name,
            'nickname': @user.nickname,
            'image': @user.image
          }
        }
        render json: { status: 'SUCCESS', message: 'Loaded the post', data: json_data}
      end

      def create
        post = Post.new(post_params)
        if post.save
          render json: { status: 'SUCCESS', data: post}
        else
          render json: { status: 'ERROR', data: post.errors }
        end
      end

      def destroy
        @post.destroy
        render json: { status: 'SUCCESS', message: 'Delete the post', data: @post}
      end

      def update
      end

      private

      def set_post
        @post = Post.find(params[:id])
      end

      def post_params
        params.require(:post).permit(:content, :user_id)
      end

    end
  end
end  

models/post.rb

post.rb
class Post < ApplicationRecord
  belongs_to :user
end

Postmanを用いてAPIの動作確認をする

create

chromeのデベロッパーツール->Application->Local Storageからauth_tokenとかをコピーして、
スクリーンショット 2020-01-12 21.43.04.png
Postmanに貼り付ける。
スクリーンショット 2020-01-12 21.42.44.png
そしてlocalhost:3000/api/v1/postsにPOSTすると
スクリーンショット 2020-01-12 21.41.24.png
postが作成されたことが確認できます。

index

localhost:3000/api/v1/postsにGETすると
スクリーンショット 2020-01-12 21.45.34.png

show

localhost:3000/api/v1/posts/1にGETすると、idが1のpostが返されます。
スクリーンショット 2020-01-12 21.45.52.png

destroy

localhost:3000/api/v1/posts/1にDELETEすると、idが1のpostが消えます。
スクリーンショット 2020-01-12 21.46.06.png
indexで確認すると、消えています。
スクリーンショット 2020-01-12 21.46.17.png

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

Dockerで開発環境を構築する

はじめに

前回の記事でDockerってどんなものなんだろうってことを軽く調べて書かせて頂きました。
今回は実際にDockerを使用して開発環境を構築してみよう!って内容を書きたいと思います。
まずは操作に慣れたいのでイメージを取得してコンテナを作成して起動までをやってみたいと思います。

主なコマンド

  • docker pull リポジトリ:タグ (イメージの取得)
  • docker run イメージ名 (コンテナの生成から起動)
  • docker start コンテナID(もしくはコンテナ名)
  • docker stop コンテナID(もしくはコンテナ名)
  • docker rm コンテナID(もしくはコンテナ名)
  • docker ps (起動中のコンテナ表示)
  • docker ps -a (状態に関係なくすべてのコンテナを表示)
  • docker ps -aq (コンテナIDのみ表示)
  • docker commit コンテナID(もしくはコンテナ名) イメージ名:タグ (コンテナからイメージ作成)

イメージの取得

まずcentosのイメージを取得します。

centos7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:centos7
docker.io/library/centos:centos7

イメージ一覧を表示して確認。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              centos7             5e35e350aded        2 months ago        203MB

これでイメージの取得は完了です。めっちゃ簡単!!

イメージからコンテナを作成、起動

$ docker run -it -d --name centos7 centos:centos7
Unable to find image 'centos:centos7' locally
centos7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:centos7
9ac1b47222b99cb76f33837836e30859d7a0420fdccb694d0deb795a5da7b7b7

起動できているか確認

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
9ac1b47222b9        centos:centos7      "/bin/bash"         2 minutes ago       Up 2 minutes                            centos7

STATUSの欄を見るとUp 2となっているので起動できているかと思います。

実際にコンテナを操作してみる

$ docker exec -it centos7 /bin/bash
[root@9ac1b47222b9 /]#

これでコンテナ内に入れたのでコマンド操作が可能になります。
コンテナから抜けるにはexitで抜けれました。

コンテナの停止

docker stop コンテナID(またはコンテナ名)
上記でコンテナを停止できます。

$ docker stop centos7
centos7

停止しているか確認

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

プロセスが表示されていないので正しく停止してそうです。

意外と直感的に操作できた

linux環境を触ったことある人なら意外と簡単に操作できるなって感じました。
これからは自分でイメージを作成したりdockerfileについても勉強して記事にしていきたいと思います。

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

Dockerを触ってみる

はじめに

前回の記事でDockerってどんなものなんだろうってことを軽く調べて書かせて頂きました。
今回は実際にDockerを使用して開発環境を構築してみよう!って内容を書きたいと思います。
まずは操作に慣れたいのでイメージを取得してコンテナを作成して起動までをやってみたいと思います。

主なコマンド

  • docker pull リポジトリ:タグ (イメージの取得)
  • docker run イメージ名 (コンテナの生成から起動)
  • docker start コンテナID(もしくはコンテナ名)
  • docker stop コンテナID(もしくはコンテナ名)
  • docker rm コンテナID(もしくはコンテナ名)
  • docker ps (起動中のコンテナ表示)
  • docker ps -a (状態に関係なくすべてのコンテナを表示)
  • docker ps -aq (コンテナIDのみ表示)
  • docker commit コンテナID(もしくはコンテナ名) イメージ名:タグ (コンテナからイメージ作成)

イメージの取得

まずcentosのイメージを取得します。

centos7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:centos7
docker.io/library/centos:centos7

イメージ一覧を表示して確認。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              centos7             5e35e350aded        2 months ago        203MB

これでイメージの取得は完了です。めっちゃ簡単!!

イメージからコンテナを作成、起動

$ docker run -it -d --name centos7 centos:centos7
Unable to find image 'centos:centos7' locally
centos7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:centos7
9ac1b47222b99cb76f33837836e30859d7a0420fdccb694d0deb795a5da7b7b7

起動できているか確認

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
9ac1b47222b9        centos:centos7      "/bin/bash"         2 minutes ago       Up 2 minutes                            centos7

STATUSの欄を見るとUp 2となっているので起動できているかと思います。

実際にコンテナを操作してみる

$ docker exec -it centos7 /bin/bash
[root@9ac1b47222b9 /]#

これでコンテナ内に入れたのでコマンド操作が可能になります。
コンテナから抜けるにはexitで抜けれました。

コンテナの停止

docker stop コンテナID(またはコンテナ名)
上記でコンテナを停止できます。

$ docker stop centos7
centos7

停止しているか確認

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

プロセスが表示されていないので正しく停止してそうです。

意外と直感的に操作できた

linux環境を触ったことある人なら意外と簡単に操作できるなって感じました。
これからは自分でイメージを作成したりdockerfileについても勉強して記事にしていきたいと思います。

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

Docker で pygments 環境を用意して minted パッケージを試す

LaTeX でソースコードをいい感じにシンタックスハイライトしてくれる minted パッケージを,Docker を使って試してみたときのメモです。手元の Python 環境に手を加えずに Docker コンテナを利用して minted パッケージを動かすことを目指します。この方法は,minted に限らず,外部ツールを呼び出す系の LaTeX パッケージを,手元の環境を汚さずに試す方法の一例として参考になると思います。

minted パッケージの使用例

minted パッケージの動作要件

  • minted.sty(TeX Live ならば初めからインストールされている)
  • pygments がインストールされた Python 環境
  • minted.sty から pygmentize コマンドを呼び出すために LaTeX エンジンに -shell-escape を与えることが必須

pygments の準備

pygments のインストールは,pip が使える Python 環境であれば

$ pip install pygments

とすればOKです。

ただし,今回はあくまでお試しということで,手元の Python 環境を汚さずに minted パッケージを試したいと思います。そこで pygments を搭載した Docker コンテナを用意します。

pygments 入り Docker コンテナイメージのビルド

Alpine Linux + Python のベースイメージに対し,pygments を追加インストールして,自動で pygmentize コマンドが起動するように設定した Docker コンテナです。

Dockerfile
FROM python:alpine
WORKDIR /workdir
RUN pip install pygments
ENTRYPOINT ["pygmentize"]

この Dockerfile をビルドし,ここでは仮に pygmentize-wrapper という名前のイメージとして保存します。

$ docker build -t pygmentize-wrapper .

pygmentize コマンドのラッパースクリプトの準備

次に,テスト用ディレクトリ(たとえば /tmp/minted-test )に次のスクリプトを用意し,pygmentize という名前で保存して,実行権限を与えて(chmod +x)おきます。

pygmentize
#!/bin/sh
docker run --rm \
  --mount type=bind,src="$(pwd)",dst=/workdir \
  pygmentize-wrapper "$@"

発想としては,minted.sty から \ShellEscape で呼び出される pygmentize コマンドを,本物の pygmentize コマンドではなく,Docker コンテナ内の pygmentize を呼び出すこのラッパースクリプトに差し替えて偽装しようというわけです。

サンプル文書の用意

次のようなサンプル文書を用意します。minted パッケージが提供する minted 環境のみならず,tcolorbox パッケージが提供する tcblisting 環境のシンタックスハイライトエンジンを minted に設定したものも試します。(このサンプル文書は upLaTeX 文書となっていますが,そこは特に深い意味はありません。pLaTeX や pdfLaTeX 等でもOKです。)

sample.tex
%#!uplatex
\documentclass[uplatex,dvipdfmx,papersize]{jsarticle}
\usepackage{graphicx,xcolor}
\usepackage[cache=false]{minted}
\usepackage{tcolorbox}
\tcbuselibrary{minted}
\tcbset{listing engine=minted}
\pagestyle{empty}

\begin{document}

\begin{minted}{c}
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Hello, world!\n");
    return 0;
}
\end{minted}

\begin{tcblisting}{colback=red!5!white,colframe=red!75!black,left=1cm,minted options={fontsize=\small,linenos,firstnumber=1100,numbersep=3mm}}
This is a \LaTeX\ example which displays the text as source code
and in compiled form.
\end{tcblisting}

\begin{tcblisting}{listing only,title=another language listing only example,fonttitle=\bfseries,colback=red!5!white,colframe=red!75!black,minted language=xml}
   <?xml version="1.0"?>
   <project name="Package tcolorbox" default="documentation" basedir=".">
     <description>
       Sample
     </description>
   </project>
\end{tcblisting}

\end{document}

サンプル文書のコンパイル

コンパイル実行の仕方

現状,次のようなファイル構成になっています。

/tmp/minted-test (実験用ディレクトリ)
        ├── pygmentize (ラッパースクリプト)
        └── sample.tex (サンプル文書)

LaTeX コンパイルのコマンド実行に前置して,PATH=.:$PATH を加えておきます。これにより,PATH の設定に一時的にカレントディレクトリが加わります。こうすることで,minted.sty から \ShellEscape で呼び出される pygmentize コマンドを,カレントディレクトリのラッパースクリプトに差し替えることができます。

$ PATH=.:$PATH ptex2pdf -u -l -ot -shell-escape sample.tex

-ot で TeX エンジンに対して -shell-escape を渡しています。

コンパイル結果

無事にホスト側の LaTeX エンジンから Docker コンテナ内の pygmentize コマンドが呼び出され,綺麗に色分けされました!

image.png

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

Docker で Pygments 環境を用意して minted パッケージを試す

様々な言語のソースコードをいい感じにシンタックスハイライトして,LaTeX 文書内に貼り込んでくれる minted パッケージを,Docker を使って試してみたときのメモです。手元の Python 環境に手を加えずに Docker コンテナを利用して minted パッケージを動かすことを目指します。この手法は,minted に限らず,別途インストールする必要のある外部ツールを呼び出す系の LaTeX パッケージを,手元の環境を汚さずに試す方法の一例として参考になるのではないでしょうか。

minted パッケージの使用例

minted パッケージの動作要件

  • minted.sty(TeX Live ならば初めからインストールされている)
  • Pygments がインストールされた Python 環境
  • minted.sty から pygmentize コマンドを呼び出すために LaTeX エンジンに -shell-escape を与えることが必須

Pygments の準備

Pygments のインストールは,pip が使える Python 環境であれば

$ pip install pygments

とすればOKです。

ただし,今回はあくまでお試しということで,手元の Python 環境を汚さずに minted パッケージを試したいと思います。Python のvenvvirtualenv を使ってもよいのですが,ここでは,(Python に限らず使える手法という意味で)より一般的で,より環境の分離がしっかりできる,Docker によるコンテナ化の方針でゆくことにします。つまり,Pygments を搭載した Docker コンテナを用意します。

Pygments 入り Docker コンテナイメージのビルド

Alpine Linux + Python のベースイメージに対し,Pygments を追加インストールして,自動で pygmentize コマンドが起動するように設定した Docker コンテナです。

Dockerfile
FROM python:alpine
WORKDIR /workdir
RUN pip install pygments
ENTRYPOINT ["pygmentize"]

この Dockerfile をビルドし,ここでは仮に pygmentize-wrapper という名前のイメージとして保存します。

$ docker build -t pygmentize-wrapper .

pygmentize コマンドのラッパースクリプトの準備

次に,テスト用ディレクトリ(たとえば /tmp/minted-test )に次のスクリプトを用意し,pygmentize という名前で保存して,実行権限を与えて(chmod +x)おきます。

pygmentize
#!/bin/sh
docker run --rm \
  --mount type=bind,src="$(pwd)",dst=/workdir \
  pygmentize-wrapper "$@"

発想としては,minted.sty から \ShellEscape で呼び出される pygmentize コマンドを,本物の pygmentize ではなく,Docker コンテナ内の pygmentize を呼び出すこのラッパースクリプトに差し替えて偽装しようというわけです。

サンプル文書の用意

次のようなサンプル文書を用意します。minted パッケージが提供する minted 環境のみならず,tcolorbox パッケージが提供する tcblisting 環境のシンタックスハイライトエンジンを minted に設定したものも試します。(このサンプル文書は upLaTeX 文書となっていますが,そこは特に深い意味はありません。pLaTeX や pdfLaTeX 等でもOKです。)

sample.tex
%#!uplatex
\documentclass[uplatex,dvipdfmx,papersize]{jsarticle}
\usepackage{graphicx,xcolor}
\usepackage[cache=false]{minted}
\usepackage{tcolorbox}
\tcbuselibrary{minted}
\tcbset{listing engine=minted}
\pagestyle{empty}

\begin{document}

\begin{minted}{c}
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Hello, world!\n");
    return 0;
}
\end{minted}

\begin{tcblisting}
    {colback=red!5!white,
    colframe=red!75!black,
    left=1cm,
    minted options={fontsize=\small,linenos,firstnumber=1100,numbersep=3mm}}
This is a \LaTeX\ example which displays the text as source code
and in compiled form.
\end{tcblisting}

\begin{tcblisting}
    {listing only,
    title=another language listing only example,
    fonttitle=\bfseries,
    colback=red!5!white,
    colframe=red!75!black,
    minted language=xml}
   <?xml version="1.0"?>
   <project name="Package tcolorbox" default="documentation" basedir=".">
     <description>
       Sample
     </description>
   </project>
\end{tcblisting}

\end{document}

サンプル文書のコンパイル

コンパイル実行の仕方

現状,次のようなファイル構成になっています。

/tmp/minted-test (実験用ディレクトリ)
        ├── pygmentize (ラッパースクリプト)
        └── sample.tex (サンプル文書)

LaTeX コンパイルのコマンド実行に前置して,PATH=.:$PATH を加えておきます(sh系シェルの場合,コマンド実行に前置してスペース区切りで環境変数の定義を書くことで,そのコマンド呼び出し時のみ一時的に環境変数の値を変更して実行できます)。これにより,PATH の設定の先頭に一時的にカレントディレクトリが加わった状態で LaTeX エンジンを呼び出せます。その結果,minted.sty から \ShellEscape で呼び出される pygmentize コマンドを,カレントディレクトリのラッパースクリプトに差し替えることができます。

$ PATH=.:$PATH ptex2pdf -u -l -ot -shell-escape sample.tex

-ot オプション(options for TeX の意)で TeX エンジンに対して -shell-escape を渡しています。

コンパイル結果

無事にホスト側の LaTeX エンジンから Docker コンテナ内の pygmentize コマンドが呼び出され,綺麗に色分けされました!

image.png

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

GitHub Package RegistryのDockerイメージは認証無しではPullできない (2020/01/12時点)

ハマる人がいるかもしれないのでMEMOです。

2020/01/12時点ではGitHub PackagesのDockerレジストリ(docker.pkg.github.com)に登録されているDockerイメージはdocker loginによる認証が必須となります。レポジトリがPublicかPrivateに関わらず認証が必須です。

このため例えばGKE等でDocker Hub上のDockerイメージと同じようにPullをしようとするとno basic auth credentialsというエラーが発生してPullに失敗します。

以下はGKE上でエラーが発生した時のPodのエラーメッセージ例です。

  Warning  Failed     58s (x3 over 100s)  kubelet, gke-cluster-xxx  Failed to pull image "docker.pkg.github.com/xxx/xxx/xxx:latest": rpc error: code = Unknown desc = Error response from daemon: Get https://docker.pkg.github.com/v2/xxx/xxx/xxx/manifests/latest: no basic auth credentials
  Warning  Failed     58s (x3 over 100s)  kubelet, gke-cluster-xxx  Error: ErrImagePull

今後の対応予定

ちなみに本件についてはGitHub側は仕様であると回答してますが、認証無しの要望についてはGitHub Package Registryチームに展開したと述べています。このため将来的にはPublicレポジトリについては認証無しでもPullできるようになるかもしれません。

https://github.community/t5/GitHub-Actions/docker-pull-from-public-GitHub-Package-Registry-fail-with-quot/td-p/32782

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

Raspberry PI(Raspbian)開発環境をx86_64マシン上に構築する

はじめに

2019年の年末に、年末だからという理由だけでラズパイ(Raspberry PI Zero W)を購入しました。で、冬休みにいろいろ触ってみたのですが、やっぱり動作が重たいんですよねぇ。さらに、SDカードも32GBでそれほど余裕もなく。なので、ラズパイ上に開発環境を構築してアプリを開発しようという夢は諦めて、x86_64マシンに開発環境を構築して、アプリ開発を行うことにしました。
本記事は、開発環境をx86_64マシン上に構築するための手順やその時ハマった内容などを、備忘録として記載したものです。

開発環境概要

開発環境構築作業は、以下のホスト上で行いました。

  • ホスト:Ubuntu 18.04LTS

また、開発環境はDockerを使ってコンテナ上に構築しています。コンテナを利用することで、ホストの環境を汚すことなく開発環境構築が行えます。

  • Docker Version:19.03.5

ラズパイ用OSは、Raspbian Liteを使用しました。

  • Raspbian Buster Lite(Minimal image based on Debian Buster)
    • Version:September 2019
    • Release date:2019-09-26
    • Kernel version:4.19

つまり、Raspbian(buster)コンテナイメージを作成し、そのイメージを使って開発環境を構築するということです。
但し、RaspbianはARM系アーキテクチャマシンで動作するバイナリですので、単純にDockerで立ち上げても動作しませんので、QEMUエミュレータを使用して動作させることになります。

構築手順

実際の手順については、こちらの記事がわかりやすいので、そちらを参照してください。手順概要は以下です。
1. Dockerでベースコンテナの準備
 開発環境構築作業用コンテナを立ち上げます。
2. Raspbian Buster Liteのイメージファイルのマウント
 立ち上げたコンテナ内で、Raspbian Buster Liteイメージファイルをマウントします。
3. Raspbian Buster Liteのファイル群の取得(tarで固める)
 イメージをマウントすることで、OSファイルが参照出来ますので、tarで固めて取得します。
 また、QEMUを利用してARM系の実行ファイルをx86_64で動作させるため、qemu-arm-staticツールを格納しておきます。
4. 取得したファイル群で、コンテナイメージを作成
 作成したtarファイルを利用して、コンテナイメージを作成します。 
5. 作成したコンテナイメージで、コンテナを作成・起動
 作成したコンテナイメージでコンテナを立ち上げます。これで、RaspbianOSのコンテナが立ち上がります。

上記で、コンテナは問題なく立ち上がり、ラズパイ用アプリの開発は行えるのですが、ホストPCを再起動した後にコンテナを立ち上げようとすると、以下のようになって、コンテナが立ち上がらなくなります。

container
$ docker start -i 8d1086983af8
standard_init_linux.go:211: exec user process caused "exec format error"

いろいろ調べたら、x86_64環境で他のアーキテクチャのバイナリ(コンテナ)を実行する方法について紹介されていた資料を見つけました。

その中で、x86_64環境で他のアーキテクチャのバイナリ(コンテナ)を実行する場合は、事前に以下のコマンドを実行する必要があるとのこと。

host
docker run --rm --privileged multiarch/qemu-user-static --reset

これで異なるアーキテクチャのバイナリ(コンテナ)を実行することが出来ます。

host
$ docker run --rm --privileged multiarch/qemu-user-static --reset
Unable to find image 'multiarch/qemu-user-static:latest' locally
latest: Pulling from multiarch/qemu-user-static
bdbbaa22dec6: Pull complete 
42399a41a764: Pull complete 
ed8a5179ae11: Pull complete 
1ec39da9c97d: Pull complete 
df7dd9470aac: Pull complete 
Digest: sha256:25d6e8bb037094525cd70da43edc06a62122028cb9ad434605affbd4fffb3a4f
Status: Downloaded newer image for multiarch/qemu-user-static:latest
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb
Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc
Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus
Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64
Setting /usr/bin/qemu-ppc-static as binfmt interpreter for ppc
Setting /usr/bin/qemu-ppc64-static as binfmt interpreter for ppc64
Setting /usr/bin/qemu-ppc64le-static as binfmt interpreter for ppc64le
Setting /usr/bin/qemu-m68k-static as binfmt interpreter for m68k
Setting /usr/bin/qemu-mips-static as binfmt interpreter for mips
Setting /usr/bin/qemu-mipsel-static as binfmt interpreter for mipsel
Setting /usr/bin/qemu-mipsn32-static as binfmt interpreter for mipsn32
Setting /usr/bin/qemu-mipsn32el-static as binfmt interpreter for mipsn32el
Setting /usr/bin/qemu-mips64-static as binfmt interpreter for mips64
Setting /usr/bin/qemu-mips64el-static as binfmt interpreter for mips64el
Setting /usr/bin/qemu-sh4-static as binfmt interpreter for sh4
Setting /usr/bin/qemu-sh4eb-static as binfmt interpreter for sh4eb
Setting /usr/bin/qemu-s390x-static as binfmt interpreter for s390x
Setting /usr/bin/qemu-aarch64-static as binfmt interpreter for aarch64
Setting /usr/bin/qemu-aarch64_be-static as binfmt interpreter for aarch64_be
Setting /usr/bin/qemu-hppa-static as binfmt interpreter for hppa
Setting /usr/bin/qemu-riscv32-static as binfmt interpreter for riscv32
Setting /usr/bin/qemu-riscv64-static as binfmt interpreter for riscv64
Setting /usr/bin/qemu-xtensa-static as binfmt interpreter for xtensa
Setting /usr/bin/qemu-xtensaeb-static as binfmt interpreter for xtensaeb
Setting /usr/bin/qemu-microblaze-static as binfmt interpreter for microblaze
Setting /usr/bin/qemu-microblazeel-static as binfmt interpreter for microblazeel
Setting /usr/bin/qemu-or1k-static as binfmt interpreter for or1k
fujita@Inspiron-11-3162:~$ docker start -i 8d1086983af8
root@8d1086983af8:/# 

makeやgccなどはすでにインストール済みなので、C言語での開発ならすぐに始めることができます。

おまけ

マルチアーキテクチャのコンテナイメージがGitHubで公開されています。

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

dockerのscratchイメージ上でgolangのWebアプリを動かす際は、スタティックリンクが必要

Best practices for writing Dockerfiles (参考訳v18.09ベース)を参考に、golangで書いたWebアプリを動かそうとしたらハマったので、その記録を残します。

ざっくりいうと

  1. golangで書いたwebアプリ(サンプル)を、dockerのscratchイメージ上で動かそうとしたら起動で失敗
  2. 調べたらダイナミックリンクでビルドされており、scratchイメージではファイルが足りなかったのが原因
  3. スタティックリンクでビルドし直したら解決した

環境

  • go 1.13.5
  • docker 19.03.5

ハマるまでの流れ

"Use multi-stage builds"にマルチステージビルドを使うgolangのサンプルがあります。ビルドするときに使うイメージとリリースするイメージを分けることで、リリースイメージに余計なもの入れなくてすみ、イメージのサイズも小さくできます。

それはよさそうだと言うことで、手元にあったWebアプリをサンプルにして次のようなDockerfileを用意しました。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

sample-go-serverは、hello worldを返す簡単なものです。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = fmt.Fprintf(w, "hello world")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

このDockerfileをビルドします。

❯ docker build -t sample-go-server .
❯ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
sample-go-server         latest              0acf7d1e1ed7        42 minutes ago      7.45MB

runで起動すると思いきや次のようなエラーで失敗します。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
1e097919ec5ac31839228646e2b14bd0434f56d74787d73b6afa172154829250

❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

❯ docker logs sample
standard_init_linux.go:211: exec user process caused "no such file or directory"

"no such file or directory"と言われましても…。何が足りないかを言ってくれ〜?

解決方法

ググったところ以下が見つかりました。ありがとうインターネッツ。

netパッケージを含む場合はダイナミックリンクでビルドされ、それが原因でno such fileになるらしいです。
なので、さっそくこれに該当しているかを確認してみます。
ビルドで使ったalpineイメージにはfileコマンドが入っていないため、まずそれを入れます。パッケージは Alpine Linux packagesで探せます。

/bin # apk update && apk add file
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
v3.11.2-25-g58afcd742e [http://dl-cdn.alpinelinux.org/alpine/v3.11/main]
v3.11.2-24-g7cfe3a1534 [http://dl-cdn.alpinelinux.org/alpine/v3.11/community]
OK: 11261 distinct packages available
(1/2) Installing libmagic (5.37-r1)
(2/2) Installing file (5.37-r1)
Executing busybox-1.31.1-r8.trigger
OK: 12 MiB in 17 packages
/bin # which file
/usr/bin/file

fileコマンドで確認してみると、たしかにdinamically linkedとなっていました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, Go BuildID=5E6Qy3Li7DELFoSZUyv5/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/wYNglNx2pwV9Z_45IRLn, not stripped

参考サイトにあったCGO_ENABLED=0でビルドをし直してみます。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN CGO_ENABLED=0 go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

たしかにstatically linkedに変わりました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=cD81ASWTt8bngTyIxfpe/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/rmgAW8vnYv0XAugzIkMj, not stripped

docker runでも無事起動できました。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
c27e29aaa697ac7131995472377bb2ff58e6a6ebe6a8174fb8a9de64efc767d5

❯ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c27e29aaa697        sample-go-server    "/bin/sample-go-serv…"   2 seconds ago       Up 1 second         0.0.0.0:8080->8080/tcp   sample

❯ curl http://localhost:8080
hello world

参考

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

dockerのscratchイメージでgolangのWebアプリを動かすときは、スタティックリンクしてるかを確認

Best practices for writing Dockerfiles (参考訳v18.09ベース)を参考に、golangで書いたWebアプリを動かそうとしたらハマったので、その記録を残します。

ざっくりいうと

  1. golangで書いたwebアプリ(サンプル)を、dockerのscratchイメージ上で動かそうとしたら起動で失敗
  2. 調べたらダイナミックリンクでビルドされており、scratchイメージではファイルが足りなかったのが原因
  3. スタティックリンクでビルドし直したら解決した

環境

  • go 1.13.5
  • docker 19.03.5

ハマるまでの流れ

"Use multi-stage builds"にマルチステージビルドを使うgolangのサンプルがあります。ビルドするときに使うイメージとリリースするイメージを分けることで、リリースイメージに余計なもの入れなくてすみ、イメージのサイズも小さくできます。

それはよさそうだと言うことで、手元にあったWebアプリをサンプルにして次のようなDockerfileを用意しました。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

sample-go-serverは、hello worldを返す簡単なものです。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = fmt.Fprintf(w, "hello world")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

このDockerfileをビルドします。

❯ docker build -t sample-go-server .
❯ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
sample-go-server         latest              0acf7d1e1ed7        42 minutes ago      7.45MB

runで起動すると思いきや次のようなエラーで失敗します。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
1e097919ec5ac31839228646e2b14bd0434f56d74787d73b6afa172154829250

❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

❯ docker logs sample
standard_init_linux.go:211: exec user process caused "no such file or directory"

"no such file or directory"と言われましても…。何が足りないかを言ってくれ〜?

解決方法

ググったところ以下が見つかりました。ありがとうインターネッツ。

netパッケージを含む場合はダイナミックリンクでビルドされ、それが原因でno such fileになるらしいです。
なので、さっそくこれに該当しているかを確認してみます。
ビルドで使ったalpineイメージにはfileコマンドが入っていないため、まずそれを入れます。パッケージは Alpine Linux packagesで探せます。

/bin # apk update && apk add file
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
v3.11.2-25-g58afcd742e [http://dl-cdn.alpinelinux.org/alpine/v3.11/main]
v3.11.2-24-g7cfe3a1534 [http://dl-cdn.alpinelinux.org/alpine/v3.11/community]
OK: 11261 distinct packages available
(1/2) Installing libmagic (5.37-r1)
(2/2) Installing file (5.37-r1)
Executing busybox-1.31.1-r8.trigger
OK: 12 MiB in 17 packages
/bin # which file
/usr/bin/file

fileコマンドで確認してみると、たしかにdinamically linkedとなっていました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, Go BuildID=5E6Qy3Li7DELFoSZUyv5/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/wYNglNx2pwV9Z_45IRLn, not stripped

参考サイトにあったCGO_ENABLED=0でビルドをし直してみます。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN CGO_ENABLED=0 go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

たしかにstatically linkedに変わりました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=cD81ASWTt8bngTyIxfpe/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/rmgAW8vnYv0XAugzIkMj, not stripped

docker runでも無事起動できました。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
c27e29aaa697ac7131995472377bb2ff58e6a6ebe6a8174fb8a9de64efc767d5

❯ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c27e29aaa697        sample-go-server    "/bin/sample-go-serv…"   2 seconds ago       Up 1 second         0.0.0.0:8080->8080/tcp   sample

❯ curl http://localhost:8080
hello world

参考

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

dockerのscratchイメージでgolangのWebアプリを動かす

Best practices for writing Dockerfiles (参考訳v18.09ベース)を参考に、golangで書いたWebアプリを動かそうとしたらハマったので、その記録を残します。

ざっくりいうと

  1. golangで書いたwebアプリ(サンプル)を、dockerのscratchイメージ上で動かそうとしたら起動で失敗
  2. 調べたらダイナミックリンクでビルドされており、scratchイメージではファイルが足りなかったのが原因
  3. スタティックリンクでビルドし直したら解決した

環境

  • go 1.13.5
  • docker 19.03.5

ハマるまでの流れ

"Use multi-stage builds"にマルチステージビルドを使うgolangのサンプルがあります。ビルドするときに使うイメージとリリースするイメージを分けることで、リリースイメージに余計なもの入れなくてすみ、イメージのサイズも小さくできます。

それはよさそうだと言うことで、手元にあったWebアプリをサンプルにして次のようなDockerfileを用意しました。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

sample-go-serverは、hello worldを返す簡単なものです。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = fmt.Fprintf(w, "hello world")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

このDockerfileをビルドします。

❯ docker build -t sample-go-server .
❯ docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
sample-go-server         latest              0acf7d1e1ed7        42 minutes ago      7.45MB

runで起動すると思いきや次のようなエラーで失敗します。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
1e097919ec5ac31839228646e2b14bd0434f56d74787d73b6afa172154829250

❯ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

❯ docker logs sample
standard_init_linux.go:211: exec user process caused "no such file or directory"

"no such file or directory"と言われましても…。何が足りないかを言ってくれ〜?

解決方法

ググったところ以下が見つかりました。ありがとうインターネッツ。

netパッケージを含む場合はダイナミックリンクでビルドされ、それが原因でno such fileになるらしいです。
なので、さっそくこれに該当しているかを確認してみます。
ビルドで使ったalpineイメージにはfileコマンドが入っていないため、まずそれを入れます。パッケージは Alpine Linux packagesで探せます。

/bin # apk update && apk add file
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
v3.11.2-25-g58afcd742e [http://dl-cdn.alpinelinux.org/alpine/v3.11/main]
v3.11.2-24-g7cfe3a1534 [http://dl-cdn.alpinelinux.org/alpine/v3.11/community]
OK: 11261 distinct packages available
(1/2) Installing libmagic (5.37-r1)
(2/2) Installing file (5.37-r1)
Executing busybox-1.31.1-r8.trigger
OK: 12 MiB in 17 packages
/bin # which file
/usr/bin/file

fileコマンドで確認してみると、たしかにdinamically linkedとなっていました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, Go BuildID=5E6Qy3Li7DELFoSZUyv5/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/wYNglNx2pwV9Z_45IRLn, not stripped

参考サイトにあったCGO_ENABLED=0でビルドをし直してみます。

FROM golang:1.13.5-alpine AS build
WORKDIR /go/src/sample-go-server
COPY ./app /go/src/sample-go-server
RUN CGO_ENABLED=0 go build -o /bin/sample-go-server

FROM scratch
COPY --from=build /bin/sample-go-server /bin/sample-go-server
EXPOSE 8080
ENTRYPOINT ["/bin/sample-go-server"]

たしかにstatically linkedに変わりました。

/bin # file sample-go-server 
sample-go-server: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=cD81ASWTt8bngTyIxfpe/TdC1EDiTsXrg0i0ta2Xx/49v4RWXcyEm12mEJPV8f/rmgAW8vnYv0XAugzIkMj, not stripped

docker runでも無事起動できました。

❯ docker run -d -p 8080:8080 --name sample sample-go-server
c27e29aaa697ac7131995472377bb2ff58e6a6ebe6a8174fb8a9de64efc767d5

❯ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c27e29aaa697        sample-go-server    "/bin/sample-go-serv…"   2 seconds ago       Up 1 second         0.0.0.0:8080->8080/tcp   sample

❯ curl http://localhost:8080
hello world

参考

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

軽量なDocker Imageを作成する

目的

この記事では、軽量のDocker Imageを生成するDockerfileを作成する手順を書いていきます。

余談

有名な仮想化ソフトとして、Virtual Box(+ Vagrant)がありますが、以下のような問題点があります。

  • 仮想マシン起動が遅い
  • イメージの容量が大きい
    • 2GBとか

勿論、Virtual Boxは、ホストOS(PC)の中にそのままOSを立ち上げるため、ネットワーク周り等扱いやすいと言えば扱いやすいのですが、仮想マシン立ち上げ時に時間がかかったり、ほかの人と同じ環境を共有する際、2GBのイメージを交換したりするのは大変です。

そこで、Dockerという仮想化ソフトの出番ですが、実際に使ってみると初心者は特に、以下の課題が発生するかと思います。

  • Docker Imageが1GBを超える

仮想環境のイメージを共有する際、Virtual Boxとは異なり、Imageを生成するためのテキストで記述されたDockerfileを使用することに関しては、イメージ共有を効率化するのですが、何も考えずイメージを作成していしまうと、1GBのイメージになってしまい、それなりにリソースを食います。

やはり、かっこいいのは、軽量化されたイメージだと思うので、今回は自分で目的に沿ったイメージを作成したいと思います。

開発環境

今回のDocker Imageは、以下の環境で作成/テストを行います。

  • OS: Windows 10
  • Docker: Docker Toolbox version 19.03.1

Dockerfileの作成

ゴール

Ruby on RailsのWebアプリケーション(rails newした初期アプリ)が入っているDocker Imageを生成するDockerfileを作成します。

ハードウェア容量が少ないサーバー等に需要があるかと思います。

また、Docker Imageを共有するときも、軽い方がImageの生成が素早くていいと思います。

作成するDocker Image

Ruby公式の軽量イメージのalpineイメージを使用します。

このalpineイメージ、最小のソフトしかインストールされていない為、Ruby on Railsのアプリケーション起動に必要なソフトをインストールしながらDockerfileを作成します。

インストールするアプリケーションのバージョンは、以下です。

  • Ruby: 2.6.5
  • Ruby on Rails: 6.0.1

Dockerfileの作成手順

Dockerfileを作成するの手順は以下の様に行います。

  1. ベースイメージのPull
  2. ベースコンテナの立ち上げ
  3. コンテナ内で必要ソフトのインストール
  4. Dockerfileの作成
  5. Dockerfileの実行

地道な作業になりますが、やる気をそがれず、後戻りせず行うためには、上記のような手順になるかと思います。

それでは、実際にイメージを作成していきます。

Dockerはインストールするされていることが前提で解説をします。

1.ベースイメージのPull

以下のコマンドでベースとなるDocker Imageをローカルにダウンロードします。

どのバージョンのRubyイメージがあるかは、公式HPDescriptionタブに記述があります。

docker pull ruby:2.6.5-alpine3.10

2.ベースコンテナの立ち上げ

以下のコマンドで、Pullしたイメージを使用し、コンテナを立ち上げます。

docker run -it ruby:2.6.5-alpine3.10 /bin/ash

alpineイメージでは、bashは使用できないため、/bin/ashを指定して実行します。

3.コンテナ内で必要ソフトのインストール

コンテナ内でRailsアプリケーションを立ち上げるために必要なソフトをインストールします。

インストールしたソフトやコマンドに関しては、Dockerfileまたはメモに書き残します。

エラーが発生した場合、エラー文を読んだり、検索したりして対処を行います。

また、コマンド実行後に、y/nの選択肢が出る場合は、記録を行い、Dockerfileでは-yなどのオプションをつけて記述していきます。

今回は、railsをインストールして、必要なパッケージをインストールする方法をとりました。

コンテナ内で実行したコマンド

/ # apk update
/ # apk add yarn nodejs
/ # gem install bundler
/ # gem install rails <- C compilerなどがなく エラー
/ # apk add gcc
/ # apk add g++
/ # apk add make
/ # gem install rails <- 成功
/ # mkdir app
/ # cd app
/ # rails new . <- sqlite3がなくエラー
/ # apk add sqlite-dev
/ # rails s
... <- rails sができるまで試す
メモ
apk update
apk add yarn nodejs
gem install bundler
apk gcc g++ make
apk add sqlite-dev
...

4.Dockerfileの作成

3でメモしたコマンドを元に、Dockerfileを作成します。

作成したDockerfileが以下です。

Dockerfile
FROM ruby:2.6.5-alpine3.10

ENV APP_HOME /app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD . $APP_HOME

RUN apk update \
    && apk add  --no-cache gcc g++ make sqlite-dev yarn nodejs \
    && gem install bundler \
    && bundle install \
    && yarn install

EXPOSE 3000
CMD ["rails", "s", "-b", "0.0.0.0"]

5.Dockerfileの実行

4.で作成したDockerfileを実行します。

railsのアプリケーションディレクトリの中に、Dockerfileを置き、イメージを生成します。

ディレクトリは以下のような構成になります。

app/
   ├ Dockerfile
   ├ bin/
   ├ config.ru
   ├ Gemfile
   ├ Gemfile.lock
   ├ lib/
   ├ node_modules/
   ├ postcss.config.js
   ├ Rakefile
   ├ storage/
   ├ tmp/
   ├ yarn.lock
   ├ babel.config.js
   ├ config/
   ├ db/
   ├ log/
   ├ package.json
   ├ public/
   ├ README.md
   ├ test/
   └ vendor/

また、4.でrails sを実行した際に、Please add gem 'tzinfo-data' to your Gemfile and run bundle installといったエラーが出たので、ホストOSのGemfileを変更します。

- (修正前) gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+ (修正後) gem 'tzinfo-data'

以下のコマンドでDockerfileをビルドします。

docker build -t rails-app .

作成したイメージを使用して上手くコンテナが起動できない場合は、以下のコマンドを使用して、ログを確認しつつ、エラーを解消していきます。

docker logs <コンテナID>

作成したイメージからコンテナを立ち上げ、ブラウザなどから、Railsアプリケーションの起動が確認できれば終了です。

docker run -d -p 3000:3000 rails-app

curl http://192.168.99.100:3000

公式イメージとの比較

Rubyの公式イメージにrailsをインストールしたDocker Imageと比較しました。

イメージ名 容量
rails-app 649MB
ruby(公式) 1.29GB

容量はあくまでも参考にしてください。
そもそも、Rubyの公式イメージ自体、840MBあるので、今回作成したイメージが軽量化されていることがわかります。

docker-composeを使用して、ホストOS側のアプリケーションディレクトリをマウントすると、もっとイメージ自体の容量が少なくなります。
Macを使用して、ホストOSからエディタで開発をする場合はdocker-composeを使用した方がいいかもしれません。

ポイントとしては、rails new .をするまでの過程の中で、必要最低限のものしかインストールしない事だと思います。
例えば、alpine-sdkをインストールすれば、gccやmakeがインストールできるのですが、その他gitやcurlなど必要のない物もインストールされてしまいます。
なので、gem install railsbundle installした際にエラーが出て、インストールが必要なものだけ入れるのが良いと思います。

また、今回使用したruby:2.6.5-alpine3.10には、viが入っていたので、この辺りも削除するとよいと思います。

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

dockerでbrowser-syncを導入して令和のWordPress環境に

gengou_happyou_reiwa_kakageru.png

概要

2017年ぐらいまではほぼWPに食わせてもらっていたというぐらいにWP案件をやりまくっていたものの、そこからSPAなどを触るようになりブラウザシンクやローカル構築に甘やかされまくった結果、WPの仕事が辛くて仕方なくなる

クリアライン

・ブラウザシンクを入れてローカルのthemeを変更したらブラウザシンクでブラウザをオートリロードさせて開発スピードをアップしたい

問題解決に向けて

docker-comopseを導入する
docker-compose.yml

version: "3"

services:
    db:
        image: mysql:5.7
        volumes:
            - ./db_data:/var/lib/mysql
            - ./localhost.sql:/docker-entrypoint-initdb.d/install_wordpress.sql
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: main_db
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress

    wordpress:
        image: wordpress:latest
        depends_on:
            - db
        ports:
            - "8000:80"
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_NAME: main_db
            WORDPRESS_DB_PASSWORD: wordpress
            WORDPRESS_TABLE_PREFIX: wp_
        volumes:
            - ./themes:/var/www/html/wp-content/themes
            - ./plugins:/var/www/html/wp-content/plugins
            - ./languages:/var/www/html/wp-content/languages

    phpmyadmin:
        image: phpmyadmin/phpmyadmin
        environment:
            - PMA_ARBITRARY=1
            - PMA_HOST=db:3306
            - PMA_USER=wordpress
            - PMA_PASSWORD=wordpress
        depends_on:
            - db
        ports:
            - 8080:80
        volumes:
            - /sessions

    bs-wordpress:
        image: ustwo/browser-sync
        command: start --proxy "wordpress:80" --files "themes/**/*.php,themes/**/*.css"
        volumes:
            - ./themes:/source/themes
        depends_on:
            - wordpress
        ports:
            - "3000:3000"
            - "3001:3001"

docker-compose up後に

bs-wordpress_1  | [Browsersync] Proxying: http://wordpress:80
bs-wordpress_1  | [Browsersync] Access URLs:
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |        Local: http://localhost:3000
bs-wordpress_1  |     External: http://172.21.0.5:3000
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |           UI: http://localhost:3001
bs-wordpress_1  |  UI External: http://172.21.0.5:3001
bs-wordpress_1  |  -----------------------------------

というメッセージが出てきてlocalhost:3000でブラウザシンクが立ち上がり
themes配下のphpファイルとcssをを更新するとブラウザシンクが走りリロードされます。

何をやっているのか

Dockerオートデプロイ (1).png

ついでに

普段のWP環境はこれに
・localhost.sqlを利用してサーバーのDBをローカルにpullする
・WP Offload Mediaを利用して画像ファイルの管理をすべてS3にぶん投げてローカルとサーバーのズレを最小限にする
・AWS code deployを利用して特定のgitブランチにアップすると自動でサーバーにデプロイを行う
ということを組み合わせて行いPRベースでの開発を徹底しています。
そのあたりもまた機会があれば記事にしたいと思います。

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

dockerでオートデプロイを導入して令和のWordPress環境に

gengou_happyou_reiwa_kakageru.png

概要

2017年ぐらいまではほぼWPに食わせてもらっていたというぐらいにWP案件をやりまくっていたものの、そこからPWAなどを触るようになりブラウザシンクやローカル構築に甘やかされまくった結果、WPの仕事が辛くて仕方なくなる

クリアライン

・ブラウザシンクを入れてローカルのthemeを変更したらブラウザシンクでブラウザをオートリロードさせて開発スピードをアップしたい

問題解決に向けて

docker-comopseを導入する
docker-compose.yml

version: "3"

services:
    db:
        image: mysql:5.7
        volumes:
            - ./db_data:/var/lib/mysql
            - ./localhost.sql:/docker-entrypoint-initdb.d/install_wordpress.sql
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: main_db
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress

    wordpress:
        image: wordpress:latest
        depends_on:
            - db
        ports:
            - "8000:80"
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_NAME: main_db
            WORDPRESS_DB_PASSWORD: wordpress
            WORDPRESS_TABLE_PREFIX: wp_
        volumes:
            - ./themes:/var/www/html/wp-content/themes
            - ./plugins:/var/www/html/wp-content/plugins
            - ./languages:/var/www/html/wp-content/languages

    phpmyadmin:
        image: phpmyadmin/phpmyadmin
        environment:
            - PMA_ARBITRARY=1
            - PMA_HOST=db:3306
            - PMA_USER=wordpress
            - PMA_PASSWORD=wordpress
        depends_on:
            - db
        ports:
            - 8080:80
        volumes:
            - /sessions

    bs-wordpress:
        image: ustwo/browser-sync
        command: start --proxy "wordpress:80" --files "themes/**/*.php,themes/**/*.css"
        volumes:
            - ./themes:/source/themes
        depends_on:
            - wordpress
        ports:
            - "3000:3000"
            - "3001:3001"

docker-compose後に

bs-wordpress_1  | [Browsersync] Proxying: http://wordpress:80
bs-wordpress_1  | [Browsersync] Access URLs:
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |        Local: http://localhost:3000
bs-wordpress_1  |     External: http://172.21.0.5:3000
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |           UI: http://localhost:3001
bs-wordpress_1  |  UI External: http://172.21.0.5:3001
bs-wordpress_1  |  -----------------------------------

というメッセージが出てきてlocalhost:3000でブラウザシンクが立ち上がり
themes配下のphpファイルとcssをを更新するとブラウザシンクが走りリロードされます。

何をやっているのか

Dockerオートデプロイ.png

ついでに

普段のWP環境はこれに
・localhost.sqlを利用してサーバーのDBをローカルにpullする
・WP Offload Mediaを利用して画像ファイルの管理をすべてS3にぶん投げてローカルとサーバーのズレを最小限にする
・AWS code deployを利用して特定のgitブランチにアップすると自動でサーバーにデプロイを行う
ということを組み合わせて行いPRベースでの開発を徹底しています。
そのあたりもまた機会があれば記事にしたいと思います。

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

dockerでブラウザシンクを導入して令和のWordPress環境に

gengou_happyou_reiwa_kakageru.png

概要

2017年ぐらいまではほぼWPに食わせてもらっていたというぐらいにWP案件をやりまくっていたものの、そこからPWAなどを触るようになりブラウザシンクやローカル構築に甘やかされまくった結果、WPの仕事が辛くて仕方なくなる

クリアライン

・ブラウザシンクを入れてローカルのthemeを変更したらブラウザシンクでブラウザをオートリロードさせて開発スピードをアップしたい

問題解決に向けて

docker-comopseを導入する
docker-compose.yml

version: "3"

services:
    db:
        image: mysql:5.7
        volumes:
            - ./db_data:/var/lib/mysql
            - ./localhost.sql:/docker-entrypoint-initdb.d/install_wordpress.sql
        environment:
            MYSQL_ROOT_PASSWORD: wordpress
            MYSQL_DATABASE: main_db
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress

    wordpress:
        image: wordpress:latest
        depends_on:
            - db
        ports:
            - "8000:80"
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_NAME: main_db
            WORDPRESS_DB_PASSWORD: wordpress
            WORDPRESS_TABLE_PREFIX: wp_
        volumes:
            - ./themes:/var/www/html/wp-content/themes
            - ./plugins:/var/www/html/wp-content/plugins
            - ./languages:/var/www/html/wp-content/languages

    phpmyadmin:
        image: phpmyadmin/phpmyadmin
        environment:
            - PMA_ARBITRARY=1
            - PMA_HOST=db:3306
            - PMA_USER=wordpress
            - PMA_PASSWORD=wordpress
        depends_on:
            - db
        ports:
            - 8080:80
        volumes:
            - /sessions

    bs-wordpress:
        image: ustwo/browser-sync
        command: start --proxy "wordpress:80" --files "themes/**/*.php,themes/**/*.css"
        volumes:
            - ./themes:/source/themes
        depends_on:
            - wordpress
        ports:
            - "3000:3000"
            - "3001:3001"

docker-compose up後に

bs-wordpress_1  | [Browsersync] Proxying: http://wordpress:80
bs-wordpress_1  | [Browsersync] Access URLs:
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |        Local: http://localhost:3000
bs-wordpress_1  |     External: http://172.21.0.5:3000
bs-wordpress_1  |  -----------------------------------
bs-wordpress_1  |           UI: http://localhost:3001
bs-wordpress_1  |  UI External: http://172.21.0.5:3001
bs-wordpress_1  |  -----------------------------------

というメッセージが出てきてlocalhost:3000でブラウザシンクが立ち上がり
themes配下のphpファイルとcssをを更新するとブラウザシンクが走りリロードされます。

何をやっているのか

Dockerオートデプロイ (1).png

ついでに

普段のWP環境はこれに
・localhost.sqlを利用してサーバーのDBをローカルにpullする
・WP Offload Mediaを利用して画像ファイルの管理をすべてS3にぶん投げてローカルとサーバーのズレを最小限にする
・AWS code deployを利用して特定のgitブランチにアップすると自動でサーバーにデプロイを行う
ということを組み合わせて行いPRベースでの開発を徹底しています。
そのあたりもまた機会があれば記事にしたいと思います。

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

日本語自然言語処理で必須の前処理まとめ(Dockerによる環境構築込み)

この記事でやること

日本語文章で自然言語処理的なことをやる際に, アルゴリズム選択やパラメータチューニングと同等かそれ以上に重要となる前処理。丁寧に色々やりたいとは言え毎回ゼロから同じようなスクリプトを書くのも面倒なので, 毎回必ずやるであろう

  • 全角・半角の統一と重ね表現(!!とかーーとか)の除去
  • HTMLタグの除去
  • 絵文字の除去
  • URLの除去
  • 記号の除去
  • 数字の表記統一
  • 分かち書き
  • 見出し語化

あたりの処理を一発で済ませるために用意した自分なりの秘伝のタレを公開します。
ついでにMeCabの導入やJupyter lab環境の構築もDocker化できたので合わせて載せてます。

環境構築編

まずは以下のDockerfileを用意します。gensimやspaCyなど今回の前処理には使わないパッケージも入ってますがお気になさらず。
(2020/1/12追記) mecab-ipadic-neologdのインストールで-aオプションを付けないと一部の辞書しかインストールされないのでオプションを追加
(2020/1/13追記) プロセス並列で実行するためのメソッドを追加

FROM jupyter/minimal-notebook

USER root

## Mecab関連インストール
## mecabrc is installed in /etc/mecabrc
## default dictionary path is /var/lib/mecab/dic/debian
## mecab-ipadic-utf-8 is installed in /var/lib/mecab/dic/ipadic-utf8
## mecab-ipadic-neologd is installed in /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get install -y file && \
    apt-get install -y mecab && \
    apt-get install -y libmecab-dev && \
    apt-get install -y mecab-ipadic-utf8 && \
    git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git && \
    cd mecab-ipadic-neologd && \
    bin/install-mecab-ipadic-neologd -n -y -a && \
    rm -rf /home/jovyan/mecab-ipadic-neologd

## Pythonパッケージインストール
USER $NB_UID
RUN conda install --quiet --yes \
    'conda-forge::blas=*=openblas' \
    'ipywidgets=7.5*' \
    'numpy=1.17*' \
    'pandas=0.25*' \
    'matplotlib=3.1*' \
    'seaborn=0.9*' \
    'sqlalchemy=1.3*' \
    'beautifulsoup4=4.7.*' \
    'scikit-learn=0.22*' \
    'tensorflow=1.13*' \
    'keras=2.2*' && \
    conda clean --all -f -y && \
    pip install spacy==2.2.3 \
    'https://github.com/megagonlabs/ginza/releases/download/latest/ginza-latest.tar.gz' \
    japanize-matplotlib==1.0.5 \
    mecab-python3==0.996.3 \
    neologdn==0.4 \
    emoji==0.5.4 \
    gensim==3.8.1 \
    pipetools==0.3.5 && \
    jupyter nbextension enable --py widgetsnbextension --sys-prefix && \
    jupyter labextension install jupyterlab_vim && \
    jupyter labextension install @jupyterlab/toc && \
    jupyter labextension install @jupyter-widgets/jupyterlab-manager@^1.0.0 && \
    rm -rf $CONDA_DIR/share/jupyter/lab/staging && \
    rm -rf /home/$NB_USER/.cache/yarn && \
    rm -rf /home/$NB_USER/.node-gyp && \
    MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \
    fix-permissions /home/$NB_USER

WORKDIR /home/jovyan/work

Dockerfileが用意できたら次のコマンドでイメージをビルド・起動してJupyter Labを立ち上げます。

$ docker build -t my-nlp-notebook:1.0 .
$ docker run --rm -p 8888:8888 -e JUPYTER_ENABLE_LAB=yes -e TZ=Asia/Tokyo -v `pwd`:/home/jovyan/work my-nlp-notebook:1.0

前処理用テンプレコード

Jupyterに以下のコードを貼っつけます。
(2020/1/12追記) mecabの辞書としてmecab-ipadic-neologdを使う設定が抜けていたので修正。

import MeCab
import neologdn
import emoji
import re
from bs4 import BeautifulSoup
from pipetools import pipe
from multiprocessing import Pool

class Preprocessor:
    CATEGORY_INDEX = 0   # node.feature中で品詞が格納されているindex
    ROOT_FORM_INDEX = 6  # 単語の原型が格納されているindex
    TAGGER = MeCab.Tagger("-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd")

    def __init__(self, targets = ["名詞", "動詞", "形容詞", "副詞", "連体詞"]):
        self.target_categories = set(targets)
        self.url_pattern = re.compile(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+')
        self.half_width_symbol_pattern = re.compile(r'[!-/:-@[-`{-~]')
        self.full_width_symbol_pattern = re.compile(u'[■-♯]')
        self.number_pattern = re.compile(r'\d+')

    def pipe_all(self, texts):
        '''
        全前処理工程を行う 
        1. 全角・半角の統一と重ね表現の除去
        2. HTMLタグの除去
        3. 絵文字の除去
        4. URLの除去
        5. 記号の除去
        6. 数字の表記統一
        7. 分かち書きと見出し語化
        '''

        result = texts > (pipe
            | (lambda x: self._loop(x, self._normalize_text))
            | (lambda x: self._loop(x, self._remove_html_tag))
            | (lambda x: self._loop(x, self._remove_emoji))
            | (lambda x: self._loop(x, self._remove_url))
            | (lambda x: self._loop(x, self._remove_symbol))
            | (lambda x: self._loop(x, self._convert_number_to_zero))
            | (lambda x: self._loop(x, self._divide_text))
        )

        return result

    def parallel_pipe_all(self, texts, num_process = 2):
        '''pipe_allをプロセス並列で実行する'''

        with Pool(processes = num_process) as p:
            result = p.map(func = self._normalize_text, iterable = texts)
            result = p.map(func = self._remove_html_tag, iterable = result)
            result = p.map(func = self._remove_emoji, iterable = result)
            result = p.map(func = self._remove_url, iterable = result)
            result = p.map(func = self._remove_symbol, iterable = result)
            result = p.map(func = self._convert_number_to_zero, iterable = result)
            result = p.map(func = self._divide_text, iterable = result)

        return result    

    def _loop(self, texts, func):
        '''テキストのリストに対する処理を高速化するため内包表記をかます'''

        return [func(text) for text in texts]

    def _normalize_text(self, text):
        '''全角/半角の統一と重ね表現の除去'''

        return neologdn.normalize(text)

    def _remove_html_tag(self, text):
        '''HTMLタグを含むテキストから文字列のみを取り出す'''

        return BeautifulSoup(text).get_text() 

    def _remove_emoji(self, text):
        '''絵文字を空文字に置換する'''

        return ''.join(['' if char in emoji.UNICODE_EMOJI else char for char in text])

    def _remove_url(self, text):
        '''URLを空文字に置換する'''

        return self.url_pattern.sub('', text)

    def _remove_symbol(self, text):
        '''記号をスペースに置換する(意味のある記号も存在するため)'''

        # 半角記号の除去
        text_without_half_width_symbol = self.half_width_symbol_pattern.sub(' ', text)

        # 全角記号の置換 (ここでは0x25A0 - 0x266Fのブロックのみを除去)
        text_without_full_width_symbol = self.full_width_symbol_pattern.sub(' ', text_without_half_width_symbol)

        return text_without_full_width_symbol

    def _convert_number_to_zero(self, text):
        '''数字を全て0に置換する'''

        return self.number_pattern.sub('0', text)

    def _divide_text(self, text):
        '''分かち書きとMeCab辞書による見出し語化'''

        words = []
        node = self.TAGGER.parseToNode(text)

        while node:
            features = node.feature.split(',')

            if features[self.CATEGORY_INDEX] in self.target_categories:
                # 原型がMeCabの辞書に存在しない場合には単語の表層を格納する
                if features[self.ROOT_FORM_INDEX] == "*":
                    words.append(node.surface)
                # 辞書に載っている単語については原型に直して格納する
                else:
                    words.append(features[self.ROOT_FORM_INDEX])

            node = node.next

        return words

使い方

pipe_allメソッドに文章のリストを渡せば全処理をシリアル実行してくれます。
マルチコア環境の場合はparallel_pipe_allの方を使うと並列実行されます。
全部の処理が効くように敢えて変な文章を相手に前処理してみたのが以下。

text = """
今週は男2人でカフェ開拓してきたよv(^^)v
僕が頼んだのは濃厚なかぼちゃのタルト。
うめーーーーー!!
超Deliciousで接客もGoodでした?
これで1,430.52円は安い!☆
お店のリンク: http://hogehoge.navi/fuga_cafe
#週末グルメ
<h1>タイトル<p>路地裏のカフェ</p></h1>
"""

processor = Preprocessor()
print(processor.pipe_all([text]))

=> [['今週', '男', '0', '人', 'カフェ', '開拓', 'する', 'くる', 'v', 'v', '僕', '頼む', 'の', '濃厚', 'かぼちゃ', 'タルト', 'うめー', 'Delicious', '接客', 'Good', 'これ', '0', '0', '0円', '安い', '店', 'リンク', '週末', 'グルメ', 'タイトル', '路地', '裏', 'カフェ']]

v(^^)v ⇐こやつの両手が残っちゃってますね:droplet:
まあこれはいずれ何とかします(え)。

実行時間を測ってみる

手元にちょうどいいデータセットがなかったので, ひとまずさっきと同じテキストを1万件前処理した際の実行時間を見てみました。

lenovo ideapad 330S Intel® Core™ i5 8コア
Ubuntu 18.04 LTS

の環境で以下を実行。

[1] texts = [text for _ in range(10000)]

[2] %%timeit
     precessor.pipe_all(texts)
4.08 s ± 7.84 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

約4秒。各処理ごとの実行時間の内訳を見てみると...

正規化, HTMLタグの除去, 分かち書き辺りで時間を食っているようですね。

次に並列実行してみます。と言っても呼び出すメソッド名を変えるだけですが。
どのくらい高速化されたかをわかりやすくするためデータ件数を10万に増やした上でシングルコア計算の場合と比較したものが次のグラフです。

8コア並列までやるとシングルコアの場合の4倍速くらいになっていますね!

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

Vagrant で Elixir/Phoenix 開発環境を構築する手順

Elixir/Phoenix の開発環境を構築するにはいくつかの方法がありますが、ある程度の規模の Phoenix アプリを開発するなら Docker Compose を利用したくなるでしょう。

しかし、実際に開発を始めると、悩ましい問題に遭遇します。それは、Docker Desktop for Mac あるいは Docker Desktop for Windows の元で動く Phoenix アプリがとても遅い、ということです。いや、Phoenix アプリに限りません。データベースを使用する Web アプリ全般の反応がとても悪いです。「Docker Mac 遅い」または「Docker Windows 遅い」で Google 検索すると、大量の怨嗟の声とさまざまな解決策がヒットします。

ひとつの解決策は、Docker Desktop for Mac/Windows の利用をあきらめて、Vagrant + VirtualBox を採用するというものです。VirtualBox の上に Linux を載せ、そこに Docker をインストールし、Linux 上に Elixir コンテナを構築するという方法です。

筆者が試してみた限りでは、この方法はとてもうまく行きます。しかし、VirtualBox 特有の罠がいくつかあるので、なにもないところから VagrantfileDockerfiledocker-compose.yml を作るのは意外に難しいものです。

そこで、phx-vagrant という GitHub リポジトリに、これらの設定ファイルのセットを作りました。

以下、このリポジトリを clone して Elixir/Phoenix 開発環境を構築する手順を紹介します。

もしこの手順の通りにやってみて環境構築に失敗したら、GitHub で issue を立てて教えていただけると助かります。

動作確認済みのOS

  • macOS Mojave (v10.14)
  • Windows 10 Pro

※ おそらく Windows 10 Home でも動作しますが、筆者自身は確認していません。もし確認できた方がいらっしゃいましたら、t-kuroda @oiax.jp までご連絡いただけると助かります。

必要なソフトウェア

  • Oracle VM VirtualBox 6.0 ※ 最新の 6.1 は非推奨
  • Vagrant 2.2 以上
  • Git 2.7 以上

VirtualBox のバージョンに関する注記

2020年1月12日時点での VirtualBox の最新版は v6.1.0 ですが、Vagrant の最新版(v2.2.6)は VirtualBox 6.1 に対応していません。可能であれば、VirtualBox 6.0 をインストールしてください。

すでに VirtualBox 6.1 をインストールしている方、あるいは VirtualBox 6.1 を使いたい方は、「mac vagrant virtualbox 6.1」でネット検索して対応方法を探してください。

Git for Windows に関する注記

Git for Windows をインストールする過程で「Configuring the line ending conversions」について尋ねられたとき、デフォルトの「Checkout Windows-style, commit Unix-style line endings」ではなく、2番目の選択肢「Checkout as-is, commit Unix-style line endings」を選んでください。

すでに Git for Windows をインストール済みの場合は、次のコマンドで変更できます。

% git config --global core.autocrlf input

環境構築手順

% git clone https://github.com/oiax/phx-vagrant.git
% cd phx-vagrant
% vagrant plugin install vagrant-disksize
% vagrant up
% vagrant ssh
$ bin/setup.sh

これで、Ubuntu 18.04 Server の上に Docker がインストールされ、Elixir 1.9.4 がインストールされた Debian の Docker コンテナができあがります。

ネットワーク接続状況によりますが、初めてこの環境を構築する場合、2時間以上かかることがあります。ほとんどの時間は Ubuntu 18.04 Server の ISO イメージのダウンロードに費やされます。

Phoenix アプリケーション開発手順

Phoenix アプリケーションの新規作成

$ bin/login.sh
> mix phx.new . --app my_app --module MyApp

途中で「Y」または「n」の入力を求められたら、そのまま Enter キーを押してください。

ソースコードの書き換え

ここから先、生成された Phoenix アプリケーションのソースコードをテキストエディタで書き換えていきます。ホストPC(Mac/Windows)側で編集しても、コンテナ内で Vim を使って編集しても、どちらでも構いません。

データベース接続設定の変更

config/dev.exs を開き、hostname の値を "localhost" から "db" に変更してください。

phoenix_live_reload の設定

以下の記述を config/dev.exsMyApp.Repo に関する設定(4-10行)の直後に追加してください。

if System.get_env("COMPOSE_FILE") == "docker-compose.vagrant.yml" do
  config :phoenix_live_reload,
    backend: :fs_poll,
    backend_opts: [
      interval: 500
    ],
    dirs: [
      "priv/static",
      "priv/gettext",
      "lib/my_app_web/templates",
      "lib/my_app_web/views"
    ]
end

この記述がないと、HTMLテンプレートやスタイルシートを変更しても、ブラウザが自動更新されません。

webpack の設定

assets/webpack.config.js の末尾の }); の前に以下の記述を追加してください。

  watchOptions: {
    aggregateTimeout: 300,
    poll: 1000,
    ignored: /node_modules/
  }

また、直前の行の末尾に ] の後にコンマを追加してください。

  ],

データベースの作成

> mix ecto.create

サーバーの起動

> exit
$ bin/start.sh

動作確認

ブラウザで http://localhost:4000 を開けば、Phoenix アプリケーションにアクセスできます。

ホストPC(Mac/Windows)側のテキストエディタで以下の2つのファイルを適宜書き換えてください。

  • lib/my_app_web/templates/page/index.html.eex
  • assets/css/phoenix.css

ファイルを保存してから数秒以内にブラウザが自動でリロードされ、表示が更新されることを確認してください。

サーバーの停止

ターミナルで Ctrl-C を入力すると Phoenix サーバーが停止します。

Docker コンテナの停止

$ bin/stop.sh

VirtualBox ゲストマシンの停止

$ exit
% vagrant halt

備考

この記事の冒頭で「VirtualBox 特有の罠」と書きました。主な罠は、次の 2 点です。

  1. VirtualBox の共有フォルダの中にデータベースのデータ領域を置いてはならない。
  2. VirtualBox の共有フォルダの中に node_modules ディレクトリを置いてはならない。

これらの罠にはまると、Phoenix サーバーがうまく動きません。

詳しい説明は省きますが、docker-compose.vagrant.ymlの中でいろいろと工夫しています。

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

Dockerで簡単にRedis試す

1, フォルダ作成

mkdir redis
cd redis

2, docker-compose.ymlファイル作成

docker-compose.yml
version: '3'
services:
  redis:
    image: "redis:latest"
    container_name: redis_test #下記のコマンド時に使用するコンテナ名
    ports:
      - "6379:6379" #redisのデフォルトのポートは6379
    volumes:
      - "./data/redis:/data"

3, 上記で作ったymlファイルがある階層で、下記を実行

$ docker-compose up -d
Creating network "redis_default" with the default driver
Creating redis_test ... done

$ docker exec -it redis_test /bin/bash

# Redisクライアントの起動
root@9e25d6b48e8c:/data# redis-cli

# 現在のkey全部の確認
127.0.0.1:6379> keys *
(empty list or set)

4, 文字列型の操作

コマンドリファレンスが分かりやすいです。

# 文字列 valueにkeyをセットする
127.0.0.1:6379> set name hoge
OK

# 指定したkeyに対応するvalueを表示
127.0.0.1:6379> get name
"hoge"
# keyに有効期限(秒数)を付けることができる(成功時は1, 失敗時は0を返す)
127.0.0.1:6379> expire name 3
(integer) 1

# 3秒後に、nameキーの値がnilになる
127.0.0.1:6379> get name
(nil)
# valueを1増やしたり、1減らしたりする
127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> incr age
(integer) 21
127.0.0.1:6379> decr age
(integer) 20
# keyの削除
127.0.0.1:6379> del age
(integer) 1
127.0.0.1:6379> keys *
(empty list or set)

参考にさせて頂いた記事

docker-composeでredis環境をつくる

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

code-server オンライン環境篇 (7) git 上のcompose を EC2上に展開する

目次
ローカル環境篇 1日目
オンライン環境篇 1日目 作業環境を整備する

オンライン環境篇 2日目 仮想ネットワークを作成する

オンライン環境篇 3日目 Boto3 で EC2 インスタンスを立ち上げる

オンライン環境篇 4日目 Code-Serverをクラウドで動かしてみる

オンライン環境篇 5日目 Docker 上で、code-server を立ち上げる

オンライン環境篇 6日目 自動化してみよう

オンライン環境篇 7日目 git 上のcompose を EC2上に展開する

...
オンライン篇 .. Coomposeファイルで構築

オンライン篇 .. K8Sを試してみる

...

魔改造篇

はじめに

前回までで、Docker を利用して、EC Instance 上に Code-Serverを立ち上げることができるようになりました。

今回は、github 上に、compose file から、EC2 Instance に立ち上げるまでをやってみます。

  • 作成
  • 停止
  • 再開
  • 削除
  • 情報取得

新規の知識はないので、茶々っと作ってみてください。
汚くて良いと思います。

成果物例

https://github.com/kyorohiro/advent-2019-code-server/tree/master/app/docker_image_uploader_for_ec2

$ git clone https://github.com/kyorohiro/advent-2019-code-server.git
$ cd advent-2019-code-server/remote_cs04/
$ docker-compose build
$ docker-compose up -d

ブラウザで、http://127.0.0.1:8443/ を開く。

Screen Shot 2019-12-24 at 0.39.23.png

Terminal 上で

Terminal
$ pip install -r requirements.txt
$ aws configure 
..
..

EC2Instance を 作成

$ python main.py --create

EC2 情報を取得

$ python main.py --get
>>>> i-0d1e7775a07bbb326
>>>> 
>>>> 3.112.18.33
>>>> ip-10-1-0-228.ap-northeast-1.compute.internal
>>>> 10.1.0.228
>>>> {'Code': 16, 'Name': 'running'}

ブラウザー でアクセス

Screen Shot 2019-12-24 at 1.11.08.png

Screen Shot 2019-12-24 at 1.06.50.png

Screen Shot 2019-12-24 at 1.12.23.png

できました!!

一時停止してみよう

$ python main_command.py --stop

EC2 Insntace を止めてます。
利用料金を安く抑えることができます。
EBS の Storage の使用量などはかかります。

再開してみよう

 python main_command.py --start

停止したものを再開できます。
IPアドレスが変わるので注意

削除しよう

# ec2 instance から logout
$ exit

# local の code-server 上で
$ python main.py --delete

次回

EC2ベースにする場合、あとは、解説するようなものはなく、作り込むだけだと思います。

ここまで出来れば、
クラウド上に、VSCode(Code-Server) を配置することは、もう出来ると思います。

VSCode に関係なく、 Docker Image 、 Composefile かした物なら何でも
クラウド上に置けますね。

次回は K8S編 or Fargate編 に入ります。
今までは自作してきましたが、
ありものを利用して、アレコレしていきます。

コード

https://github.com/kyorohiro/advent-2019-code-server/tree/master/remote_cs06

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