- 投稿日:2020-05-29T23:40:06+09:00
localに特定のdocker imageが存在しないときや、requirements.txtが変更されているときにbuildするshell script
- 投稿日:2020-05-29T23:40:06+09:00
localに特定のdocker imageが存在しないときにbuildするshell script
- 投稿日:2020-05-29T23:21:46+09:00
tiberiusを使ってRustでMSSQLに接続する
はじめに
RustからMSSQLを操作したいと思い、いい感じのcrateがないか探していました。
色々調べるとDB操作関連に関してはDieselというORMがよく使われているようでした。
https://github.com/diesel-rs/diesel「情報もある程度ありそうだしこれを使ってみよう!」
と思っていたら‥Supported databases: 1. PostgreSQL 2. MySQL 3. SQLiteだめやん‥
というわけで他の方法を探すことにしました。
tiberius
tiberiusというcrateがありました。
https://crates.io/crates/tiberiusスター数があまり多くないのは気になりますが、検証ということでとりあえずこちらを使ってみることにします。
注意
「rust tiberius」でググるとgithubのページが二つ出てくると思います。
前者が最新のリポジトリのようなので気をつけてください。
確認環境
今回はそれぞれ以下のバージョンを使用しました。
- rustc
- 1.45.0-nightly(dockerの「rustlang/rust:nightly」を使用)
- tiberius
- 0.4.0-alpha.6
- Crates.ioに公開されているバージョンを使いたかったのですが、いい感じのexampleが見つけられず現時点の最新版(2020/05/29 時点)を使っています。申し訳ありません‥
実装
ディレクトリ構造
今回作成したプロジェクトは以下の構造になっています。
├── Dockerfile ├── app │ ├── Cargo.lock │ ├── Cargo.toml │ └── target ※このディレクトリ配下は省略 │ └── src │ └── main.rs └── docker-compose.yamlそれでは一つづつみていきましょう!
Dockerfile
今回はnightlyのバージョンを使います。
FROM rustlang/rust:nightlydocker-compose.yaml
docker-compose.yamlは以下の通りです。
接続するMSSQLは公式で配布されているdocker imageを使います。また、あらかじめテスト用のデータを作成するためにアプリケーションとmssqlの他にmssqlのcliツールを使用するコンテナも作成します。
version: '3.7' services: app: build: . volumes: - ./app:/app working_dir: /app tty: true depends_on: - db db: image: microsoft/mssql-server-linux:2017-GA environment: ACCEPT_EULA: Y SA_PASSWORD: "P@ssw0rd!" volumes: - rust-mssql-data:/var/opt/mssql/ ports: - "1433:1433" mssql_cil_client: image: node:alpine tty: true volumes: rust-mssql-data: driver: localCargo.toml
「Cargo.toml」はdependenciesだけ抜粋しています。
サンプルを動かすにはtiberiusの他にも幾つか必要なcrateがあるので全て追加してください。[dependencies] tiberius = { git = "https://github.com/prisma/tiberius.git" } tokio = { version = "0.2", features = ["macros"] } anyhow = "1.0.31" futures = "0.3.5"tiberiusについては「動作確認環境」にも書きましたが最新版を使いたかったのでgithubから直接ダウンロードするようにしています。
サンプル用確認用のテーブル
サンプルを実装する前にテスト用のデータベースを作成してサンプルデータを登録しておきます。
コンテナの起動
docker-compose up -dMSSQLが起動するので、データベースやテーブルを作成します。
cli用のコンテナにログイン
docker-compose exec mssql_cil_client /bin/sh
sql-cliのinstall
npm install -g sql-climssqlにログイン
mssql -s db -u sa -p P@ssw0rd!データベースの作成
create database test; use test;テーブルの作成
create table users \ ( \ id int not null, \ name nvarchar(128), \ constraint pk_users primary key (id) \ );テストデータの登録
insert into users(id,name) values(1,'Taro'); insert into users(id,name) values(2,'Jiro'); insert into users(id,name) values(3,'Hanako');テストデータの確認
想定通りにデータが登録されているか確認しましょう!
select * from users;以下ように表示されればOKです!
id name -- ------ 1 Taro 2 Jiro 3 Hanako 3 row(s) returned Executed in 1 ms問題なければ、mssqlおよびコンテナからログアウトしましょう
.quit exit
main.rs
それでは先ほど作成したテストデータをRustから取得してみます!
以下にテーブルを作成するサンプルが格納されています。
今回はこれをベースにしました。
https://github.com/prisma/tiberius/blob/master/examples/new.rsuse tiberius::{AuthMethod, Client}; #[tokio::main] async fn main() -> anyhow::Result<()> { let mut builder = Client::builder(); builder.host("db"); builder.port(1433); builder.database("test"); builder.authentication(AuthMethod::sql_server("SA", "P@ssw0rd!")); builder.trust_cert(); let mut conn = builder.build().await?; let results = conn .simple_query("select id, name from Users;") .await? .into_results() .await?; for val in results.iter() { // 取得した件数分ループする for inner in val.iter() { // id列の情報を取得 if let Some(id) = inner.get::<i32, _>("id") { print!("id = {} ", id); } // name列の情報を取得 if let Some(name) = inner.get::<&str, _>("name") { println!("name = {}", name); } } } Ok(()) }とりあえず使ってみるだけであれば、特に難しい点はなさそうです。
resultsが2次元配列になっている理由が今ひとつわからず気になりました。細かいことは一旦気にせず上記コードを実行してみましょう!
docker-compose exec app cargo run
結果
id = 1 name = Taro id = 2 name = Jiro id = 3 name = Hanakoいい感じですね!
今回作ったサンプルは以下で公開しています。
https://github.com/shushutochako/tiberius_sampleさいごに
Rustでmssqlを操作するサンプルがあまり多くない印象で少し手こずってしまいました。
これから色々と実装例が増えてくることを切に願います(´·ω·`)他にもRustからMSSQLを操作する場合はODBCのWrapperライブラリを使う方法などもあるようです。
ODBCクレートを使用する場合はこちらの記事が非常に参考になりました。
https://setsuna-no-matataki.hateblo.jp/entry/2020/04/30/182305
ZEROBILLBANKでは一緒に働く仲間を募集中です。
ZEROBILLBANK JAPAN Inc.
- 投稿日:2020-05-29T22:34:36+09:00
Dockerを使ってHTTPS環境を構築
Dockerを使ってHTTPS環境を構築
Dockerを使ってHTTPS環境を構築出来ないかと調べていたらHTTPS-PORTALという便利なものがあったので、試しにローカルでHTTPS接続できる環境を構築してみました。
HTTPS-PORTALとは?
HTTPS-PORTAL is a fully automated HTTPS server powered by Nginx, Let's Encrypt and Docker. By using it, you can run any existing web application over HTTPS, with only one extra line of configuration.
The SSL certificates are obtained, and renewed from Let's Encrypt automatically.
要するに自動でHTTPSサーバを作ってくれるDockerコンテナです。
前提
VirtualBox(仮想OS)に以下の環境を構築。
- OS:
CentOS7
- Docker:
v19.03.10
- Docker-compose:
v1.25.25
やること
ゲストOSのdocker上に起動したMetabaseにホストOSのブラウザからHTTPSで接続する
※今回はサンプルとしてMetabase(データ分析用のWebアプリ)を使用する手順
- dockerをインストールする ※関連リンクを参照
- docker-composeをインストールする ※関連リンクを参照
- docker-compose.ymlを作成する
- docker-composeでコンテナを起動する
- VirtualBoxのネットワーク設定を行う
- ブラウザからHTTPSで接続する
docker-compose.ymlを作成する
CentOS7上の適当なディレクトリにdocker-compose.ymlを作成してください。
※今回は /var/lib/docker 直下にファイル作成しましたdocker-compose.ymlhttps-portal: image: steveltn/https-portal:1 ports: - '80:80' - '443:443' links: - metabase restart: always environment: STAGE: local DOMAINS: 'localhost -> http://metabase:3000' metabase: image: metabase/metabase volumes: - ~/metabase-data:/metabase-data environment: - MB_DB_FILE=/metabase-data/metabase.dbhttps-portalを経由してmetabaseに接続するようなイメージです。
設定内容は以下の情報を元にしています。docker-composeでコンテナを起動する
dokcer-compose.ymlのあるディレクトリにて以下のコマンドを実行してください。
# docker-composeでコンテナを起動 docker-compose up -d以下のコマンドでhttps-portalとmetabaseのコンテナが起動していることを確認できます。
# dockerの起動しているコンテナを確認 docker ps
コンテナを停止したい場合は以下のコマンドです。
# docker-composeでコンテナを停止 docker-compose stop
VirtualBoxのネットワーク設定を行う
ホストOSのブラウザからゲストOSのWebアプリに接続する為にVirtualBoxの設定をします。
ネットワーク設定にて、NATでホストOSの80, 443ポートをゲストOSの80, 443にフォワード設定します。ブラウザからHTTPSで接続する
ブラウザにて
https://localhost
を表示する
※オレオレ証明書なので上記の警告画面がでます。以下のMetabaseの初期画面が表示されていれば成功です。
あとがき
今回はお試しということでローカル用に環境構築してみました。
(未検証ですが)設定を切り替えればLet's Encryptから取得した証明書を使うようなので社内ツールなどをHTTPS化したい場合に手軽に出来て良さそうです。関連リンク
以下、環境構築の際に参考にしたサイトです
- 投稿日:2020-05-29T20:58:13+09:00
Dockerについて
前提
本日学んだことを書いていきます。
本題
コンテナとは
内部にものを貯める容器・運搬可能
容器にはアプリケーションが入っている。
自宅のPCやラップトップ、データーセンターで稼働しているサーバー
AWSやAZUREやGCPの仮想サーバーへ持ち運び、アプリケーションを実行することができる。従来の技術モデル
アプリケーションが実行される環境が変わってきている。
一つのハードウェアに一つのOSがあり複数のアプリケーションをインストールして使用する。
このような形が従来型のアプリケーションの実行環境。
少々リソースに無駄があり、コストが高くつくのが難点。仮想化技術
ハードウェア、OSについては同様。
ハイパーバイザーというシステムをインストール(VMWereやXen、Hyper-V)。
ハイパーバイザーにWindowsやLinuxなどのOSをインストールし、仮想的に一台のサーバーを実行できる(Virtual Server)
ハイパーバイザーは複数のバーチャルサーバを実行することができ、EC2などの仮想サーバーもバーチャルサーバとして実行されている。メリット
OS丸ごとのバックアップの取得が簡単。
コンテナ
ハードウェアやOSは同様。
コンテナエンジン、コンテナデーモンをインストール。(Dockerが一番有名)
コンテナ同士は独立しており、互いに鑑賞することはない。
それぞれの実行環境がコンテナという一つの容器にまとまっている形をイメージ。なぜ軽量なのか
コンテナのOSと異なっていてもLinuxのカーネルは互換性があるため互換性の範囲内であればアプリケーションは動作できる。
→コンテナはLinuxイメージが動作しているLinuxイメージ = filesystem / libraries
OS = filesystem / libraries + kernel
それぞれのコンテナ(RedhatやSuze、Ubuntu)はホストOSのカーネルを共有しており、カーネルまで含めて仮想化しているバーチャルサーバと比べて動作が軽量。コンテナのライフサークル
・Dockerデーモンをホストマシンにインストール
→コンテナイメージを実行したり、ネットワーク周りを管理したり、コンテナ全般の管理を行うもの・Dockerclientをインストール
→デーモンに対して指示を出す役割のもので、デーモンに対してビルドやコマンドやランコマンドを実行したりする。・Registry
Dockerイメージを保管する領域。
DockerHubが有名。
AWSではECR、Elastic Container RegistryというプライベートなDockerイメージのアップロード場所をサービスとして提供している。Dockerclientが
Run
コンマンドをデーモンに対して実行。
↓
デーモンは場合によってRegistryからコンテナイメージをダウンロードし、コンテナとして実行。
※buildコマンドでどのようなコンテナイメージを作成するかによるコンテナの人生
DockerHubなどのコミュニティにある様々なコンテナ
↓
自分のパソコン(Dockerclient)にpull
↓
行いたい作業に合わせて編集しDockerHubなどのコミュニティ(Registry)にpush
↓
Dockerデーモン(ホスト)に対してRunコマンドを実行
↓
DockerデーモンはRegistryよりイメージをダウンロード
↓
コンテナの実行
- 投稿日:2020-05-29T19:00:23+09:00
Qiitaのトレンド情報を保存しておくDocker環境を作ろう!
Qiitaのトレンド情報を保存しておく環境をDockerで作成しました。
基本的にコンテナを立ち上げていれば、毎日勝手にスクレイピング処理が走り、JSON化したトレンド情報を保存してくれます。この記事は以下のような方におすすめです。
- Qiitaのトレンドを分析しておきたいな
- Pythonの勉強を少しやってみたいな
- Dockerちょっと触ってみたい
※保存しておくQiitaのJSONフォーマットについて
- author(トレンド入りした著者の一覧
- list(トレンド記事の一覧
- tag(トレンドの記事に付けられたタグ一覧
実際に保存しておくJSONの中身は以下のようになっています。
author
: Qiitaにトレンド入りした著者を取得する著者のユーザーネームを一覧化。
[ "uhyo", "suin", "Yz_4230", "atskimura", "pineappledreams", "Amanokawa", "k_shibusawa", "minakawa-daiki", "morry_48", "c60evaporator", "takuya_tsurumi", "TomoEndo", "yhatt", "CEML", "moritalous", "svfreerider", "daisukeoda", "karaage0703", "tommy19970714", "tyru", "galileo15640215", "keitah", "mocapapa", "akeome", "ssssssssok1", "yuno_miyako", "katzueno", "cometscome_phys", "mpyw", "akane_kato" ]
list
: Qiitaにトレンド入りした記事の一覧を取得する以下の情報を出力します。
- 記事のUUID(記事のID)
- 記事のタイトル
- 記事のURL
- 記事の著者名
- LGTM数
- 記事に付けたれたタグ, タグURL
[ { "article_id":"e66cbca2f582e81d5b16", "article_title":"Let's Encryptを使用しているウェブページをブロックするプロキシサーバー", "article_url":"https://qiita.com/uhyo/items/e66cbca2f582e81d5b16", "author_name":"uhyo", "likes":66, "tag_list":[ { "tag_link":"/tags/javascript", "tag_name":"JavaScript" }, { "tag_link":"/tags/node.js", "tag_name":"Node.js" }, { "tag_link":"/tags/proxy", "tag_name":"proxy" }, { "tag_link":"/tags/https", "tag_name":"HTTPS" }, { "tag_link":"/tags/letsencrypt", "tag_name":"letsencrypt" } ] }, { "article_id":"83ebaf96caa2c13c8b2f", "article_title":"macOSのスクリーンセーバーをHTML・CSS・JSで作る (Swiftスキル不要)", "article_url":"https://qiita.com/suin/items/83ebaf96caa2c13c8b2f", "author_name":"suin", "likes":60, "tag_list":[ { "tag_link":"/tags/html", "tag_name":"HTML" }, { "tag_link":"/tags/css", "tag_name":"CSS" }, { "tag_link":"/tags/javascript", "tag_name":"JavaScript" }, { "tag_link":"/tags/macos", "tag_name":"macos" } ] } ]Qiitaのトレンドは1日に2回、毎日5時/17時に更新更新されていますが、そこまで記事の入れ替わりはないので1日1回だけの実行にしておこうと思います。
tag
: Qiitaにトレンド入りした記事に付けられたタグを取得する[ { "tag_link":"/tags/python", "tag_name":"Python" }, { "tag_link":"/tags/r", "tag_name":"R" }, { "tag_link":"/tags/%e6%a9%9f%e6%a2%b0%e5%ad%a6%e7%bf%92", "tag_name":"機械学習" } ]上記の記事の一覧でもタグは取得していますが、一個の記事に紐付けられたタグなので、異なる記事で同じタグが付いていた場合重複してしまいます。そのため、重複したタグを省いてトレンド入りしたタグだけ一覧で保存しておく処理にしました。
DockerでPythonが実行できる環境を作成しよう
簡易的なDocker環境を作成していきます。
ディレクトリ構成は以下のような感じ。├── batch │ └── py │ └── article.py ├── docker │ └── python │ ├── Dockerfile │ ├── etc │ │ └── cron.d │ │ └── qiita │ └── requirements.txt ├── docker-compose.yml └── mnt └── json ├── author ├── list └── tag
batch
directory
pythonファイルを置いています。
このファイルがスクレイピングを行う実ファイルです。
docker
directory
コンテナの内部で必要なものだったり、実際のcron設定はここで置いています
mnt
directory
host上のディレクトリをマウントしていて、ここにスクレイピングの結果JSONファイルが生成されますQiitaのトレンドをスクレイピングで取得しよう (
batch directory
)batchディレクトリの中にある実ファイル
article.py
の中身です。
過去にこんな記事を書いていたので、詳しいやり方とかはそっちで解説しています。
≫ Qiitaのトレンド(ランキング)を取得してSlackに送信する
この記事ではあくまでプログラムだけにします。上記の記事のプログラムとの相違点は以下の2点です。
記事の一覧だけ欲しいねん!って人は上記の記事だけで事足りると思います。
- トレンド入りした記事のタグと著者を取得
- 取得した内容をJSON化して保存しておく
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup import json import datetime import os def get_article_tags(detail_url): tag_list = [] res = requests.get(detail_url, headers=headers) # htmlをBeautifulSoupで扱う soup = BeautifulSoup(res.text, "html.parser") tags = soup.find_all(class_="it-Tags_item") for tag in tags: tag_name = tag.get_text() tag_link = tag.get('href') tag_list.append({ 'tag_name' : tag_name, 'tag_link': tag_link }) return tag_list def write_json(json_list, path): with open(path, 'w') as f: f.write(json.dumps(json_list, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ':'))) def mkdir(path): os.makedirs(path, exist_ok=True) def get_unique_list(seq): seen = [] return [x for x in seq if x not in seen and not seen.append(x)] def get_unique_tag(tag_lists): tags = [] for v in tag_lists: for i in v: tags.append(i) return tags try: # Root URL url = "https://qiita.com/" headers = { "User-Agent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1" } today_date = datetime.datetime.now().date() items = [] item_json = [] result = [] res = requests.get(url, headers=headers) # htmlをBeautifulSoupで扱う soup = BeautifulSoup(res.text, "html.parser") try: main_items = soup.find(class_="p-home_main") for main_items in soup.find_all(): if "data-hyperapp-props" in main_items.attrs: item_json.append(main_items["data-hyperapp-props"]) items = json.loads(item_json[1]) except: raise Exception("Not Found Json Dom Info") if 'edges' not in items['trend']: raise Exception("The expected list does not exist") try: item_detail_list = [] tags_list = [] author_list = [] for edges in items['trend']['edges']: uuid = edges['node']['uuid'] title = edges['node']['title'] likes = edges['node']['likesCount'] article_url = url + edges['node']['author']['urlName'] + '/items/' + uuid author_name = edges['node']['author']['urlName'] create_at = datetime.datetime.now().date() tag_list = get_article_tags(article_url) item = { 'article_title' : title, 'article_url' : article_url, 'article_id' : edges['node']['uuid'], 'likes' : likes, 'uuid' : uuid, 'author_name' : author_name, 'tag_list' : tag_list, } item_detail_list.append(item) tags_list.append(tag_list) author_list.append(author_name) mkdir('/mnt/json/list/') mkdir('/mnt/json/tag/') mkdir('/mnt/json/author/') # タグをuniqu化 tags_list = get_unique_tag(tags_list) # jsonファイルを書き出し write_json(item_detail_list, f"/mnt/json/list/{today_date}.json") write_json(tags_list, f"/mnt/json/tag/{today_date}.json") write_json(author_list, f"/mnt/json/author/{today_date}.json") except: raise Exception("Can't Create Json") except Exception as e: # jsonファイル作成失敗 mkdir('/mnt/log/') with open(f'/mnt/log/{today_date}', 'w') as f: f.write(e)次に上記のファイルを実行する環境を作成します。
Pythonを動かすためのDocker部分を作成(
docker directory
)docker-compose.ymlの作成
ここは大したことしてない。
volumesでPC上のディレクトリとマウント。version: "3" qiita_batch: container_name: "qiita_batch" build: context: ./docker/python tty: true volumes: - ./batch:/usr/src/app - ./mnt:/mntDockerfileの作成
Dockerfile汚いのは許して...軽く説明だけ↓
- コンテナ内のタイムゾーンの設定(cron設定のため
- cronを反映
- requirement.txtで必要なモジュールをインストール
cronをちゃんと指定した日本時間で実行したいのであれば、タイムゾーンの設定は必須ですね。
なんかごちゃごちゃやって、ようやく日本時間に変えられたんですが、もっとうまいやり方あるはず...。cronの設定はetc/cron.d/qiitaにまとめておいて、後々crontabに書き込むような処理にしてます。管理が楽になるのでこっちの方がいいかなと。間違っても
crontab -r
というコマンドは呼び出してはいけない...!!FROM python:3 ARG project_dir=/usr/src/app WORKDIR $project_dir ADD requirements.txt $project_dir/py/ ADD /etc/cron.d/qiita /etc/cron.d/ ENV TZ=Asia/Tokyo RUN apt-get update && \ apt-get install -y cron less vim tzdata && \ rm -rf /var/lib/apt/lists/* && \ echo "${TZ}" > /etc/timezone && \ rm /etc/localtime && \ ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ dpkg-reconfigure -f noninteractive tzdata && \ chmod 0744 /etc/cron.d/* && \ touch /var/log/cron.log && \ crontab /etc/cron.d/qiita && \ pip install --upgrade pip && \ pip install -r $project_dir/py/requirements.txt CMD ["cron", "-f"]Pythonの実行に必要なパッケージをまとめたrequirement.txtを作成
requirement.txtは自分のMacbookProで使用していたものを出力しただけなので、かなり適当に色々なものが入っています。いらないものは適宜削ってくださいまし。
beautifulsoup4
とrequests
とjson
だけあれば事足ります。なんか足らん!って人は動かしながら足らないやつpip install!!appdirs==1.4.3 beautifulsoup4==4.8.1 bs4==0.0.1 certifi==2019.9.11 chardet==3.0.4 Click==7.0 filelock==3.0.12 get==2019.4.13 gunicorn==20.0.4 idna==2.8 importlib-metadata==1.5.0 importlib-resources==1.0.2 itsdangerous==1.1.0 Jinja2==2.11.1 MarkupSafe==1.1.1 post==2019.4.13 public==2019.4.13 query-string==2019.4.13 request==2019.4.13 requests==2.22.0 six==1.14.0 soupsieve==1.9.5 urllib3==1.25.7 virtualenv==20.0.1 Werkzeug==1.0.0 zipp==2.2.0cron設定
/etc/cron.d/qiita
の中身ですPATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=ja_JP.UTF-8 # Create Qiita JSON (every day AM:10:00) 0 10 * * * python /usr/src/app/py/article.py >> /var/log/cron.log 2>&1こんな感じ!
あとはdocker-compose up -d
でやれば立ち上がるので、放置しておけば勝手にQiitaにスクレイピングしに行ってjsonファイルを作成してくれます。簡易的なDocker環境で出来るのでおすすめ!
- 投稿日:2020-05-29T18:28:45+09:00
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 Rails 本番環境でDBデータを消す方法
現在、ポートフォリオを作成している途中のゆーた(@onoblog)です。
ポートフォリオフォリオにこんな感じで、複数のタグを選択して検索する機能を実装しました。
本番環境で、段階的に、デプロイしているポートフォリオに、タグを追加したいとなり、seedファイルを編集し、データベースを一回消して追加してみたときのエラーをまとめます。
環境
- rails 5.2.3
- carrierwave
- fog-aws
- jquery-rails (4.3.5)
- vue/cli 4.1.2
- yarn 1.21.1
- webpacker (5.0.1)
- Docker 19.03.5
- docker-compose 1.25.2
- nginx 1.15.8
対処法
ローカル環境と同じように、DBを削除する方法。
#ターミナルにて # Dockerの方 $ docker-compose -f staging.yml run app rails db:drop DISABLE_DATABASE_ENVIRONMENT_CHECK=1 # 通常コマンド $ rails db:drop DISABLE_DATABASE_ENVIRONMENT_CHECK=1 $ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop原因
Rails5から本番環境では、通常消すことがないように、防止処理が働いているようです。
参考
- 投稿日:2020-05-29T18:24:19+09:00
超基礎からの 速習 Docker (4)
本稿は、Christffer Noring さん (@chris_noring) の Learn Docker, from the beginning, part IV を翻訳し、分かりやすいように少しだけ追記、サンプルコードの実行上の補足等を行ったものです。シリーズ翻訳の意図については 超基礎からの 速習 Docker (1) の冒頭に掲載しています。併せてご参照くださいませ。
Twitter をフォローして、トピックへのあなたの問い合わせやご質問、提案を頂けるとハッピーです。
超基礎からの 速習 Docker シリーズ一覧
この文章はシリーズの一つです:
- 超基礎からの 速習 Docker (1)
- なぜ Docker なのか、コンテナーやイメージ、Dockerfile の基本コンセプトの解説、もちろん、それらを管理するのに必要なコマンド群もカバーしています。
- 超基礎からの 速習 Docker (2)
- Volume を用いたデータの永続化や、開発環境の Volume 化を通じて、開発をより手軽なものにします。
- 超基礎からの 速習 Docker (3)
- データベースをコンテナ化し、レガシーなやり方及び新しいやり方である Network を用いて他のコンテナから連絡可能にします。
- 超基礎からの 速習 Docker (4)
- いまここ。
- 超基礎からの 速習 Docker (5)
- Docker Compose を用いた複数サービスの管理方法を解説します(その2)
このパートでは、複数の Docker コンテナーの扱いについて述べます。やがてはたくさんのコンテナーを持ってしまって、すべてを管理できないと感じるようになるはずです。docker run を入力し続けるのは一定のポイントまでで、複数のコンテナを起動し始めると、すぐに頭と指が痛くなります。
TLDR; Docker Compose は巨大なトピックです。そんなわけで、二つのパートに分けました。このパートでは、なぜ Docker Compose で、いつそれは輝くのか説明します。続編では、Docker Compose について、環境変数、Volume、データベースと言った、より高度なトピックについてカバーします。
このパートでカバーしているのは:
- なぜ Docker Compose? Docker Compose の理解には重要です。ハイレベルには最低でも、二つの主要なアーキテクチャ、Monolith と Microservice があり、Docker Compose は Microservice をきちんとサポートします。
- 機能 Docker Compose がどんな機能をサポートし、なぜ、そんなに Microservice にフィットするのか、理解してもらいます。
- Docker が十分じゃないとき Docker コマンドを使うことがつまらなくて苦痛になる個所と、もっともっと魅力的に見え始める時がいつかについて説明します。
- アクション 最後に、スクラッチから docker-compose.yaml をビルドして、Docker Compose を使ったコンテナーの管理といくつかコア コマンドについて学びましょう。
リソース
Docker を使う事、コンテナー化は、一枚岩をマイクロサービスに分解していくことです。このシリーズのいたるところで僕らは Docker やそのコマンド体系をマスターするために学ぶことになります。そうすれば、きっと君は自作のコンテナーをプロダクション環境で使いたくなるでしょう。その環境は大抵クラウド上にあります。十分な Docker 経験を積んだと思ったなら、次のリンクで Docker をクラウドでどのように活用できるか、ご確認してみると良いと思います。
- Azure 無料アカウントのサインアップ プライベート レジストリのようなクラウドのコンテナーを使うには、無料 Azure アカウントが必要でしょう。
- クラウドのコンテナー クラウドのコンテナーについて他に知っておくべきことについて網羅する概要ページです。
- 自作コンテナーをクラウドにデプロイ 今の Docker スキルをレバレッジしてクラウド上でサービスを動かすことがいかに簡単かを示すチュートリアル。
- コンテナー レジストリの作成 自作 Docker イメージを Docker Hub に入れられますが、クラウドのコンテナー レジストリも可能です。自作イメージをどこかにストアして、一瞬でレジストリから実際のサービスをできるようにすることは凄くないですか?
なぜ Docker Compose?
Docker Compose は多くのサービスを個別に管理する必要がある時に使われます。これから話すことは Microservice アーキテクチャと言われるものです。
Microservice アーキテクチャ
このアーキテクチャの特徴を定義していこう。
- 疎結合 (訳注:疎結合の原文は Loosely coupled、緩くカップルになってる感じ)、これは他のサービスの機能に依存せず、必要なデータがそのままそこにあるということです。それらは他のサービスに影響しあえますが、HTTP コールのような外部 API 呼び出しで実現しています。
- 個別にデプロイ可能 他のサービスに直接影響することなく、スタート、ストップ、リビルドできることを意味します。
- 高いメンテナンスとテストが可能 それぞれサービスが小さいため、理解が容易で、お互いに依存しないため、テストがよりシンプルです。
- ビジネス ケーパビリティと共にある 異なるテーマを見つけて試せることを意味します。ブッキングだったり、プロダクト管理だったり、会計だったり・・
なぜ僕らはこのアーキテクチャにしたいのか?という問いから始めましょう。上の特徴リストからも明らかであるように、高いフレキシビリティや、依存度がない点などがあります。それは良いことに聞こえますが、全てのアプリが持っているべき新しいアーキテクチャなのでしょうか。
そういうことは常にモノに依ります。モノリシックなアーキテクチャに対してMicroserviceが輝くかどうかは基準があります:
- 異なる技術スタック/新しい技術 多くの開発チームがあって、それぞれが自身の技術スタックあmたはすべてのアプリを変更するわけではなく、新しい技術を試したい。各チームは自分で選んだ技術を、Microservice アーキテクチャの一部としてサービスをビルドしましょう。
- 再利用 「会計」と言った、一つのケーパビリティをビルドしたい場合、一つの個別のサービスに分解すれば、他のアプリケーションへの再利用が容易になります。Microservice アーキテクチャでは、異なるサービスを組み合わせたり、そこから多くのアプリを作り出すことが良いです。
- 最小の失敗インパクト モノシリック アーキテクチャで失敗があると、アプリ全体が落ちてしまうかも知れません。Microservice なら、失敗からできるだけ守ることができます。
なぜ Microservice がモノリシック アーキテクチャを超えるのかについてはたくさんの議論があります。ご興味があれば、こちら のリンク先をお勧めします。
Docker Compose の事例
Microservice アーキテクチャの記述は、ビジネス ケーパビリティと共にあるサービス群が必要であることを教えてくれます。更に言うなら、個別にデプロイ可能で、異なる技術スタックや更に多くを使うことが可能である必要があるということです。私の意見としては、これは Docker がとても汎用的にフィットしているように聞こえます。Docker を超えて Docker Compose の事例を作る理由は、そのサイズにあります。もし、僕らが二つ以上のコンテナーを持っていたなら、僕らがタイプしなくちゃならないコマンドの数は突然線形に増えていく。次のセクションでは、たくさんのサービスが増えた時、どんな Docker Compose 機能がスケールできるのか、解説しましょう。
Docker Compose 機能概要
Docker Compose は簡単にいくつかのイメージを一度に簡単にビルドしたり、いくつかのコンテナーその他のものを一度に起動できるという意味で、非常に優れたスケーリングが可能になりました。機能の一覧は以下の通りです:
- Manages アプリのライフサイクル全体を管理
- Start、Stop、リビルド
- View サービス実行のステータスを参照
- Stream 実行サービスの log 出力を確認
- Run 一度のコマンドでサービスを実行
見ての通り、多くのサービスで構成されている microservice アーキテクチャを管理する必要があるとき、必要のある可能性のあるすべてを提供しています。
素の Docker では十分じゃないとき
Docker がどのように操作し、どんなコマンドが必要だったか、サービスが一つ二つ追加するときについて見てみましょう。
- Dockerfile の定義 OS イメージ、インストールするライブラリ、環境変数、開くべき Port、最後にサービス起動の方法
- イメージのビルド または Docker Hub からイメージを引っ張ってくる
- コンテナーの生成と実行
Docker Compose でも Dockerfile が一部必要ですが、Docker Compose はイメージをビルドし、コンテナーを管理します。プレーン Docker の場合のコマンドをお見せしましょう:
docker build -t some-image-name .
続いて、
docker run -d -p 8000:3000 --name some-container-name some-image-name
書くのに大変な量と言うわけではないですが、これを行う必要のある 3つの異なるサービスを持っている場合を想像してみてください。突然6つのコマンドまで増えます。さらに、終了用にコマンドが2つ増えます。これはほんとスケールしない。
docker-compose.yaml を書く
ここは本当に Docker Compose が輝いているところ。ビルドしたいサービス毎に二つのコマンドをタイプする代わりに、プロジェクトの全てのサービスを一つのファイル
docker-compose.yaml
で定義できます。docker-compose.yaml
ファイルの中では以下のトピックを設定できます。
- Build ビルド内容と 標準的な名前とは異なるべきである Dockerfile の名前を特定できます。
- Environment 多くの必要な環境変数を定義し、値を設定できます。
- Image スクラッチからイメージをビルドする代わりに、Docker Hub から引っ張ってきて自身のソリューションに使える、Ready-made イメージを定義します。
- Networks Network を作成し、もし必要であれば、各サービスがどのネットワークに属しているべきかを特定できます。
- Ports コンテナー内部のどのポートが、どの外部ポートにあたるか、ポート フォワーディングを定義できます。
- Volumes もちろん、Volume も定義できます。
Docker Compose の実行
OK、ここまでで、Docker Compose がコマンドラインでできることならなんでも行うことができ、何を実行するのか知るには
cocker-compose.yaml
ファイルに依存していることをご理解頂けたかと思います。docker-compose.yaml をはじめよう
実際にファイルを作ってみて、解説を加えましょう。最初に典型的なプロジェクト ファイルの構造について簡単にレビューしましょう。以下は二つのサービスを構成するプロジェクトで、それぞれディレクトリを持っています。それぞれのディレクトリは、サービスをどうビルドするかを指定した
Dockerfile
があります。訳注
本章のハンズオンで実際に触るのは、docker-compose.yaml だけで、各イメージやコンテナーを作るソースコードと設定ファイルが提示されていません。パート 5 では、GitHub からそれらサービス用コードをダウンロードしてのハンズオンとなっていますので、本章は「まあ、そんなものか」と読み進んで頂くのが良いかなと思います。こんな感じになっています:
docker-compose.yaml /product-service app.js package.json Dockerfile /inventory-service app.js package.json Dockerfile上記で注目すべきは、プロジェクトのルートに
docker-compose.yaml
ファイルを作成するというやり方です。そのようにする理由は、ビルドするすべてのサービスについて、どのようにビルドするか、どのようにスタートするかが一つのファイルdocker-compose.yaml
に定義されているからです。OK、docker-compose.yaml
を開いて、最初の1行を入力しましょうj:docker-compose.yamlversion: '3'ここで何を指定するかは実際重要です。現在、Docker は 3つの異なるメジャー バージョンをサポートしています。3 は最も新しいバージョンで、各バージョンでの違いとそれに付随する異なる機能とシンタックスについては、 official docs をご覧ください。
docker-compose.yamlversion: '3' services: product-service: build: context: ./product-service ports: - "8000:3000"OK、一度にたくさんあるので、ブレイク ダウンしていきましょう:
- services: docker-compose.yaml ファイル全体の中で一つだけあります。
:
で終わっているやり方にも注意ください。これが必要な場合は有効な構文ではあります。そのことはコマンド一般に言えます。- product-service: サービス名として任意で選択した名前。
- build: Docker Compose がどのようにイメージを build するかの指定。もし既に Ready-made イメージを持っている場合はこれを指定する必要はありません。
- context: Dockerfile がどこにあるかを Docker Compose に伝えるために必要です。このケースでは、product-service ディレクトリ以下にあります。
- ports: これはポート フォワーディングで、最初に外部ポート、次に内部ポートを指定します。
これ全ては以下の二つのコマンドに対応します。
docker build -t [default name]/product-service . docker run -p 8000:3000 --name [default name]/product-serviceええっと、そりゃだいたいあってるけど、まだ イメージのビルド実行や、コンテナーの作成と実行をする Docker Compose についてちゃんと話してない。どのように開始してどのようにイメージをビルドするかについて学習しましょう。
docker-compose build
上記で docker-compose.yaml 内で定義したシングル サービスをビルドします。コマンドの実行結果を見てみましょう。
上の内容では、イメージをビルドし、最後の行で
compose-experiments_product-service:latest
と言うフルネームが与えられていることが分かります。名前はディレクトリー名compose-experiments
からつけられ、他の部分はdocker-compose.yaml
ファイルから与えられます。OK、以下のようにタイプして起動しましょう:
docker-compose up
これによって docker-compose.yaml が再度読み込まれますが、今度はコンテナーを作成・実行します。バックグラウンドでコンテナーを実行したい場合、
-d
フラグをつけて呼び出します。フルコマンドは:
docker-compose up -d
OK、上記でサービスが生成されました。
docker ps
を実行して新しく作られたコンテナーを確認しましょう:どうやら 8000 ポートで実行されていますね。確認してみましょう:OK、ターミナルからコンテナーを作れれたことを確認できました。docker stop と docker kill でコンテナーを終了できることを知っていますが、docker-compose ではどうやるでしょう:
docker-compose down
上記コマンドのログで、コンテナーの停止と削除が分かり、
docker stop [id]
とdocker rm [id]
の両方が行われているらしい。いけてる もしやりたいことがコンテナーの停止なら、次のようにするべきだ:
docker-compose stop
君のことは知らないけど、僕は
docker build
、docker run
、docker stop
、docker rm
を使って停止の準備ができた。Docker Compose はすべてのライフサイクルをサポートしているように見えますDocker Compose アピール
ここまでを復習しましょう。Docker Compose は僕らのためにサービス管理の全ライフサイクルをケアしてくれます。最もよく使う Docker コマンドとどれが Docker Compose のコマンドが対応するかリストしましょう:
docker build
はdocker-compose build
になり、Docker Compose の方は、docker-compose.yaml
にあるすべてのサービスをビルドできます。シングル サービスでもビルドできるため、よりきめ細かい制御が可能となります。docker build + docker run
はdocker-compose up
になり、一度に多くのことができます。もし、事前にイメージがビルドされていない場合、ビルドは自動的に行われ、イメージからコンテナーが生成されます。docker stop
はdocker-compose stop
になり、Docker Compose の方はすべてのコンテナーを停止させることも、またはパラメータを与えれば特定のコンテナーを停止することもできます。docker stop && docker rm
はdocker-compose down
になり、最初コンテナーをすべて停止し、その上でコンテナーすべてを削除することで、終了させます。これにより僕らは新たにスタートすることが可能です。以上はそれ自身すごいことですが、もっとすごいことはソリューションの拡張し続けることや、サービスを更にさらに追加することが容易であることです。
ソリューションをビルドする
他のサービスを追加して、それが如何に簡単で、以下にスケールしやすいか見て行きましょう。以下が必要です:
- add docker-compose.yaml に新しいサービス エントリーを追加します。
- build
docker-compose build
でイメージをビルドします。- run
docker-compose up
docker-compolse.yaml
ファイルを見てみましょう。必要な情報を次のサービスのために追加しましょう。docker-compose.yamlversion: '3' services: product-service: build: context: ./product-service ports: - "8000:3000" inventory-service: build: context: ./inventory-service ports: - "8001:3000"OK、それじゃあ、新しいサービスを含んだコンテナー達を up して、実行しよう。
docker-compose up
待って、
docker-compose build
するんじゃない?ええっと、実際いらないよ。docker-compose up
が僕らがやるすべてで、イメージのビルド、コンテナーの作成と実行を行ってくれます。注意、そんなに単純じゃありません。事前にイメージがない場合、最初は build + run として実行されます。ですが、もしサービスが変更されたなら、リビルドが必要で、その場合は
docker-compose build
を最初に行ってからdocker-compose up
する必要があります。サマリー
Docker Compose をカバーする最初の半分に来ましたが、とっても内容は多いですね。Docker Compose の背後のモチベーションと Microservice アーキテクチャについて簡単に説明しました。さらに、Docker VS Docker Compose について話し、最後に、Docker Compose と素の Docker との対比と比較ができました。それによって、Docker Compose を使うことと
docker-compose.yaml
ファイルですべてのサービスを特定することで、如何に簡単になるかを見せることができていればと思います。Docker Compose にはさらに、環境変数、Network、Database のようなことがあると言いましたが、それらは次のパートです。
- 投稿日:2020-05-29T18:21:02+09:00
WebStorm + node + dockerでデバッグ
こちらの記事の方法で、WebStormでも問題なく実施、感謝
https://qiita.com/silverbirder/items/ec6d7b61cc61d95011891 引数 --inspect=0.0.0.0:9229 を付けて、docker上でアプリ起動
dockerでもdocker-composeでも特に変わらず
9229ポートを開けておくのを忘れずに2 デバッグの構成、Attach to Node.js/Chrome を構成、ポートに9229を設定
3 dockerが動いてる状態で、デバッグ実行
- 投稿日:2020-05-29T18:10:37+09:00
dockerでマルチドメインのWebサーバー構築(�https-portal+php-apache+mysql+phpmyadmin)
目的
最近Dockerを自学しました、忘れないようにもの作りをしたい。
やりたいこと
docker-composeで以下のWeb環境を作りたい。
- Webサーバー:
- php+apache2
- 複数のドメイン
- https対応
- DBサーバー:
- mysql
- phpMyadmin
Dockerの勉強
お世話になったサイトを紹介します!
1. https://knowledge.sakura.ad.jp/13265/
いつもお世話になったさくらのナレッジにある記事です。結構簡単に分かりやすく書いている文書です。
入門として最初これを読んで見た方がいいでしょう
http://docs.docker.jp/
Docker 公式日本語サイトです。内容が多いですが、ざっくりと読みました。内容としてはちょっと古いところがあるんですが、入門には全然問題ない。https://youtu.be/RppfZGuLsmA
次はYoutubeのビデオです。インド人作られた内容です。英語はなかなか慣れていないため、Youtubeの字幕を見ながら内容を見覗きました。今回の内容で使うDockerイメージ
SteveLTN/https-portal
https-portalはhttps のリクエストを受け取り、他のコンテナの http へ転送するリバースプロキシとして動作する nginx です。
php:5.6-apache
Webサーバーを構築するイメージですが、php7もあるが、今回試験の目的で一旦php5.6を選択した。
phpmyadmin/phpmyadmin
Mysqlデータベースを管理するため、phpmyadminも入れておきたい。
docker-compose.ymlの設計
さっそくですが、docker-compose.ymlの中身を覗きます。
version: '3' services: web: image: php:5.6-apache container_name: php56-apache-web volumes: - "./html:/var/www/html" - "./apache.conf:/etc/apache2/sites-enabled" #ports: # - "8080:80" networks: docker-net-001: aliases: - example-site1.jp - example-site2.jp https-portal: image: steveltn/https-portal ports: - 80:80 - 443:443 restart: always environment: STAGE: local DOMAINS: 'example-site1.jp -> http://example-site1.jp, example-site2.jp -> http://example-site2.jp' networks: - docker-net-001 mysql: image: mysql:5.7 container_name: php56-apache-mysql volumes: - "./.data/mysql:/var/lib/mysql" restart: always environment: MYSQL_ROOT_PASSWORD: rootpwd@12345 # MYSQL_DATABASE: wordpress # MYSQL_USER: wordpress # MYSQL_PASSWORD: wdpwd@12345 networks: - docker-net-001 phpmyadmin: image: phpmyadmin/phpmyadmin container_name: php56-apache-phpmyadmin environment: - PMA_HOST=php56-apache-mysql ports: - "3333:80" networks: - docker-net-001 networks: docker-net-001:確認ポイント
Webサーバーでは、マルチドメインを運用するので、Apacheでは、ドメイン名でバーチャルサイトを設定しています。
詳しくはapache.conf/example-site1.jp.confを参考してください。
なので、Webサーバにドメインごとにアクセスできるように設定する必要があるので、以下のようにNetworkでaliasでドメイン名ごとに定義します。web: .... networks: docker-net-001: aliases: - example-site1.jp - example-site2.jpこれで、https-portalでドメインごとにWEBのコンテナに設定します。
https-portal: ... environment: STAGE: local DOMAINS: 'example-site1.jp -> http://example-site1.jp, example-site2.jp -> http://example-site2.jp'mysqlとphpmyadminは特に工夫せずに大体同じサンプルコードを使っていました。
最後
今回作ったサンプルは以下のURLから参考してください。
https://github.com/lzs0627/docker-sample01
- 投稿日:2020-05-29T13:39:31+09:00
Dockerでエラー Couldn't connect to Docker daemon. You might need to start Docker for Mac.
./scripts/start.shで開発環境を開始しようとしたのですが、
ERROR: Couldn't connect to Docker daemon. You might need to start Docker for Mac.このようなエラーが出ました。
Macの上のバーを見ると クジラがいない!
再起動するとDockerが落ちることがあったので、立ち上げると成功しました。
エラーが出たら再起動する、アプリが立ち上がっているか確かめる、バージョンを確かめる
鉄則ですね!
- 投稿日:2020-05-29T13:22:07+09:00
[Rails6]webpacker-dev-serverがheap out of memory(OOM)エラーで落ちる時の対処方法
RailsでWebpackerを用いフロント開発していたところ、
webpacker-dev-serverがやたらとメモリを食い「heap out of memory」エラーが頻出していました。Docker環境だからか、VM上でDockerを立てていたからか、仕様かわかりませんが、
最大メモリサイズを指定することでエラーがほぼ出なくなったので、同様の現象が起きている方は参考にしてみてください。rails 6.0.3.1 ruby 2.6.6 webpacker 5.1.1 フロント:React(bin/webpack-dev-server利用) サーバー:Rails結論
bin/webpack-dev-server
に最大のメモリサイズを渡すと、最大メモリに近づいた時にメモリ解放を行ってくれました。
NODE_OPTIONS
の環境変数に--max-old-space-size=3072
を加えると最大メモリサイズを設定することができます。bin/webpack-dev-server#... ENV["NODE_OPTIONS"] ||= "--max-old-space-size=3072" #...参考: Rails5.1のbin/webpacker-dev-serverでJavaScript heap out of memoryが起きた時の対処方
解説
開発はDockerを用いています。
Rails ServerとWebpackerを分けて、composeで管理をしています。docker-compose.ymlversion: '3' services: db: image: postgres:11.6-alpine volumes: - db:/var/lib/postgresql/data:cached networks: - web environment: TZ: Asia/Tokyo webpacker: build: . command: ./bin/webpack-dev-server volumes: - .:/app:cached - bundle:/usr/local/bundle:cached - yarn:/node_modules:cached ports: - '3035:3035' networks: - web environment: NODE_ENV: development RAILS_ENV: development WEBPACKER_DEV_SERVER_HOST: 0.0.0.0 web: build: . command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/app:cached - bundle:/usr/local/bundle:cached - yarn:/node_modules:cached ports: - '3000:3000' depends_on: - db - webpacker networks: - web tty: true stdin_open: true environment: WEBPACKER_DEV_SERVER_HOST: webpacker volumes: db: bundle: yarn: networks: web:webpack-dev-serverを立てている状態でフロント部分を開発していると、JSを更新すると自動コンパイルされます。
コンパイル内容をメモリに格納していくようで、開発を進めていると更新の度にどんどんメモリが圧迫されます。LIMITを超えたタイミングで「heap out of memory」エラーが発生しDockerを再起動する必要があります。(メモリを開放する)
Dockerのメモリ使用量は
docker stats
で確認することができます。docker stats => CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS f697683f3b6e app_web_1 0.01% 116.4MiB / 3.859GiB 2.95% 84.5kB / 39.1kB 0B / 0B 19 c66e3f0371b1 app_db_1 0.00% 2.633MiB / 3.859GiB 0.07% 11.1kB / 60kB 0B / 0B 7 8bcd63949c32 app_webpacker_1 0.00% 859.9MiB / 3.859GiB 21.76% 92.6kB / 63kB 0B / 0B 11
MEM USAGE
がLIMITPIDS
を超えるとOOMエラーとなります。MEM USAGE / LIMITPIDS 859.9MiB / 3.859GiBWebpackerのDockerでは
./bin/webpack-dev-server
コマンドを実行してます。
./bin/webpack-dev-server
では最終的にnode_modules/.bin/web-packer-dev
を実行しているようです。参考: Webpacker使うなら最低限これだけは知っておいてほしいこと
./bin/webpack-dev-server
上ではnodeに環境変数を渡すことができます。
NODE_OPTIONSに--max-old-space-size=3072
を渡すと最大メモリサイズを指定してweb-packer-dev
を実行するようになります。ご自身の環境に合わせて、任意のメモリサイズを指定してください。
bin/webpack-dev-server#!/usr/bin/env ruby ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" ENV["NODE_ENV"] ||= "development" ENV["NODE_OPTIONS"] ||= "--max-old-space-size=3072" require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) require "bundler/setup" require "webpacker" require "webpacker/dev_server_runner" APP_ROOT = File.expand_path("..", __dir__) Dir.chdir(APP_ROOT) do Webpacker::DevServerRunner.run(ARGV) endこれでwebpack-dev-serverが最大メモリサイズに達したらメモリ解放されるようになりました。
メモリサイズが小さいため、頻繁にコンパイルするとメモリ解放が間に合わずOOMが出る時もありますが、かなり頻度が下がりました。
ご自身のスペックにあったメモリサイズを指定し、快適な開発に用いてください!
- 投稿日:2020-05-29T11:22:36+09:00
初学者がlocust 1.0で負荷試験を行う
Webシステムの負荷試験を行う際、最近はjmeterではなくlocustがオススメと聞いたので、試してみました。
- シナリオをpythonで書けるので複雑なケースに対応できる
- 多重度を上げる際、jmeterだと1ユーザ1スレッドになるが、locustなら少ないリソースでも負荷をかけやすい
結論から言うと、公式ドキュメント通りにやれば動きます。
が、割と最近に出た1.0で破壊的変更があったようで、少し前の外部記事を元にすると動きません。そしてハマる(実際ハマった)。
この記事はそういった人がエラーメッセージから逆引きするもののつもりで書いています。なお、いくつか動かない実装として他記事を引用していますが、あくまでlocustの破壊的変更によるものであり、引用元記事が間違っている訳ではないことは注釈しておきます。
細かな仕様や説明は当記事よりそちらの方が詳しいので、ご参考まで。前提環境
- 端末: MacBook Pro Mojave
- 環境: docker for mac 2.0.0.3
- locust: 1.0.2
$ docker -v Docker version 18.09.2, build 6247962 $ docker-compose -v docker-compose version 1.23.2, build 1110ad01とある事情で、諸々最新ではない。
シングル構成でlocustを実行する
コンテナでlocustをインストール
公式のlocustio/locustを使ってもいいのだが、cmdではなくentrypointで
locust
が指定されている。
locustの起動でエラーが起きるとコンテナが即死するだけなので、ログを追いにくくデバッグが辛い。なのでまずはpythonイメージを元にして試してみる。
Webインターフェースを使えるように8089ポートを繋いでおく。$ docker run -it -p 8089:8089 python:3.6 /bin/bashlocustのインストールはpipを叩くだけ。
このとき、古いやり方のpip install locustio
だとLocust package has moved from 'locustio' to 'locust'. Please update your reference (or pin your version to 0.14.6 if you dont want to update to 1.0)
と怒られる。$ pip install locustあと、そのままだとエディタがなくて辛いので、vimなどは適宜入れる。
$ apt-get update -y $ apt-get install -y vimlocustfileを作る
最初、こちらの記事を参考にしたのだが、これはこのままでは動かなかった。
locustfile.pyfrom locust import HttpLocust, TaskSet, task, between, constant class UserBehavior(TaskSet): @task(1) def profile(self): self.client.get("/sample", verify=False) class WebsiteUser(HttpLocust): task_set = UserBehavior wait_time = constant(0)実行すると、まず以下のエラーが出る。
ImportError: The HttpLocust class has been renamed to HttpUser in version 1.0. For more info see: https://docs.locust.io/en/latest/changelog.html#changelog-1-0エラーメッセージ通り、ver1.0 の仕様変更によるもの。
このエラー自体は、単にHttpLocust
をHttpUser
に変えれば良い。
しかしそれ以外にも、この状態で起動すると、あとで実際にリクエストを送るタイミングで以下のエラーが発生する。10b1687a2aee/ERROR/locust.user.task: Cannot choose from an empty sequence Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/locust/user/task.py", line 280, in run self.schedule_task(self.get_next_task()) File "/usr/local/lib/python3.6/site-packages/locust/user/task.py", line 408, in get_next_task return random.choice(self.user.tasks) File "/usr/local/lib/python3.6/random.py", line 260, in choice raise IndexError('Cannot choose from an empty sequence') from None IndexError: Cannot choose from an empty sequenceどうやら
TaskSet
周りの実装方法が変わったらしい。
task_set = UserBehavior
はtasks = {UserBehavior:1}
と書く必要がある。結果、完成したファイルは以下の通り。
パス指定などについては引用元記事を参照まで。locustfile.pyfrom locust import HttpUser, TaskSet, task, between, constant class UserBehavior(TaskSet): @task(1) def profile(self): self.client.get("/sample", verify=False) class WebsiteUser(HttpUser): tasks = {UserBehavior:1} wait_time = constant(0)locustを起動する
以下を実行する。
(実際にはファイル名がこのままなら-f
以降は省略できるが、常にこの名前に縛られるのも不便なので、今から明示的に指定)$ locust -f ./locustfile.pyこのあとでブラウザから
http://localhost:8089/
につなぐと、WebUIが出てくる
- 最大ユーザ(接続)数
- 接続数の増加率(1秒間に何接続増やすか)
- アクセス先URL
図の例の場合、10ユーザになるまで1秒に2ユーザずつ増やし(1秒で2人、2秒で4人……)、10人に到達したら以降10ユーザでアクセスし続ける(10ユーザになったら止まるわけではない)。
なお、私の場合、アクセス先URLの指定をホスト名のみにしたら(e.g.
http://hoge
)、以下のエラーが発生した。ConnectionError(MaxRetryError("HTTPConnectionPool(host='hoge.huga.com', port=80): Max retries exceeded with url: /sample(Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x....>: Failed to establish a new connection: [Errno -5] No address associated with hostname',))",),)curlではホスト名のみでも正常にアクセスできたが、locustではFQDNにしないと接続できなかった。
詳細は調べていない。実行した後はWeb上に色々記事があるので、そちらを参照まで。
docker-compose で並列実行する。
せっかくlocustを使うので、master/slave構成で使いたいと言う欲が出る。
docker-credential-desktopのエラー回避
docker for macの2.0.0.3のバグ(?)で、docker-composeの初期化で以下のエラーが出た
$ docker-compose up -d Creating network "locust_default" with the default driver Creating volume "locust_tests" with default driver Pulling locust-master (locustio/locust:)... Traceback (most recent call last): File "docker-compose", line 6, in <module> File "compose/cli/main.py", line 71, in main File "compose/cli/main.py", line 127, in perform_command File "compose/cli/main.py", line 1080, in up File "compose/cli/main.py", line 1076, in up File "compose/project.py", line 475, in up File "compose/service.py", line 352, in ensure_image_exists File "compose/service.py", line 1217, in pull File "compose/progress_stream.py", line 101, in get_digest_from_pull File "compose/service.py", line 1182, in _do_pull File "site-packages/docker/api/image.py", line 381, in pull File "site-packages/docker/auth.py", line 48, in get_config_header File "site-packages/docker/auth.py", line 96, in resolve_authconfig File "site-packages/docker/auth.py", line 127, in _resolve_authconfig_credstore File "site-packages/dockerpycreds/store.py", line 25, in __init__ dockerpycreds.errors.InitializationError: docker-credential-desktop not installed or not available in PATH [60116] Failed to execute script docker-compose確かに、
/Applications/Docker.app/Contents/Resources/bin/
をみてもdocker-credential-desktop
なんて存在しない。https://github.com/docker/for-mac/issues/3785 によると、2.1.0.0では解消されているので、更新すれば良い。
が、何かしらの事情で更新できない場合、~/.docker/config.json
のcredsStore
を手修正してdesktop
からosxkeychain
にすれば動くようになる。config.json{ "auths" : { "https://index.docker.io/v1/" : { } }, "stackOrchestrator" : "swarm", "experimental" : "disabled", "credsStore" : "desktop <= ここをosxkeychainに変える", "credSstore" : "osxkeychain" }チケットに書いてある通り、確かにどう見てもtypoに見える。。。
docker-composeファイルを作る
こちらの記事を参考にしたのだが、これもそのままでは動かなかった。
ちなみに、このYAMLはアンカーとエイリアスがあるが、パース後に実際に生成されるオブジェクトが知りたい場合は、YAMLをjsonにするオンラインパーサがあるので、活用するとわかりやすいかも。
docker-compose.yamlversion: "3.4" x-common: &common image: locustio/locust environment: &common-env TARGET_URL: http://example.com LOCUSTFILE_PATH: /tests/basic.py volumes: - tests/:/tests services: locust-master: <<: *common ports: - 8089:8089 environment: <<: *common-env LOCUST_MODE: master locust-slave: <<: *common environment: <<: *common-env LOCUST_MODE: slave LOCUST_MASTER_HOST: locust-masterdocker-composeを実行しても、Exited(1)で即死してしまう。
なお、エラーログはdocker logs (コンテナID)
で見れる$ docker-compose up -d Pulling locust-master (locustio/locust:)... latest: Pulling from locustio/locust cbdbe7a5bc2a: Pull complete 26ebcd19a4e3: Pull complete a29d43ca1bb4: Pull complete 979dbbcf63e0: Pull complete 30beed04940c: Pull complete d4954e7e8c67: Pull complete 45867b33845c: Pull complete 2be134228162: Pull complete Creating locust_locust-slave_1 ... done Creating locust_locust-master_1 ... done $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2fd911a1ee59 locustio/locust "locust" 5 minutes ago Exited (1) 5 minutes ago locust_locust-master_1 9c35f427c9eb locustio/locust "locust" 5 minutes ago Exited (1) 5 minutes ago locust_locust-slave_1公式を見ると、パラメータを環境変数から取らなくなった様子。
LOCUSTFILE_PATH: /tests/basic.py
と書いても効果はなく、以下のエラーが出る。Could not find any locustfile! Ensure file ends in '.py' and see --help for available options.
command
でlocust
コマンドへの引数を渡せるので、それでコントロールする。
entrypointが定義されたコンテナイメージでのcmdの扱いについては、こちらがわかりやすい。なお、volumesは
tests/
ではなく./tests
と書く。
でないとtestsという名前付きVolumeと見なされ、以下のエラーが発生する。ERROR: Named volume "tests:/tests:rw" is used in service "locust-master" but no declaration was found in the volumes section.結果、以下だと動く。
docker-compose.yamlversion: "3.4" x-common: &common image: locustio/locust volumes: - tests/:/tests services: locust-master: <<: *common ports: - 8089:8089 command: -f /tests/basic.py --master -H http://example.com locust-slave: <<: *common command: -f /tests/basic.py --worker --master-host locust-masterなお、workerの数を増やしたい場合、yamlを変更する必要はなく、
docker-compose
を実行する際に--scale
を指定すれば良い。$ docker-compose up -d --scale locust-slave=3 Creating network "locust_default" with the default driver Creating locust_locust-slave_1 ... done Creating locust_locust-slave_2 ... done Creating locust_locust-slave_3 ... done Creating locust_locust-master_1 ... doneこれで気軽に分散負荷試験をできるようになった!
- 投稿日:2020-05-29T11:15:00+09:00
Goの30秒で始められるGraphQLサーバー構築
前提
- dockerとdocker-composeインストール済み
- prisma cli インストール済み
どのような物を作るか?
単純に
Hello World!
などのメッセージ一覧を返したり
メッセージを新規作成したり更新、削除したりといった
GraphQLのCRUD APIサーバーを構築します。gqlkitをgit cloneし、コンテナを起動する
まずは、gqlkitというdockerアプリケーションフレームワークをgit cloneし、コンテナを起動しましょう。
これで、半分は作業が完了しました!git clone git@github.com:gqlkit-lab/gqlkit.git cd gqlkit cp .env.example .env docker-compose up -dPostgreSQLに、データの雛形をマイグレートする
今回、どのようなデータモデルをマイグレートするのかを確認しておきましょう。
gqlkit-server/prisma/schema.prismaを開くと下記のようになっています。
このファイルを編集してprisma migrate
してやる事で
データベースにデータモデルを作ることができます。gqlkit-server/prisma/schema.prismadatasource db { provider = "postgresql" url = "postgresql://postgres:postgres@localhost:5432/postgres?schema=public" } model messages { id String @default(cuid()) @id text String created_at String updated_at String }今回は、このままの内容をマイグレートするのでファイルの内容は編集せず下記を実行します。
これでPostgreSQLにmessages
テーブルが作成されました。prisma migrate save --experimental prisma migrate up --experimentalちなみに
schema.prisma
に書くモデル名の注意点ですが
gqlkitはgormを採用しているので「messages」のように複数形で「s」が最後に来るように気をつけましょう。
2単語以上の場合はsnake_caseで書いてやります。GraphQLサーバーを起動する
次の流れとしては、gqlkit-server/graph/schema.graphqlを編集し
gqlkit-server/graph/schema.resolvers.goにリゾルバを書いていくのですが
gqlkitはデフォルトのサンプルとして
messagesのCRUDサンプルはgqlgenでジェネレート済みとなっています。
なので、ここではさらっと
schema.graphqlの中身とschema.resolvers.goの中身を確認だけしておきます。gqlkit-server/graph/schema.graphqltype Query { readMessages: [Message!]! } type Mutation { createMessage(text: String!): Message! updateMessage(id: ID!, text: String!): Message! deleteMessage(id: ID!): Message! } type Message { id: ID! text: String! created_at: String updated_at: String! }gqlkit-server/graph/schema.resolvers.gopackage graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. import ( "context" "fmt" "gqlkit/env" "gqlkit/graph/generated" "gqlkit/graph/model" "time" "github.com/jinzhu/gorm" _ "github.com/lib/pq" uuid "github.com/satori/go.uuid" ) func (r *mutationResolver) CreateMessage(ctx context.Context, text string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } id := uuid.Must(uuid.NewV4(), nil) loc, _ := time.LoadLocation("Asia/Tokyo") now := time.Now().In(loc).Format("2006-01-02T15:04:05+09:00") r.message = &model.Message{ ID: id.String(), Text: text, CreatedAt: &now, UpdatedAt: now, } db.Create(&r.message) return r.message, nil } func (r *mutationResolver) UpdateMessage(ctx context.Context, id string, text string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } loc, _ := time.LoadLocation("Asia/Tokyo") now := time.Now().In(loc).Format("2006-01-02T15:04:05+09:00") db.Where("id = ?", id).First(&r.messages) r.message = r.messages[0] db.Model(&r.message).Where("id = ?", id).Update("text", text) db.Model(&r.message).Where("id = ?", id).Update("updated_at", now) return r.message, nil } func (r *mutationResolver) DeleteMessage(ctx context.Context, id string) (*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } db.Where("id = ?", id).First(&r.messages) r.message = r.messages[0] db.Where("id = ?", id).Delete(&r.messages) return r.message, nil } func (r *queryResolver) ReadMessages(ctx context.Context) ([]*model.Message, error) { db, err := gorm.Open("postgres", env.DB_CONNECT) defer db.Close() if err != nil { return nil, fmt.Errorf(err.Error()) } db.Order("created_at").Find(&r.messages) return r.messages, nil } // Mutation returns generated.MutationResolver implementation. func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } // Query returns generated.QueryResolver implementation. func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver }実際に、任意のアプリを開発する際は、
schema.graphql
を編集する
↓
go run github.com/99designs/gqlgen
でリゾルバをジェネレートする
↓
schema.resolvers.go
を編集する
という感じの流れで開発していきます。という事で最後に、下記を実行してGraphQLプレイグラウンドを立ち上げましょう!
http://localhost:8080/ でGraphQLプレイグラウンドが立ち上がっています。cd gqlkit-server go run server.go
まとめ
現在、マークアップエンジニアからwebエンジニアへと
ステップアップ転職を目指しているのですが何を思ったか求人の多いRubyに手を出さず
先にGoに手を出してしまいました。すると、Goのなんと楽にバックエンド開発が終了してしまう事か
これは、下手をするとfirebase + nuxtでアプリ作ってた時以上に楽です。Goに触れたのは幸なのか不幸なのか
その後、Railsの学習に手をつけてみようと何度かトライするのですが
Goの圧倒的すぎるシンプルさ、簡単さ、スッキリさ、に引きずられてしまい
どうしても、わざわざ学ぼうという意欲が出ないでいます。
Laravelも同じく...
求人は多いのに...(泣)
Goめ!実に罪深い!(褒め言葉)
- 投稿日:2020-05-29T10:46:16+09:00
nvidiaのdockerでroot以外のユーザでGPUを使う
はじめに
NvidiaはDokcerのサポートを強化しています。NGCなどから、イメージをダウンロードしコンテナとして実行が可能です。
なにかとバージョン依存の多いdarknetだのopenCVだのをつかうにあたって、dockerがとても便利だとおもって、openCVのイメージ だのdarknetのイメージだのをつくって、さあこれから使おうとおもって、User追加してみたら、rootじゃないとGPUが使えませんでした。やったこと
なかなか検索してもひっかからなかったので、ここに書いとくことにしました。
解決策は以下
nvidia-docker seems unable to use GPU as non-root userDockerfileにすろと、こんなの足しとけばいけました。
RUN useradd -m ${USER} && \ echo ${USER}:${PASSWD} | chpasswd && \ echo "${USER} ALL=(ALL) ALL" >> /etc/sudoers RUN sudo usermod -a -G video ${USER}上記のdarknetのイメージをもとにするんだったらこんな感じ
ついでに、Dockerでapt-get upgradeもしてからユーザ追加してます。FROM darknet:100 ENV USER="hoge" ENV PASSWD="hogehoge" ENV HOME=/home/${USER} RUN apt-get -y update RUN echo '* libraries/restart-without-asking boolean true' | debconf-set-selections RUN apt-get -y upgrade RUN apt -y install xfce4-terminal RUN useradd -m ${USER} && \ echo ${USER}:${PASSWD} | chpasswd && \ echo "${USER} ALL=(ALL) ALL" >> /etc/sudoers RUN sudo usermod -a -G video ${USER} USER ${USER} WORKDIR ${HOME} CMD ["/bin/bash"]
- 投稿日:2020-05-29T10:45:34+09:00
EC2にDockerをインストールして自作イメージからコンテナを起動してみる。
調べが足りないだけかもしれませんが。。
Dockerのインストールガイドで、AmazonLinuxでのインストール方法が見つからなかったので、自分がやった手順を残しておこうと思います。
環境
以下の環境で試しました。
大項目 中項目 値 EC2 インスタンスタイプ t2.micro OS Amazon Linux 2 Dockerリポジトリ Docker Hub yumでインストールできました。
なんとなく、こんなコマンドでいけるのでは?
と、打ち込んでみたら、大当たり。
sudo yum install docker
systemctlでdockerサービスを起動
インストールしたら、勝手にサービスが上がってくるだろうと思ってたら、そうではないようです。
以下のコマンドで、dockerサービスが起動できます。
sudo systemctl start docker
docker login
docker login時はサーバを指定しました。
sudo docker login https://index.docker.io/v1/
docker pull
ここから、先はつまづくことはなかったです。(イメージ名はサンプルです。)
sudo docker pull myaccount/sampleapp:latest
docker container run
macで作ったRailsのアプリが、いとも簡単に起動しました。
sudo docker container run -d -p 8080:3000 myaccount/sampleapp:latest
- 投稿日:2020-05-29T10:18:17+09:00
Docker超入門!Apacheを使ってhtmlを表示してみよう!
目的
- Dockerを学ぶ最初の一歩として自分の知識を整理しながら基礎をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.3) ハードウェア MacBook Pro (16-inch ,2019) プロセッサ 2.6 GHz 6コアIntel Core i7 メモリ 16 GB 2667 MHz DDR4 グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB
- ソフトウェア環境
項目 情報 備考 Docker バージョン 19.03.8 こちらの方法で導入→Docker Desktop for Mac をインストールする 概要
- イメージのダウンロード
詳細
イメージのダウンロード
下記コマンドを実行してApacheのイメージのダウンロードを行う。(DockerではApacheはhttpdという名前で扱われている。)
$ docker pull httpd下記コマンドを実行して現在インストールされているイメージの一覧を出力しApache(httpd)が存在する事を確認する。
$ docker images >REPOSITORY TAG IMAGE ID CREATED SIZE >httpd latest d4e60c8eb27a 12 days ago 166MBコンテナの作成
下記コマンドを実行してイメージからコンテナを作成し、作成したコンテナを起動する。
-d
はデーモンモードにて起動するオプションである。-p 物理マシンのポート番号:コンテナのポート番号
はポート設定を行うオプションである。(物理マシンとは、みなさんのMacBookやWindowsPCを指す。)- 下記コマンドの意味は「デーモンモードにて、物理マシンのポート番号8080番とコンテナのポート番号80番をつないでイメージからApache(httpd)のコンテナを作成します」である。
$ docker run -d -p 8080:80 httpdブラウザにて下記にアクセスする。
下記の様に表示される事を確認する。
下記コマンドを実行して現在起動しているコンテナの一覧を表示する。
$ docker ps下記コマンドを実行して一旦Apacheのコンテナを停止する。(コンテナ名は先のコマンド
$ docker ps
のNAMESの内容)$ docker stop コンテナ名htmlの表示
下記コマンドを実行してhtmlファイルを格納するディレクトリを作成する。
$ mkdir -p /tmp/html下記コマンドを実行してhtmlファイルを作成する。
$ echo "Hello Japan" >> /tmp/html/index.html下記を実行してdockerコンテナ先のディレクトリにマウントする。(
$ docker run -d -p 8080:80 -v "物理マシンにあるhtmlファイルの親ディレクトリのフルパス(マウントするディレクトリ):コンテナ側のディレクトリ(マウント先のディレクトリ)" httpd
)$ docker run -d -p 8080:80 -v "/tmp/html/:/usr/local/apache2/htdocs/" httpd確認
- ブラウザにて下記にアクセスする。
下記の様に表示される事を確認する。
- 投稿日:2020-05-29T08:26:58+09:00
nuxt.js(vuetify)+Rails(api)+mysql on dockerでHelloWorld!!
前書き
railsとvue.jsを同一コンテナ内で環境構築することはやったことがあったんですが、フロントエンドとバックエンドのコンテナを分けるのが最近のトレンドだと耳にしたのでHelloWorldに挑戦してみました!
こちらの記事を参考にさせていただきました!ありがとうございました!
参考→https://qiita.com/at-946/items/08de3c9d7611f62b1894
postgresqlからmysql、nuxt.jsをnpmからyarn、railsのコンテナをalpineからdebianに変更しています。今回作る環境
ruby:2.6.5
rails:6.0.3
mysql:8.0
nuxt.js(yarn)
vuetifyコンテナの準備
ディレクトリ構成
// |--front/ | |--Dockerfile |--back/ | |--Dockerfile | |--Gemfile | |--Gemfile.lock #空ファイル | |--entrypoint.sh |--docker-compose.ymlフロントコンテナ内のDockerfile
front/DockerfileFROM node:12.5.0-alpine ENV HOME="/myapp" \ LANG=C.UTF-8 \ TZ=Asia/Tokyo WORKDIR ${HOME} RUN apk update && \ apk upgrade && \ npm install -g npm && \ npm install -g @vue/cli ENV HOST 0.0.0.0 EXPOSE 3000バックコンテナ内のDockerfile
back/DockerfileFROM ruby:2.6.5 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ && apt-get update -qq \ && apt-get install -y nodejs yarn \ && mkdir /myapp ENV HOME="/myapp" \ LANG=C.UTF-8 \ TZ=Asia/Tokyo WORKDIR ${HOME} COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . ${HOME} COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]Gemfile
back/Gemfilesource 'https://rubygems.org' gem 'rails', '~> 6.0.3', '>= 6.0.3.1'back/entrypoint.sh#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"docker-compose.ymlversion: '3' services: db: container_name: db image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password #3307にしているのは筆者の環境では3306がpc自体のMySQLで使われているためです。3306:3306の方がいいかもです。 ports: - '3307:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql back: container_name: back build: back/ command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - ./back:/myapp ports: - "3000:3000" depends_on: - db stdin_open: true tty: true command: bundle exec rails server -b 0.0.0.0 front: container_name: front build: front/ command: yarn dev volumes: - ./front:/myapp ports: - 8080:3000 #depends_onでbackコンテナへのリンクを張っています。 depends_on: - back volumes: mysql-data: driver: localここまで写し終わったら
$ docker-compose buildこれでdockerimageが作成され、コンテナの準備ができました!
nuxt.jsのHelloWorld
参考記事とほとんど変わらないので書くのがはばかられますが、少し違うので一応書いておきます。
まずはnuxt.jsのアプリを作成します。
途中の選択画面でエンターだけでなくスペースを押す必要がある項目もあるので注意してください。$ docker-compose run --rm front npx create-nuxt-app ? Project name --> myapp # アプリ名 ? Project description --> myapp # アプリの説明 ? Author name --> me # アプリの作成者 ? Choose the package manager --> Yarn ? Choose UI framework --> Vuetify ? Choose custom server framework --> None ? Choose Nuxt.js modules --> Axios ? Choose linting tools --> - ? Choose test framework --> None ? Choose rendering mode --> Universal (SSR)これでnuxtアプリの完成です!
フロントコンテナを立ち上げて確認してみましょう!$ docker-compose up front
http://localhost:8080
にアクセスしていい感じになってたらいい感じです。(語彙)(参考)ホットリロードがうまくいかない時は冒頭の参考記事に解決法が記載されているのでそちらを参考にしてください。
→ https://qiita.com/at-946/items/08de3c9d7611f62b1894Rails(Api)のHelloWorld
apiモードでrailsアプリを作ります。
$ docker-compose run --rm back rails new . -f -d mysql --api次にDBを接続します。
back/config/database.ymldefault: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch("MYSQL_USERNAME", "root") %> password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %> host: <%= ENV.fetch("MYSQL_HOST", "db") %>ドメイン許可の設定をします。行頭に追記してください。
(ここに2日かかりました。これを書きたいがためにこの記事を書いたと言っても過言ではないです。)config/environments/development.rbRails.application.config.hosts << 'back' ##省略##以降は参考記事と全く同じなので省略します。(サボれるところはサボる主義です。)
gitの設定
axiosでpostできたら、次にgitの設定をします。
railsはnewするときにgit initしてしまうのでbackディレクトリだけgit管理される状況になってしまいます。/$ cd ./backback/$ sudo rm -rf .git $ cd ..sudoはいらないかもです。
この後に$ git initを打って完了です。
セキュリティ的にいいのかはわからないんですが、
.gitignore#.nuxt #dist #sw.* #node_modules/ #jspm_packages/と、この5つをコメントアウトしておかないと他のパソコンでdocker-compose upが使えなかったので参考にしてみてください。
あとがき
いやー、ハマりましたね。ただやっぱなんとなくこの構成かっこいい、、かっこよくない?
というわけで参考になれば嬉しいです。よろしければLGTMお願いします!(露骨な媚び)
それではまた!
- 投稿日:2020-05-29T08:16:57+09:00
Windows10+WSL2+Ubuntu+Docker
本日、「Windows 10 May 2020 Update」が公開されました。これで、Insider Previewでなくても、wsl2が使えるようになり、Windows10 Home上でDocker環境を簡単に構築できるようになりました。
今回は、Ubuntuを入れて、そこにDocker for Windowsを乗せるところまでの備忘録。最終的にはLaravelを動かす予定。
手順
※再起動が促されたら従うこと。
WSL2の有効化
以下にエクスプローラでアクセスする。
コントロール パネル\プログラム\プログラムと機能
Windowsの機能の有効化または無効化を選択する。
以下の画面が出てくるので、Linux用Windowsサブシステムを有効にする。
PowerShellを管理者権限で開き、以下を実行してWSL2が動くようにする。
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
Ubuntuのインストール
Microsoft StoreでUbuntuを検索し、Ubuntu 18.04 LTSをインストールする。
(別のバージョンでも構いませんが、現時点ではこれをオススメ)Ubuntuが起動されてユーザとパスワードが聞かれるので設定する。
PowerShellで以下を実行して、WSL1からWSL2に切り替える。
wsl --set-version Ubuntu-18.04 2
ここで、「カーネルコンポーネントの更新が必要です」と出たら、以下にアクセスしてLinux カーネル更新プログラム パッケージをダウンロードして実行し、再度上記を実行する。
https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-kernel
PowerShellで以下を実行して、WSL2に切り替わっていることを確認する。
wsl -l -v
VERSIONのところが2になっていたら成功。
Docker for Windowsのインストール
以下のページから、Docker for Windows(stableでOK)をダウンロードしてインストールする。
https://www.docker.com/products/docker-desktop
Docker Desktop for Mac and Windows | DockerLearn why Docker Desktop is the preferred choice for millionswww.docker.com
何も変更せずインストールする。
※最後、Windowsからログアウトするので注意。
再ログインすると、自動的にDocker for Windowsが立ち上がる。チュートリアルは面倒なのでskipしました。
先程作ったWSL2のUbuntu-18.04をリソースとして設定する。
Dockerが使える環境になりました。
次回への準備(Laravel環境を作らないなら必要無し、備忘録のため残しておく)
WindowsのスタートメニューからUbuntu-18.04を立ち上げる。
立ち上がったターミナルで以下を実行していく。
hogehogeさんはプロジェクト名とか任意のものでOK。cd ~ mkdir hogehoge cd hogehoge explorer.exe .
最後のコマンドで、Ubuntu内で現在いるディレクトリのWindows上でのフォルダが開かれる。
次回、この上にLaravel実行環境を構築していく。
- 投稿日:2020-05-29T04:12:14+09:00
Docker for Mac の Mutagen-based cachingを使ったらホスト側のファイルの変更が反映されなくなった
何が起きたか
Docker for Mac の Mutagen-based caching で Volume のパフォーマンスが劇的に改善した
こちらの記事を見て試してみたらrspecとかrubocopとか爆速になってうおおおおおおってなったけど
swagger.ymlのホスト側での変更がredocのコンテナ内に反映されなくなってしまった
しかし、railsプロジェクトの方は問題なく反映されていてなんでだろうと思ったら原因
docker-compose.ymlversion: '3' services: redoc: image: redocly/redoc:latest volumes: - ./swagger.yml:/usr/share/nginx/html/swagger.yml environment: SPEC_URL: swagger.yml ports: - 8081:80volumesで
- ./swagger.yml:/usr/share/nginx/html/swagger.yml
と書いていたこと
どうやらファイル単位での指定をすると反映がされなくなるようだ
なんでかはわからん、暇な時に気が向いたら調べる解決策
ディレクトリ単位でマウントする
docker-compose.ymlversion: '3' services: redoc: image: redocly/redoc:latest volumes: - ./swagger:/usr/share/nginx/html/swagger environment: SPEC_URL: swagger/swagger.yml ports: - 8081:80ちなみに
Mutagen-based caching使ったらrspecとか4倍ぐらい早くなるので
railsをdocker使って開発してて遅いなぁって困ってる人にはとてもおすすめ
もうdocker for mac遅いなんて言わせない!!!!!edge版なので何があるかわからんけど