20200708のdockerに関する記事は19件です。

PrometheusのNode exporterをdockerで起動してちゃんとホスト側のメトリクスを収集させる方法

docker run -d \
  -v "/proc:/host/proc:ro" \
  -v "/sys:/host/sys:ro" \
  -v "/:/rootfs:ro" \
  --net="host" \
  quay.io/prometheus/node-exporter
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでdeviseを追加したいのにbundle installができない

dockerで環境構築を行いgemの追加をした際にエラーが発生しましたので
備忘録として情報共有しようと思います!

開発環境

docker
rails (5.2.0)
ruby (2.7.1)
mysql (5.7)
nginx
puma

※docker-compose buildでgemの更新をしますが時間がかかるので下記の記事を参考に
gemの更新を素早くする設定をしています。
 https://qiita.com/neko-neko/items/abe912eba9c113fd527e

エラー内容

Gemfileでdeviseのgemを追加し、docker-compose run --rm rails bundle installをしたところ以下のエラーが発生

~ RailsApp % docker-compose run --rm rails bundle install              
Starting railsapp_db_1 ... done
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Bundler could not find compatible versions for gem "railties":         
  In snapshot (Gemfile.lock):
    railties (= 5.2.4.3)

  In Gemfile:
    devise (= 4.1.0) was resolved to 4.1.0, which depends on
      railties (< 5.1, >= 4.1.0)

    rails (~> 5.2.2) was resolved to 5.2.4.3, which depends on
      railties (= 5.2.4.3)

Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.

何が原因なのかわからなかったが、とりあえず「bundle updateしたら解決するかもよ」と書いてあったので
docker-compose run --rm rails bundle updateを実行

↓↓↓↓↓↓↓↓

~ RailsApp % docker-compose run --rm rails bundle update           
Starting railsapp_db_1 ... done
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...........................
Bundler could not find compatible versions for gem "railties":      
  In snapshot (Gemfile.lock):
    railties (= 5.2.4.3)

  In Gemfile:
    devise (= 4.1.0) was resolved to 4.1.0, which depends on
      railties (< 5.1, >= 4.1.0)

    rails (~> 5.2.2) was resolved to 5.2.4.3, which depends on
      railties (= 5.2.4.3)

ダメでしたね・・・

原因

結論から申し上げるとdeviseというgemがlistにないことがエラーの原因だったみたいです。


下記の記事を参考にさせていただきました。
https://qiita.com/hatorijobs/items/2928e152f22d009b07d0

こちらの記事をそのまま実行すれば解決しますが、dockerで作業している方は若干、コマンドが
異なりますのでこちらで説明させていただこうと思います。

対処方法

以下の順に操作をしていきます。

1. docker-compose exec [任意サービス名] gem list でGemの一覧を確認し、deviseのgemがないことを確認する。

2. docker-compose exec [任意サービス名] gem install devise でdeviseをインストールする。

3. もう一度docker-compose exec [任意のサービス名] gem list でGemの一覧を確認し、devise(4.7.2)があることを確認する。

4. Gemfileに**gem 'devise','4.7.2'を記述する

5. docker-compose run --rm rails bundle updateを実行

順番に見ていきましょう。
↓↓↓↓↓↓↓↓

1. docker-compose exec [任意サービス名] gem list でGemの一覧を確認し、deviseのgemがないことを確認する。

~ RailsApp % docker-compose exec app gem list

*** LOCAL GEMS ***

actioncable (5.2.4.3, 5.2.2)
actionmailer (5.2.4.3, 5.2.2)
actionpack (5.2.4.3, 5.2.2)
actionview (5.2.4.3, 5.2.2)
actionjob (5.2.4.3, 5.2.2)

~省略~

web-console (3.7.0)

2. docker-compose exec [任意サービス名] gem install devise でdeviseをインストールする。

~ RailsApp % docker-compose exec app gem install devise
Fetching warden-1.2.8.gem
Fetching bcrypt-3.1.13.gem

~省略~

Successfully installed devise-4.7.2
5 gems installed

3. もう一度docker-compose exec [任意のサービス名] gem list でGemの一覧を確認し、devise(4.7.2)があることを確認する。

~ RailsApp % docker-compose exec app gem list

*** LOCAL GEMS ***

actioncable (5.2.4.3, 5.2.2)
actionmailer (5.2.4.3, 5.2.2)
actionpack (5.2.4.3, 5.2.2)
actionview (5.2.4.3, 5.2.2)
actionjob (5.2.4.3, 5.2.2)

~省略~

devise (4.7.2)

~省略~

web-console (3.7.0)

4. Gemfileにgem 'devise','4.7.2'を記述する

Gemfile.
source 'https://rubygems.org'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.0', '>= 5.0.2.1'
# Use mysql as the database for Active Record
gem 'mysql2', '>= 0.3.18', '< 0.5'
# Use Puma as the app server

~省略~

#ログイン機能の追加
gem 'devise','4.7.2'

~省略~

5. docker-compose run --rm rails bundle updateを実行

~ RailsApp % docker-compose run --rm rails bundle update

これでエラーが出なければ我々の勝ちです

気づいたこと

エラー対応している際に気づいたことがいくつかあったので共有させていただきます

docker-compose exec app gem install deviseを実行すると最新版のgemがインストールされます。
最新版でも特に問題ないと判断したため、バージョン指定する方法の説明は省略させていただきました。
※逆に方法がわかる方は教えてください!

ちなみにdeviseの全バージョン履歴が掲載されたサイトを見つけましたのでURLを連携させていただきます。
https://rubygems.org/gems/devise/versions
※2020.06.10時点での最新バージョンは4.7.2


[任意のサービス名]とはdocker-compose.ymlで指定しているサービス名のことです。
任意で決めることができますが、どのサイトでもdbとかappとかwebて設定している方が多い印象です。

※わからないて方は、「docker-compose.yml サービス名」で調べると記事がヒットすると思います。

終わりに

Railsやdockerについては今後もアウトプットのためにエラーに関する記事等を定期的に投稿していこうと思っております。
また、初めての投稿で至らない点があったかと思いますが、最後まで読んでいただきありがとうございました!!!

以上

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

dockerでrails+mySQLの環境構築したらlocalhost:3000にアクセス出来なくて困ってたら驚愕の事実が発覚した話

こちらの記事を参考に、docker-composeでrails+mySQLの環境構築をしてみた。

DBの作成まですんなり行き「docker最高!!!!!!!!」みたいになってたが、localhost:3000にアクセスすると「このページは動作していません。」と返ってくる…

うーわ、最悪

環境構築には嫌な思い出しかない。
一度virtualboxとvagrantで環境構築したとき無限にエラーが出続けて「これはもう神がプログラミングをやめろと言っているのでは???」みたいになって以来、環境構築という単語を聞いただけで寒気がしてくる。

まあプログラミングの学習をする上で避けては通れない道なのでやるしかない。

とりあえずコンテナ内のサーバーが起動しているか確認。

$ docker exec -it コンテナ名 bash
**** # curl http://localhost:3000/

コンテナの中に入ってlocalhost:3000にアクセスしてみると普通にHTMLが返ってくる。こっちは問題なさそう。

とりあえずログを見てみる。

docker logs ***_***_web

見たけど特にエラーは出ていない。
もう一度コンテナ内からアクセスしたのちログをみると、さっきと同様のログが一つ増えていたので多分このログはコンテナ内からアクセスしたものっぽい。

ブラウザからアクセスしてもログが残っていないということは、そもそもブラウザからWebコンテナの3000ポートまでリクエストが到達してないってことらしい。

なるほどね……………ドユコト???クッソ、横文字ばっか並べやがって…

その後も格闘は続いた。ありとあらゆるサイトを読み漁り、英語を必死に読解し、嫌になってスプラトゥーンをやって、YouTubeを見て、twitterを見て…とかなんとかしているうちに夜になっていた。

もう諦めようか…そんな考えが頭をよぎり出したとき、ある記事が目に入る。
私と同じようなエラーが出て困っているようだったのだが、その人が「esetのファイアウォールを無効にしたらいけました〜」と言うているのだ。

eset??まって私もセキュリティソフトesetだわ、ウイルスバスターって名前がダサくて嫌だったから特に何も考えずに購入したeset…まさかお前が…?いや、こんな悩みに悩んだ挙句セキュリティソフトに通信遮断されてました!は流石に酷いと思わない…???ねえ、違うよね??違うって言ってよ!!!

とか思いながら恐る恐るesetのファイアウォールを無効にしてlocalhost:3000にアクセスしてみたら

image.png

で、出た〜〜〜〜〜〜〜〜〜!!!!!!!!!!!!お前、あっさり出た〜〜〜〜〜〜〜〜!!!!!!!!

くそがよ

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

dockerでrails+mySQLの環境構築したけどlocalhost:3000にアクセス出来なくて困ってたら驚愕の事実が発覚した話

こちらの記事を参考に、docker-composeでrails+mySQLの環境構築をしてみた。

DBの作成まですんなり行き「docker最高!!!!!!!!」みたいになってたが、localhost:3000にアクセスすると「このページは動作していません。」と返ってくる…

うーわ、最悪

環境構築には嫌な思い出しかない。
一度virtualboxとvagrantで環境構築したとき無限にエラーが出続けて「これはもう神がプログラミングをやめろと言っているのでは???」みたいになって以来、環境構築という単語を聞いただけで寒気がしてくる。

まあプログラミングの学習をする上で避けては通れない道なのでやるしかない。

とりあえずコンテナ内のサーバーが起動しているか確認。

$ docker exec -it コンテナ名 bash
**** # curl http://localhost:3000/

コンテナの中に入ってlocalhost:3000にアクセスしてみると普通にHTMLが返ってくる。こっちは問題なさそう。

次にログを見てみる。

docker logs ***_***_web

見たけど特にエラーは出ていない。
もう一度コンテナ内からアクセスしたのちログをみると、さっきと同様のログが一つ増えていたので多分このログはコンテナ内からアクセスしたものっぽい。

ブラウザからアクセスしてもログが残っていないということは、そもそもブラウザからWebコンテナの3000ポートまでリクエストが到達してないってことらしい。

なるほどね……………ドユコト???クッソ、横文字ばっか並べやがって…

その後も格闘は続いた。ありとあらゆるサイトを読み漁り、英語を必死に読解し、嫌になってスプラトゥーンをやって、YouTubeを見て、twitterを見て…とかなんとかしているうちに夜になっていた。

もう諦めようか…そんな考えが頭をよぎり出したとき、ある記事が目に入る。
私と同じようなエラーが出て困っているようだったのだが、その人が「esetのファイアウォールを無効にしたらいけました〜」と言うているのだ。

eset??まって私もセキュリティソフトesetだわ、ウイルスバスターって名前がダサくて嫌だったから特に何も考えずに購入したeset…まさかお前が…?いや、こんな悩みに悩んだ挙句セキュリティソフトに通信遮断されてました!は流石に酷いと思わない…???ねえ、違うよね??違うって言ってよ!!!

とか思いながら恐る恐るesetのファイアウォールを無効にしてlocalhost:3000にアクセスしてみたら

image.png

で、出た〜〜〜〜〜〜〜〜〜!!!!!!!!!!!!お前、あっさり出た〜〜〜〜〜〜〜〜!!!!!!!!

くそがよ

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

Docker&Rails環境で、gemを永続化させる

本記事について(お断り)

この記事は、しがないプログラミング初心者がお勉強よろしくプログラミング・技術に触れるべく、行ったことの備忘録として書き綴ったものです。ご了承ください。
ご指摘は甘んじて受け入れます?‍♂️

起こったこと

とあるプロダクトでおもむろにdocker-compose upしてたら、

...
web_1  | Bundler::GemNotFound: Could not find gem 'rspec-rails' in any of the gem sources listed in your Gemfile.
...
myapp_web_1 exited with code 1

と怒って勝手に出て行ってしまった。
おかしい、確かにインストールしたはずのgemがないとは、、、

一度落として、再度docker-compose buildすると問題なく動いた。
まあこれでもいいんだけど、毎回ビルドしてコンテナ起動するのは面倒だと思う。

調べてみると、volumeの永続化を行うことで、こうした問題が解消されるとのこと。

docker-compose.ymlの修正

現在のファイルの中身。

docker-compose.yml
ersion: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=password
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

これを書き加える

docker-compose.yml
ersion: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=password
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
      - gem_data:/usr/local/bundle # <= ココと
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  gem_data: # <= ココ。

パスは、コンテナの中に入って確認できます。

$ docker-compose exec web bash
$ gem environment
RubyGems Environment:
  - RUBYGEMS VERSION: 3.0.3
  - RUBY VERSION: 2.6.5 (2019-10-01 patchlevel 114) [x86_64-linux]
  - INSTALLATION DIRECTORY: /usr/local/bundle
  ...(略)

これでgemを永続化する環境を構築できたことになります。
試しに、gemを追加、

Gemfile
+ gem 'rails-erd'

その後、bundle installしてみます。

$ docker-compose exec web bundle install

そして、一度コンテナを削除した後に再度起動してみます。

$ docker-compose down
$ docker-compose up

Rails6.png

問題なくコンテナを起動できました!

コンテナ削除前にインストールしたgemもちゃんと入っています。

$ docker-compose exec web bundle list |grep 'rails-erd'
  * rails-erd (1.6.0)

参考

今回の作業にあたり、以下のページを参考にさせていただきました。とても勉強になりました。ありがとうございます?‍♂️

https://nishinatoshiharu.com/datavolume-for-gem/

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

Riken_simulatorが偶然弊社のOSXでbuild出来てしまった話

はじめに

弊社に設置してあるOSX(iMac)でdockerいじってたら、面白そうなシミュレータの記事が出てたので、
commitできる余地があればと思い本記事を投稿するに至りました。

参考にした記事はこちらになります。

自分がした操作は、以下の通りになります。

操作

  1. 上記記事に記載のDockerfile(下記)を丸パクリ。
FROM ubuntu:18.04
MAINTAINER kaityo256

ENV USER user
ENV HOME /home/${USER}
ENV SHELL /bin/bash

RUN useradd -m ${USER}
RUN gpasswd -a ${USER} sudo
RUN echo 'user:userpass' | chpasswd

RUN apt-get update && apt-get install -y \
    g++ \
    g++-8-aarch64-linux-gnu \
    git \
    m4 \
    python-dev \
    scons \
    sudo \
    vim \
    qemu-user-binfmt \
    zlib1g-dev

USER ${USER}

RUN cd ${HOME} \
 && mkdir build \
 && cd build \
 && git clone --depth 1 https://github.com/RIKEN-RCCS/riken_simulator.git

RUN cd ${HOME} \
 && cd build/riken_simulator \
 && sed -i "369,372s:^:#:" SConstruct \
 && scons build/ARM/gem5.opt -j 20

RUN cd ${HOME} \
 && git clone https://github.com/kaityo256/aarch64env.git

RUN cd ${HOME} \
 && echo alias gem5=\'~/build/riken_simulator/build/ARM/gem5.opt ~/build/riken_simulator/configs/example/se.py -c\' >> .bashrc \
 && echo alias ag++=\'aarch64-linux-gnu-g++-8 -static -march=armv8-a+sve\' >> .bashrc

2 . 上記Dockerfileを配置しているディレクトリにホストOS上で移動し、docker build -t aarch64env .
3. scons コマンドでこけてbuild未完了のdocker imageに対して、docker run --rm -it ${IMAGEID} /bin/bash
4. riken_simulator/.git/hooks以下(.git以下だったかな...?)の中身に対してrm -rf ./*という暴挙。
5. cd ~/build/riken_simulator && git init
6. sconsのbuild process時に使用するcore数を -j 4に変更し、containerにloginした状態で再度sed -i "369,372s:^:#:" SConstruct && scons build/ARM/gem5.opt -j 4

結果

  • 時々iMacのdisplayをダウンさせながらも、余計なことを並列でしなければsimulatorは動作する。

  • build後にdocker network pruneでなぜかパフォーマンスが改善する現象を発見した。

Log (上記操作3以降)

user@67870d4b0466:~/build/riken_simulator$ cd .git/hooks
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ ls
applypatch-msg.sample  fsmonitor-watchman.sample  pre-applypatch.sample  pre-merge-commit.sample  pre-rebase.sample   prepare-commit-msg.sample
commit-msg.sample      post-update.sample         pre-commit.sample      pre-push.sample          pre-receive.sample  update.sample
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ cd ..
user@67870d4b0466:~/build/riken_simulator/.git$ rm -r hooks
rm: descend into write-protected directory 'hooks'? 
user@67870d4b0466:~/build/riken_simulator/.git$ ls
HEAD  config  description  hooks  index  info  logs  objects  packed-refs  refs
user@67870d4b0466:~/build/riken_simulator/.git$ cd hooks
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ ls
applypatch-msg.sample  fsmonitor-watchman.sample  pre-applypatch.sample  pre-merge-commit.sample  pre-rebase.sample   prepare-commit-msg.sample
commit-msg.sample      post-update.sample         pre-commit.sample      pre-push.sample          pre-receive.sample  update.sample
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ rm ./*
rm: remove write-protected regular file './applypatch-msg.sample'? yes
rm: cannot remove './applypatch-msg.sample': Permission denied
rm: remove write-protected regular file './commit-msg.sample'? ^C
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ sudo rm ./*
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ ls
user@67870d4b0466:~/build/riken_simulator/.git/hooks$ cd ../..
user@67870d4b0466:~/build/riken_simulator$ git init
fatal: cannot copy '/home/user/.git_template/hooks/pre-commit' to '/home/user/build/riken_simulator/.git/hooks/pre-commit': Permission denied
user@67870d4b0466:~/build/riken_simulator$ sudo git init
Reinitialized existing Git repository in /home/user/build/riken_simulator/.git/
user@67870d4b0466:~/build/riken_simulator$ sudo sed -i "369,372s:^:#:" SConstruct && scons build/ARM/gem5.opt -j 4
scons: Reading SConscript files ...
OSError: [Errno 13] Permission denied: '/home/user/build/riken_simulator/build':
  File "/home/user/build/riken_simulator/SConstruct", line 253:
    mkdir(build_root)
user@67870d4b0466:~/build/riken_simulator$ sudo sed -i "369,372s:^:#:" SConstruct && sudo scons build/ARM/gem5.opt -j 4
scons: Reading SConscript files ...
Warning: Your compiler doesn't support incremental linking and lto at the same time, so lto is being disabled. To force lto on anyway, use the --force-lto option. That will disable partial linking.
Warning: Protocol buffer compiler (protoc) not found.
         Please install protobuf-compiler for tracing support.
Checking for C header file Python.h... yes
Checking for C library python2.7... yes
Checking for C library pthread... yes
Checking for C library dl... yes
Checking for C library util... yes
Checking for C library m... yes
Checking for accept(0,0,0) in C++ library None... yes
Checking for zlibVersion() in C++ library z... yes
Checking for clock_nanosleep(0,0,NULL,NULL) in C library None... yes
Checking for timer_create(CLOCK_MONOTONIC, NULL, NULL) in C library None... no
Checking for timer_create(CLOCK_MONOTONIC, NULL, NULL) in C library rt... yes
Checking for C library tcmalloc... no
Checking for C library tcmalloc_minimal... no
You can get a 12% performance improvement by installing tcmalloc (libgoogle-perftools-dev package on Ubuntu or RedHat).
Checking for char temp; backtrace_symbols_fd((void*)&temp, 0, 0) in C library None... yes
Checking for C header file fenv.h... yes
Checking for C header file png.h... no
Warning: Header file <png.h> not found.
         This host has no libpng library.
         Disabling support for PNG framebuffers.
Checking for C header file linux/kvm.h... yes
Checking for C header file linux/if_tun.h... yes
Checking size of struct kvm_xsave ... yes
Checking for member exclude_host in struct perf_event_attr...yes

(以下略)

考察

作業環境の問題(弊iMacのCPUのCore数の問題)もあってか、ホストOSの作業を減らさないとbuild option -j 4ではかなり動作が遅くなってしまう模様。
ただ試してみるだけなら、build option -j 2でbuildした方が良かったのかもしれないです。

所感

ビルドに2時間くらいかかった記憶がありましたが、CPUにガンガン負荷をかけつつbuildが成功しました....

あとは、Dockerfileに記載のコマンドを順次実行して、sampleを試してたら、cacheが溜まるのかホストが動かなくなったので、docker system pruneでオサラバ。

git clone --depth 1の意味がザックリと理解できたこと、echo ${PASSWORD} | sudo -S commandでワンライナー実行できることなど、小技が学べたのが良かったです。

上記のみでは再現できない可能性がある(途中でやみくもにchmodしてた記憶がある)ので、細かい処理は(もし必要なら)弊社dockerhubレポジトリの:v1のterminal logを参照してください。

現在(2020年7月8日時点)、pipenvも動作するようなall-in-oneコンテナに改変するべくDockerfileを書きなぐっていますが、前回と異なる挙動をする(具体的には、sconsでSyntaxError: except hogehoge , e ^ みたいなエラーで止まる)ので、Docker-engineの送る処理とコマンドライン実行とでは違うのか...?それとも勝手にubuntu20:04に変えたのが間違い...?などと考えを巡らせています。(pipenvとvirtualenvはそもそも分離すべき...?)

参考

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

Kubernetesにおけるゼロダウンタイムデプロイメント

はじめに

新しいバージョンのアプリケーションをデプロイする時に、アプリケーションをコンテナで運用している場合は、コンテナを作り替える必要がある。デプロイ時に適切な手順を踏まないと、リクエストを正しく捌けずに、クライアントにエラーを返すことになる。これは本番環境で動いているアプリケーションに取ってはクリティカルな問題である。
Kubernetesは RollingUpdate をデフォルトで対応していため、デプロイは適切にManifestを設定をしていればダウンタイムなくデプロイしてくれる。新しいPodの生成からServiceへの追加はヘルスチェック(readnessProbe)を適切に設定するだけで良い。しかし、古いPodを停止する時には、色々考慮する問題が出てくる。適切に設定を行わないと、まだアプリケーションがリクエストを処理中にもかかわらず、Podを停止してしまうということが起こり得る。今回はこの問題を解決するために考察したことをまとめた。

KubernetesのPodを停止するまでの挙動

Kubernetesの挙動は以下のようになっている。

スクリーンショット 2020-07-08 午後4.17.28.png

Kubernetesでは「 preStop 処理 + SIGTERM 処理」と、「ServiceからのPodの除外処理」が非同期で行われる。コンテナは SIGTERM のシグナルが送られた場合に、適切に処理中のリクエストを捌き切ってから終了するようにする必要がある。そうでなければ、 SIGKILL シグナルがコンテナに送られて強制終了してしまう。したがって、適切な terminationGracePeriodSeconds を設定する必要がる。
また、 Service は、該当のコンテナに新しいリクエストを送らないように切り離すが、コンテナが処理を行っている途中である場合は、その接続を切断しないようにしなければいけない。

Service (LoadBalancer)

LoadBalancerがコンテナに新しいリクエストを送らないようにするとともに、現在行っている処理の接続を切断しないようにするために、Connection Drainingの設定をする必要がある。

例えば、EKSでは、 Connection Draining の有効化や、タイムアウトの設定を以下のように設定する。

manifest
apiVersion: v1
kind: Service
metadata:
    name: test
    annotations:
        service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "10"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "10"
spec:
...

アプリケーションのGraceful Shutdown

コンテナが安全に終了するためには、それぞれのコンテナがGraceful Shutdownをサポートしている必要がある。

例えば、 Gunicorn はGraceful Shutdownを対応している。適切に graceful_timeout の値を設定すれば問題ない。

https://docs.gunicorn.org/en/stable/settings.html

また、アプリケーションコンテナの前に Nginx のようなリバースプロキシを立てるのはよくある構成だが、その場合、 Nginx も同様に対応していないと、 Nginx が先に終了し、クライアントに 504(Gateway Timeout)が返ってしまう。
Nginx 自体はGraceful Shutdownに対応しているが、Graceful Shutdownを行うためのシグナルが、 SIGTERM ではなく、 SIGQUIT である。

TERM, INT   fast shutdown
QUIT    graceful shutdown

http://nginx.org/en/docs/control.html

そこで、終了時のシグナルを SIGTERM から SIGQUIT に変更してやる必要がある。

Dockerfile
FROM nginx:<version>

...

STOPSIGNAL SIGQUIT

https://github.com/nginxinc/docker-nginx/issues/377

また、タイムアウトは worker_shutdown_timeout の値を設定する。

http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout

コンテナ実行時の複数コマンド実行

SIGTERM シグナルはコンテナ内の PID 1 のプロセスに送られる。コンテナ起動時に複数コマンドを実行したい場合は、Startup Scriptを使うことはあるが、通常のスクリプトを用いると、そのスクリプトが PID 1 を持つことになり、アプリケーションにシグナルが送られない。
そこで、 exec を用いて、スクリプトのプロセスをアプリケーションのプロセスに変更することで対処できる。

Dockerfile
...

ENTRYPOINT ["./startup.sh"]
CMD ["runserver"]
startup.sh
#!/bin/sh
set -e

# コマンド

exec "$@"

PID 1問題

LinuxにおけるPID 1は通常 init である。 init は全てのプロセスの親であるため、このプロセスが殺されると、システムがダウンしてしまうため、特別扱いされている。具体的には、明示的にハンドラを設定していないシグナルは無視される。

NAME
        kill - send signal to a process

NOTES
       The only signals that can be sent to process ID 1, the init process,
       are those for which init has explicitly installed signal handlers.
       This is done to assure the system is not brought down accidentally.

https://man7.org/linux/man-pages/man2/kill.2.html

したがって、アプリケーションサーバが明示的に SIGTERM のハンドラを設定していない場合は、プロセスが SIGTERM を無視してしまい、終了処理が適切に行われない。 Node.js でこれが起きるらしい。

この問題の回避方法は「明示的にシグナルをハンドリングする」または、「アプリケーションのプロセスをPID 1以外で立ち上げる」の2つが考えられる。前者はそれぞれで対応すれば良い。前者が難しい場合は、後者を使う必要がある。

Kubernetes 1.17以上の場合は、ShareProcessNamespace を使ってPID 1を回避できる。

manifest
apiVersion: v1
kind: Pod
metadata:
    name: test
spec:
    shareProcessNamespace: true
...

Kubernetes以外、またはKubernetesのバージョンが低い場合は、 tiniのような軽量initと呼ばれるライブラリを使えば解決できる。

Dockerfile
...

ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

CMD ["runserver"]

参考

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

Docker(Docker)におけるゼロダウンタイムデプロイメント

はじめに

新しいバージョンのアプリケーションをデプロイする時に、アプリケーションをコンテナで運用している場合は、コンテナを作り替える必要がある。デプロイ時に適切な手順を踏まないと、リクエストを正しく捌けずに、クライアントにエラーを返すことになる。これは本番環境で動いているアプリケーションに取ってはクリティカルな問題である。
Kubernetesは RollingUpdate デフォルトで対応しているため、基本的にはKubebernetesに任せておけばうまく行く。しかし、古いPodを停止する時に、正しく設定を行わないと、まだアプリケーションがリクエストを処理中にもかかわらず、Podを停止してしまう。今回はこの問題を解決するために考察したことをまとめた。

KubernetesのPodを停止するまでの挙動

Kubernetesの挙動は以下のようになっている。

スクリーンショット 2020-07-08 午後4.17.28.png

Kubernetesでは「 preStop 処理 + SIGTERM 処理」と、「ServiceからのPodの除外処理」が非同期で行われる。コンテナは SIGTERM のシグナルが送られた場合に、適切に処理中のリクエストを捌き切ってから終了するようにする必要がある。そうでなければ、 SIGKILL シグナルがコンテナに送られて強制終了してしまう。したがって、適切な terminationGracePeriodSeconds を設定する必要がる。
また、 Service は、該当のコンテナに新しいリクエストを送らないように切り離すが、コンテナが処理を行っている途中である場合は、その接続を切断しないようにしなければいけない。

Service (LoadBalancer)

LoadBalancerがコンテナに新しいリクエストを送らないようにするとともに、現在行っている処理の接続を切断しないようにするために、Connection Drainingの設定をする必要がある。

例えば、EKSでは、 Connection Draining の有効化や、タイムアウトの設定を以下のように設定する。

manifest
apiVersion: v1
kind: Service
metadata:
    name: test
    annotations:
        service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "10"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "10"
spec:
...

アプリケーションのGraceful Shutdown

コンテナが安全に終了するためには、それぞれ使っているアプリケーションサーバがGraceful Shutdownをサポートしている必要がある。

例えば、 Gunicorn はGraceful Shutdownを対応している。適切に graceful_timeout の値を設定する必要がある。

https://docs.gunicorn.org/en/stable/settings.html

また、 Nginx はGraceful Shutdownに対応しているが、Graceful Shutdownを行うためのシグナルが、 SIGTERM ではなく、 SIGQUIT である。

TERM, INT   fast shutdown
QUIT    graceful shutdown

http://nginx.org/en/docs/control.html

そこで、終了時のシグナルを SIGTERM から SIGQUIT に変更してやる必要がある。

Dockerfile
FROM nginx:<version>

...

STOPSIGNAL SIGQUIT

http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout

コンテナ実行時の複数コマンド実行

SIGTERM シグナルはコンテナ内の PID 1 のプロセスに送られる。コンテナ起動時に複数コマンドを実行したい場合は、Startup Scriptを使うことはあるが、通常のスクリプトを用いると、そのスクリプトが PID 1 を持つことになり、アプリケーションにシグナルが送られない。
そこで、 exec を用いて、スクリプトのプロセスをアプリケーションのプロセスに変更することで対処できる。

Dockerfile
...

ENTRYPOINT ["./startup.sh"]
CMD ["python", "runserver"]
startup.sh
#!/bin/sh
set -e

# 処理

exec "$@"

PID 1問題

LinuxにおけるPID 1は通常 init である。 init は全てのプロセスの親であるため、このプロセスが殺されると、システムがダウンしてしまうため、特別扱いされている。具体的には、明示的にハンドラを設定していないシグナルは無視される。

NAME
        kill - send signal to a process

NOTES
       The only signals that can be sent to process ID 1, the init process,
       are those for which init has explicitly installed signal handlers.
       This is done to assure the system is not brought down accidentally.

https://man7.org/linux/man-pages/man2/kill.2.html

したがって、アプリケーションサーバが明示的に SIGTERM のハンドラを設定していない場合は、プロセスが SIGTERM を無視してしまい、終了処理が適切に行われない。 Node.js でこれが起きるらしい。

この問題の回避方法は「明示的にシグナルをハンドリングする」または、「アプリケーションのプロセスをPID 1以外で立ち上げる」の2つが考えられる。前者はそれぞれで対応すれば良い。前者が難しい場合は、後者を使う必要がある。

Kubernetes 1.17以上の場合は、ShareProcessNamespace を使ってPID 1を回避できる。

manifest
apiVersion: v1
kind: Pod
metadata:
    name: test
spec:
    shareProcessNamespace: true
...

Kubernetes以外、またはKubernetesのバージョンが低い場合は、 tiniのような軽量initと呼ばれるライブラリを使えば解決できる。

Dockerfile
...

ENTRYPOINT ["/tini", "--"]
CMD ["python", "runserver"]

参考

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

Kubernetes(Docker)におけるゼロダウンタイムデプロイメント

はじめに

新しいバージョンのアプリケーションをデプロイする時に、アプリケーションをコンテナで運用している場合は、コンテナを作り替える必要がある。デプロイ時に適切な手順を踏まないと、リクエストを正しく捌けずに、クライアントにエラーを返すことになる。これは本番環境で動いているアプリケーションに取ってはクリティカルな問題である。
Kubernetesは RollingUpdate デフォルトで対応しているため、基本的にはKubebernetesに任せておけばうまく行く。しかし、古いPodを停止する時に、正しく設定を行わないと、まだアプリケーションがリクエストを処理中にもかかわらず、Podを停止してしまう。今回はこの問題を解決するために考察したことをまとめた。

KubernetesのPodを停止するまでの挙動

Kubernetesの挙動は以下のようになっている。

スクリーンショット 2020-07-08 午後4.17.28.png

Kubernetesでは「 preStop 処理 + SIGTERM 処理」と、「ServiceからのPodの除外処理」が非同期で行われる。コンテナは SIGTERM のシグナルが送られた場合に、適切に処理中のリクエストを捌き切ってから終了するようにする必要がある。そうでなければ、 SIGKILL シグナルがコンテナに送られて強制終了してしまう。したがって、適切な terminationGracePeriodSeconds を設定する必要がる。
また、 Service は、該当のコンテナに新しいリクエストを送らないように切り離すが、コンテナが処理を行っている途中である場合は、その接続を切断しないようにしなければいけない。

Service (LoadBalancer)

LoadBalancerがコンテナに新しいリクエストを送らないようにするとともに、現在行っている処理の接続を切断しないようにするために、Connection Drainingの設定をする必要がある。

例えば、EKSでは、 Connection Draining の有効化や、タイムアウトの設定を以下のように設定する。

manifest
apiVersion: v1
kind: Service
metadata:
    name: test
    annotations:
        service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "10"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
        service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "10"
spec:
...

アプリケーションのGraceful Shutdown

コンテナが安全に終了するためには、それぞれのコンテナがGraceful Shutdownをサポートしている必要がある。

例えば、 Gunicorn はGraceful Shutdownを対応している。適切に graceful_timeout の値を設定すれば問題ない。

https://docs.gunicorn.org/en/stable/settings.html

また、アプリケーションコンテナの前に Nginx のようなリバースプロキシを立てるのはよくある構成だが、その場合、 Nginx も同様に対応していないと、 Nginx が先に終了し、クライアントに 504(Gateway Timeout)が返ってしまう。
Nginx 自体はGraceful Shutdownに対応しているが、Graceful Shutdownを行うためのシグナルが、 SIGTERM ではなく、 SIGQUIT である。

TERM, INT   fast shutdown
QUIT    graceful shutdown

http://nginx.org/en/docs/control.html

そこで、終了時のシグナルを SIGTERM から SIGQUIT に変更してやる必要がある。

Dockerfile
FROM nginx:<version>

...

STOPSIGNAL SIGQUIT

https://github.com/nginxinc/docker-nginx/issues/377

また、タイムアウトは worker_shutdown_timeout の値を設定する。

http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout

コンテナ実行時の複数コマンド実行

SIGTERM シグナルはコンテナ内の PID 1 のプロセスに送られる。コンテナ起動時に複数コマンドを実行したい場合は、Startup Scriptを使うことはあるが、通常のスクリプトを用いると、そのスクリプトが PID 1 を持つことになり、アプリケーションにシグナルが送られない。
そこで、 exec を用いて、スクリプトのプロセスをアプリケーションのプロセスに変更することで対処できる。

Dockerfile
...

ENTRYPOINT ["./startup.sh"]
CMD ["runserver"]
startup.sh
#!/bin/sh
set -e

# コマンド

exec "$@"

PID 1問題

LinuxにおけるPID 1は通常 init である。 init は全てのプロセスの親であるため、このプロセスが殺されると、システムがダウンしてしまうため、特別扱いされている。具体的には、明示的にハンドラを設定していないシグナルは無視される。

NAME
        kill - send signal to a process

NOTES
       The only signals that can be sent to process ID 1, the init process,
       are those for which init has explicitly installed signal handlers.
       This is done to assure the system is not brought down accidentally.

https://man7.org/linux/man-pages/man2/kill.2.html

したがって、アプリケーションサーバが明示的に SIGTERM のハンドラを設定していない場合は、プロセスが SIGTERM を無視してしまい、終了処理が適切に行われない。 Node.js でこれが起きるらしい。

この問題の回避方法は「明示的にシグナルをハンドリングする」または、「アプリケーションのプロセスをPID 1以外で立ち上げる」の2つが考えられる。前者はそれぞれで対応すれば良い。前者が難しい場合は、後者を使う必要がある。

Kubernetes 1.17以上の場合は、ShareProcessNamespace を使ってPID 1を回避できる。

manifest
apiVersion: v1
kind: Pod
metadata:
    name: test
spec:
    shareProcessNamespace: true
...

Kubernetes以外、またはKubernetesのバージョンが低い場合は、 tiniのような軽量initと呼ばれるライブラリを使えば解決できる。

Dockerfile
...

ENTRYPOINT ["/tini", "--"]
CMD ["runserver"]

参考

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

VPN越しのlinuxマシンにpingが通らない原因がdocker0だった

3ヶ月くらいずっと原因不明だったのがやっと解決したので備忘録として書き留めておく。

事象

⭕ローカルmac <-> ローカルmac
⭕ローカルmac <-> ローカルlinux
⭕ローカルmac <-> VPN越しmac
❌VPN越しmac <-> ローカルlinux

要は リモートで何故かlinuxマシンに接続できない! という状況が発生していた。

結論

VPN配下のIPアドレスとdocker0のIPアドレスが衝突していることが原因だった。

  • 今回の環境でVPN配下に割り振られるアドレス: 172.17.XXX.0/21
  • docker0のIPアドレス初期値: 172.17.0.1/16

これをdocker0のIPアドレス設定を変更し、dockerサービスを再起動することで解決した。

(情シスはこの事象既知なんだろうか:thinking:)

やったこと

わかっていること

  • VPN越しmac -> ローカルlinuxへping: Request timeout for icmp_seq XX
  • ローカルlinux -> VPN越しmacへping: From 172.17.0.1 icmp_seq=XX Destination Host Unreachable

事前に試してダメだったことのおさらい

今回の件には結局関係なかったけど一応チェックしといてねって箇所

  • そもそもicmpが塞がれていないか(検証手段が正しいのか)
    • mac同士のpingは通るので塞がれていないことがわかる
  • host.allow および host.deny の設定見直し
    • hosts.allow172.19.と記述しても変化なかった
  • firewall設定
    • 無効化しても変化なかった

自身のアドレスを確認

pingのエラーメッセージから、 172.17.0.1とかいうよくわからん経路でコケてることは分かっていた

ふとdocker周りのネットワークが気になったので、自身のアドレスをすべて確認してみることにする

$ hostname -I
172.19.XXX.XXX 172.17.0.1 172.18.0.1 192.168.XXX.XXX ...

172.17.0.1がいる???なんで???

$ ip a
### 略 ###

2: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.30.0.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 XXXX::XXXX:XXXX:XXXX:XXXX/64 scope link 

### 略 ###

docker0とかいう仮想インターフェイスがガッツリIPアドレス被りしている模様なので、これを変更してみる

ちなみにdocker0はdocker for linuxのみでしか生成されず、これがlinuxへの疎通のみNGという理由にもなっていた

docker0の設定変更

先人の大変ありがたい資料があるので、参考に設定を進める
https://qiita.com/msi/items/d9cc1a2fd3f0fed3a901

$ sudo vi /etc/docker/daemon.json
{
    "bip": "172.30.0.254/24"
}

$ sudo systemctl restart docker

$ ip a show docker0
2: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 172.30.0.254/24 brd 172.30.0.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 XXXX::XXXX:XXXX:XXXX:XXXX/64 scope link 

ping

# VPN越しmac -> ローカルlinux
$ ping 172.19.XXX.XXX
64 bytes from 172.19.XXX.XXX: icmp_seq=0 ttl=60 time=192.154 ms
64 bytes from 172.19.XXX.XXX: icmp_seq=1 ttl=60 time=238.941 ms
64 bytes from 172.19.XXX.XXX: icmp_seq=2 ttl=60 time=292.419 ms
64 bytes from 172.19.XXX.XXX: icmp_seq=3 ttl=60 time=257.762 ms

✌️success✌️

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

[Docker][Rails] 新しくGemを導入した後の3コマンド

これはなに

Railsでアプリ開発中新しくGemを導入した後、若干躓いたので備忘録として残します。
ご指摘等あれば頂けると幸いです。

3コマンド

gem bundle install
docker-compose run web bundle install

参考記事
Docker Compose + Railsでイメージ内でbundle installしているはずなのにgemが無いとエラーがでる。

docker-compose restart

参考記事
dockerの起動、停止、再起動

以上です!ありがとうございました!

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

RabbitMQをインストールする(Windows/Mac/Docker)

最終更新日

2020年7月8日

検証を行ったOS/Dockerのバージョンは下記です。

  • Windows 10 Home 64bit 2004 19041.329
  • macOS Catalina 10.15.5
  • Docker Desktop for Mac 2.3.0.3

インストールするもののバージョンは下記です。

  • RabbitMQ 3.8.5

この記事が古くなった場合、下記の手順は最新のインストール手順とは異なっている可能性があります。その場合は公式ドキュメントをご確認ください。

Windowsの場合

Erlangのインストール

(1) https://erlang.org/download/otp_versions_tree.html からEralngのインストーラーをダウンロードしてください。

スクリーンショット 2020-07-08 15.51.43.png

(2) インストーラーをダブルクリックしてください。

(3) [はい]をクリックしてください。

スクリーンショット 2020-07-08 16.01.50.png

(4) [Next]をクリックしてください。

スクリーンショット 2020-07-08 16.02.19.png

(5) [Next]をクリックしてください。

スクリーンショット 2020-07-08 16.02.45.png

(6) [Install]をクリックしてください。

スクリーンショット 2020-07-08 16.03.11.png

(7) [Close]をクリックしてください。

スクリーンショット 2020-07-08 16.04.28.png

RabbitMQのインストール

(1) https://www.rabbitmq.com/install-windows.html#installer からRabbitMQのインストーラーをダウンロードしてください。

スクリーンショット 2020-07-08 16.00.39.png

(2) インストーラーをダブルクリックしてください。

(3) [はい]をクリックしてください。

スクリーンショット 2020-07-08 16.04.59.png

(4) [Next]をクリックしてください。

スクリーンショット 2020-07-08 16.05.26.png

(5) [Install]をクリックしてください。

スクリーンショット 2020-07-08 16.05.51.png

(6) [Windows セキュリティの重要な警告]が表示されたら[アクセスを許可する]をクリックしてください。

(7) [Next]をクリックしてください。

スクリーンショット 2020-07-08 16.07.17.png

(8) [Finish]をクリックしてください。

スクリーンショット 2020-07-08 16.07.42.png

(9) 環境変数 PATH に、 RabbitMQがインストールされたフォルダ\sbin (例: C:\Program Files\RabbitMQ Server\rabbitmq_server-3.8.5\sbin )を追加してください。

RabbitMQの設定(必要に応じて)

(1) コマンドプロンプトで rabbitmq-plugins enable rabbitmq_management を実行してください。

スクリーンショット 2020-07-08 16.16.30.png

(2) コマンドプロンプトで rabbitmq-plugins enable rabbitmq_tracing を実行してください。

スクリーンショット 2020-07-08 16.17.28.png

macOSの場合

RabbitMQのインストール

(1) ターミナルで brew install rabbitmq を実行してください。

Homebrewがインストールされていない場合は、公式サイトを参考にインストールしてください。

(2) 環境変数 PATH/usr/local/sbin を追加してください。

(3) ターミナルで rabbitmq-server を実行してください。これでRabbitMQが起動します。

スクリーンショット 2020-07-08 16.31.27.png

Ctrl + Cで停止します。

RabbitMQの設定(必要に応じて)

(1) ターミナルで rabbitmq-plugins enable rabbitmq_management を実行してください。

(2) ターミナルで rabbitmq-plugins enable rabbitmq_tracing を実行してください。

Dockerの場合

Dockerのインストール方法は別記事にて紹介しています(Windows 10 Proの場合macOSの場合

(1) 次のようなDockerfileを作成してください。

Dockerfile
FROM rabbitmq:3.8.5-management-alpine

RUN rabbitmq-plugins enable rabbitmq_tracing

EXPOSE 5672 15672

(2) ターミナル(orコマンドプロンプト)でDockerfileを作成したフォルダに移動して、 docker image build -t rabbitmq-scd . を実行してください。

$ docker image build -t rabbitmq-scd .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM rabbitmq:3.8.5-management-alpine
3.8.5-management-alpine: Pulling from library/rabbitmq
df20fa9351a1: Pull complete 
6a4ed0140701: Pull complete 
d144d94e32f5: Pull complete 
4d0a1f15085c: Pull complete 
3efe37eb67c8: Pull complete 
21fb2255fd06: Pull complete 
8d1fc732c7d2: Pull complete 
ebf280fe3644: Pull complete 
947f27a4fe95: Pull complete 
Digest: sha256:7bb012930d5fa185ad5a52e0693096eb4628fba48b9ad7303edb09b80c47ad0c
Status: Downloaded newer image for rabbitmq:3.8.5-management-alpine
 ---> 4e6d459e4748
Step 2/3 : RUN rabbitmq-plugins enable rabbitmq_tracing
 ---> Running in beba71787921
Enabling plugins on node rabbit@beba71787921:
rabbitmq_tracing
The following plugins have been configured:
  rabbitmq_management
  rabbitmq_management_agent
  rabbitmq_tracing
  rabbitmq_web_dispatch
Applying plugin configuration to rabbit@beba71787921...
The following plugins have been enabled:
  rabbitmq_tracing

set 4 plugins.
Offline change; changes will take effect at broker restart.
Removing intermediate container beba71787921
 ---> 8aacc20abf9a
Step 3/3 : EXPOSE 5672 15672
 ---> Running in f84d57362063
Removing intermediate container f84d57362063
 ---> 0ab7f38dc713
Successfully built 0ab7f38dc713
Successfully tagged rabbitmq-scd:latest

(3) ターミナル(orコマンドプロンプト)で docker container create -p 5672:5672 -p 15672:15672 --name rabbitmq-scd rabbitmq-scd を実行してください。

$ docker container create -p 5672:5672 -p 15672:15672 --name rabbitmq-scd rabbitmq-scd
67473dcbed40bee46c5f9b3531763ed71fd6cd5b6a6cb1364b90da21d621ce59

(4) ターミナル(orコマンドプロンプト)で docker container start rabbitmq-scd を実行してください。これでRabbitMQが起動します。

$ docker container start rabbitmq-scd
rabbitmq-scd

docker container stop rabbitmq-scd で停止します。

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

dockerのマウントについて 初学者なりに考えた。 自分用のメモ

マウントについて

バインドマウント(bind)

Dockerホストのファイルやディレクトリをコンテナ上にマウントする機能
バインドマウントを行うと、コンテナの外にあるファイルを、コンテナの中から読み書き可能になります。

ボリュームマウント(volume)

Docker が管理するデータ領域を コンテナ上にマウントする機能です。

バインドマウントとの違いは、バインドマウントが「Dockerが管理するデータ領域以外もマウント可能である」ことに対し、ボリュームマウントは「Dockerが管理するデータ領域内でのマウントのみ可能である」という点です。

ホストマシン上に新たなディレクトリが生成され、そこが Dockerの保存ディレクトリとなります。 そしてDockerはそのディレクトリ内の内容を管理していきます。コンテナが破棄させるとvolumesに保存される。ホストのデータが更新され、コンテナを立ち上げれば、volumeの既存データもupdateされる。

一時ファイルシステムのマウント(tmpfs)

Dockerホストにファイルとして保存したくないデータを一時的に利用できるようにする(データ領域をメモリ上に置く)機能。

ホストマシンとは 

ホストマシンとコンテナでディレクトリを同期させることができるが、 注意しておきたいのが, ここでいうホストマシンとはMacのことではない。
Mac上で起動しているのはdockerの仮想Linuxマシンであること。そもそもコンテナというものはLinuxカーネルに使われている技術。したがってMacでコンテナ技術を使うためには, 間に仮想Linuxマシンをはさまなくてはならない。
Macとコンテナはデータのやりとりができないのかというとそうではない。 仮想Linuxマシンからは, Mac全体が/Macとして参照できるらしい。
つまりMac全体が仮想Linuxマシンにマウントされているとのこと。 他にもMac上の/Usersが仮想Linuxマシンからも/Usersでアクセスできる。

実際にdocker run コマンドを使用しバインドマウントを行って見た。
Hostディレクトリ構成

docker run -it -d -p 8080:80 -v /Users/hamadayuuta/Desktop/test_dk/test3/:/var/lib/test/ nginx:latest 

バインドマウント先は任意のコンテナ内のディレクトリが作成可能。

/User~ : まではホストのターゲットpath
/var/lib/ → dockerコンテナ内のpath。環境はlinux環境
/test/は任意のディレクトリを作成。 ここがマウント領域になる。

docker exec -it nginx:latest /bin/bashで見にいくと

root@b00e211eff2b:/# cd ./var/lib/test/
root@b00e211eff2b:/var/lib/test# ls
index.html

マウントを確認。

docker inspectで確認すると

"Mounts": [
            {
                "Type": "bind",
                "Source": "/Users/hamadayuuta/Desktop/test_dk/test3",
                "Destination": "/var/lib/test",

マウントを確認できました。

コンテナはlinuxのプロセス空間を用いて作成したものであるから、 マウントをする際はlinuxのディレクトリ構造をイメージして作成しないといけないかな。→間違えてたらすみません。

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

Docker ComposeのMySQLに初期データを設定する

初期データ

initdb.dフォルダを作成してinit.sqlpet.txtを配置する。

init.sqlの内容はテーブル削除、作成データ挿入を記述

init.sql
drop table if exists pet;
create table if not exists pet (
       name varchar(20)
       , owner varchar(20)
       , species varchar(20)
       , sex char(1)
       , birth date
       , death date
);
load data local infile '/docker-entrypoint-initdb.d/pet.txt' into table pet;

pet.txtの内容はテーブルに挿入するデータをcsv形式で記述

pet.txt
Fluffy  Harold  cat f   1993-02-04  \N
Claws   Gwen    cat m   1994-03-17  \N
Buffy   Harold  dog f   1989-05-13  \N
Fang    Benny   dog m   1990-08-27  \N
Bowser  Diane   dog m   1979-08-31  1995-07-29
Chirpy  Gwen    bird    f   1998-09-11  \N
Whistler    Gwen    bird    \N  1997-12-09  \N
Slim    Benny   snake   m   1996-04-29  \N

設定

docker-compose.ymlvolumesに初期データフォルダを記述する。
ローカルのinitdb.dフォルダをコンテナ内にdocker-entrypoint-initdb.dフォルダで配置する。
dockerhub - mysql

docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
      - ./initdb.d:/docker-entrypoint-initdb.d
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: my_test
      MYSQL_USER: mysql
      MYSQL_PASSWORD: mysql

volumes:
  db_data: {}

起動

いつも通りにコンテナを起動する。

$ docker-compose up -d

終わり

起動後にデータを入れ直す

コンテナをdown --volumesして再度upすれば良いんだろうけど。。。
別の方法と言うことで、

コンテナ内に入る。

$ docker-compose exec mysql /bin/bash

コンテナ内でmysqlコマンドをバッチモードで実行する。

# mysql -u mysql --password=mysql my_test < /docker-entrypoint-initdb.d/init.sql

コンテナ内から出る。

# exit

ほんとに終わり

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

Ubuntu 16.04での「Docker」のインストールと使い方

このチュートリアルでは、Alibaba CloudDockerをインストールする方法を探り、コンテナサービスのデプロイと管理に役立ついくつかの重要なDockerコマンドを学びます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

序章

Dockerは、開発者やシステム管理者向けのオープンソースプロジェクト(コンテナ管理サービス)で、ラップトップ、データセンターのVM、クラウド上で分散アプリケーションを構築、出荷、実行し、コンテナに出荷することで、どこにでもデプロイできるようにします。Dockerは、WindowsとLinuxベースのオペレーティングシステム上でオペレーティングシステムレベルの仮想化の自動化を提供します。
Dockerを使用することで、特定のスタックに依存することなく、簡単にWebアプリ、データベース、バックエンドサービスをデプロイしてスケーリングするためのブロックを構築することができます。

Dockerはいくつかのコンポーネントで構成されています。
1)Docker for Linux:Linux OS上でDockerコンテナを実行できるようにします。
2) Docker Engine:Dockerイメージの構築やDockerコンテナの作成に使用します。
3) Docker Hub:様々なDockerイメージを保存するために使用します。
4) Docker Compose: 複数のDockerコンテナを使用してアプリケーションを定義するために使用します。

特徴

  • Docker Swarmは、Dockerエンジンのグループを単一の仮想Dockerエンジンに変えるDockerコンテナのクラスタリングソリューションを提供します。
  • Dockerは、小さなフットプリントのオペレーティングシステムを提供することで、開発の規模を縮小する能力を持っています。
  • Dockerコンテナは非常に軽量で、容易に拡張可能です。
  • 簡単かつ高速な設定を提供し、生産性を向上させる。
  • アイソレーション環境であらゆる種類のアプリケーションを実行できるコンテナを提供する。

このチュートリアルでは、Dockerをインストールする方法を説明し、いくつかの重要なDockerコマンドを説明します。また、コマンドがどのように使われているのか、どのようなことをするのかについて、いくつかのハンズオン体験を共有します。

前提条件

  • Ubuntu 16.04をインストールした新鮮なAlibaba Cloud ECSインスタンス。
  • インスタンスにルートパスワードが設定されています。

Dockerのインストール

始める前に、Dockerの最新版をサーバーにインストールする必要があります。デフォルトでは、最新版のDockerはUbuntu 16.04のリポジトリでは利用できません。そのため、公式のDockerリポジトリをサーバーに追加する必要があります。

まず、以下のコマンドで公式DockerリポジトリのGPGキーをダウンロードしてシステムに追加します。

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -を実行します。

次に、以下のコマンドでDockerリポジトリをaptのソースに追加します。

echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial stable" | sudo tee -a /etc/apt/sources.list.d/docker.list

次に、リポジトリを更新し、以下のコマンドでDockerをインストールします。

shell
apt-get update -y
apt-get install  docker-ce -y

Dockerをインストールしたら、以下のコマンドでDockerの状態を確認することができます。

shell
systemctl status docker

● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2017-12-08 20:46:13 IST; 3min 2s ago
     Docs: https://docs.docker.com
 Main PID: 926 (dockerd)
    Tasks: 45
   Memory: 79.2M
      CPU: 7.463s
   CGroup: /system.slice/docker.service
           ├─ 926 /usr/bin/dockerd -H fd://
           ├─1453 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --st
           ├─2285 docker-containerd-shim e4202324477ae1870a77e12863ab3c79661cf8b7bfa617bb5709a816ea85194e /var/run/docker/libcontainerd/e420232
           └─2290 docker-containerd-shim 97bf4d277e0563906318bb276c3c65ebc274f28b6bb86cce80def795ecba76e2 /var/run/docker/libcontainerd/97bf4d2

Dockerイメージのダウンロード

コンテナはDockerイメージを使って構築するので、まずはDockerイメージを引っ張ってくる必要があります。Dockerのサイトにはすでにたくさんのイメージが公開されています。簡単な検索コマンドで任意のイメージを見つけることができます。

例えば、Ubuntu 16.04のイメージを検索するには、以下のコマンドを実行します。

docker search ubuntu:16.04

すると、Dockerのウェブサイトに以下のような画像が公開されているはずです。

shell
NAME                                           DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
ubuntu                                         Ubuntu is a Debian-based Linux operating s...   6917                [OK]                
ubuntu-upstart                                 Upstart is an event-based replacement for ...   80                  [OK]                
ubuntu-debootstrap                             debootstrap --variant=minbase --components...   32                  [OK]                
mlaccetti/docker-oracle-java8-ubuntu-16.04     Oracle Java 8 on Ubuntu 16.04 LTS               4                                       [OK]
gocd/gocd-agent-ubuntu-16.04                   Docker GoCD agent for Ubuntu 16.04              2                                       
seresearch/opendavinci-ubuntu-16.04            Docker image with all Ubuntu 16.04 depende...   2                                       [OK]
proudmail/ubuntu-16.04                         Create ubuntu 16.04                             1                                       [OK]
superkumkum/ubuntu-16.04                       base image of ubuntu 16.04                      0                                       [OK]
gocdexperimental/gocd-agent-ubuntu-16.04       Experimental GoCD Agent - Ubuntu 16.04          0                                       
dokken/ubuntu-16.04                            For use with kitchen-dokken, Base image pl...   0                                       
keithf/ubuntu-16.04-armhf                      Ubuntu 16.04 for ARM-based devices.             0                                       
neoncluster/ubuntu-16.04                       Ubuntu 16.04 image with recent package upg...   0                                       
cdbishop89/docker-ubuntu-16.04                 Base Ubuntu 16.04 Image                         0                                       [OK]
vlex/ubuntu-16.04-node                         Ubuntu 16.04 with node 6.1.0                    0                                       
seresearch/opendavinci-ubuntu-16.04-complete                                                   0                                       
itsspeed/ubuntu-16.04-python                   Base Ubuntu 16.04 image with python and pi...   0                                       
syseleven/ubuntu-16.04-puppet4                 ubuntu-16.04-puppet4                            0                                       [OK]
opencpu/ubuntu-16.04                           OpenCPU Server builds for Ubuntu 16.04 (Xe...   0                                       [OK]
lgong/mml-ubuntu-16.04                                                                         0                                       
stafory/ubuntu-16.04-ci                                                                        0                                       
kensenshi/ubuntu-16.04-oracle-java8-ant        Oracle Java 8 and ANT on Ubuntu 16.04.          0                                       
naritadev/narita-ubuntu-16.04                  Narita Ubuntu 16.04 Distro                      0                                       
addle/ubuntu-16.04                             Ubuntu 16.04 LTS (Xenial Xerus)                 0                                       
uberr2000/ink-ubuntu-16.04                     ubuntu 16.04 with nginx ,phalcon ,mysql,ph...   0                                       
syseleven/ubuntu-16.04-puppet5                 ubuntu-16.04-puppet5                            0                                       [OK]

次に、上記の画像からUbuntu-16.04のベースイメージをダウンロードします。

docker pull ubuntu

出力は以下のようになります。

Using default tag: latest
latest: Pulling from library/ubuntu
660c48dd555d: Pull complete 
4c7380416e78: Pull complete 
421e436b5f80: Pull complete 
e4ce6c3651b3: Pull complete 
be588e74bd34: Pull complete 
Digest: sha256:7c67a2206d3c04703e5c23518707bdd4916c057562dd51c74b99b2ba26af0f79
Status: Downloaded newer image for ubuntu:latest

ダウンロードが完了したら、以下のコマンドを実行することで、システム上で利用可能なすべてのイメージを一覧表示することができます。

docker images

出力します。

REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
ubuntu                       latest              20c44cd7596f        3 weeks ago         123MB

Dockerコンテナの起動

さて、基本的なubuntu-16.04のコンテナをbashシェルで設定するには、コマンドを1つ実行するだけです。

docker run -i -t ubuntu /bin/bash

以下のような出力が表示されるはずです。

root@0b775c3f606d:/#

さて、Ubuntuのベースイメージとインスタンスの準備ができたら、Apacheサーバをインタラクティブにインストールすることができます。そのためには、ターミナルで以下のコマンドを実行する必要があります。

shell
apt-get update -y
apt-get install apache2 apache2-utils -y

これで、Ubuntu Dockerコンテナ内でbashシェルを使用していることになります。終了せずにシェルから切り離す、または切り離すには、Ctrl-p + Ctrl-qのエスケープシーケンスを使用します。

これで、Ubuntuインスタンスで行った変更を保存することができます。そのためには、まず、実行中のUbuntuインスタンスのコンテナIDが必要になります。それを取得するには、実行します。

docker ps

以下のような出力が表示されるはずです。

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
0b775c3f606d        ubuntu              "/bin/bash"              36 minutes ago      Up 36 minutes                               dreamy_murdock

さて、以下のコマンドを実行して、変更内容をubuntu-apacheという名前の新しいイメージとして保存します。

docker commit 0b775c3f606d ubuntu-apache

sha256:6997db13c6587d1403c2360515d29028a30de786101c4ec26faddc505f5242c4

コンテナIDとイメージ名ubuntu-apacheを使用して変更が保存されていることがわかります。
新しいイメージが実行されているかどうかを確認するには、実行します。

docker images

REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
ubuntu-apache                latest              6997db13c658        30 seconds ago      261MB
ubuntu                       latest              20c44cd7596f        3 weeks ago         123MB

Dockerでアプリケーションを起動

これで、Apache Web サーバを含む新しいイメージができました。そのイメージを元にDockerfileをビルドし、必要なファイルを追加することができます。サイトコンテンツのtarballへの相対パスが与えられると、Dockerは自動的にソースのtarまたはzipファイル内のファイルをターゲットディレクトリにアンタールまたはアンジップします。

これを行うには、ホストシステム上にindex.htmlファイルを作成し、カレントディレクトリにあるapplication.tarというtarballに追加する必要があります。

mkdir application
nano application/index.html

以下の行を追加します。

html
<html>
Sample Apache Web Page
</html>

保存してファイルを閉じます。

それでは、tarを使ってWebサイトのディレクトリを圧縮します。

tar -cvf application.tar application

さて、Webサイトの内容をubuntu-apacheイメージに追加するためのDockerfileを作成し、ポート80でApacheを起動します。

nano Dockerfile

以下の行を追加します。

Dockerfile
FROM ubuntu-apache
ADD application.tar /tmp/
RUN mv /tmp/application/* /var/www/html/
EXPOSE 80
ENTRYPOINT [ "/usr/sbin/apache2ctl" ]
CMD [ "-D", "FOREGROUND" ]

保存してファイルを閉じます。

上記のDockerfileでは、website.tar内のwebsiteの内容が自動的に/tmp/フォルダに展開されます。そして、サイト全体がApacheのルートディレクトリ/var/www/html/に移動し、expose80が80番ポートを開くので、正常にサイトが利用できるようになります。そして、エントリーポイントを/usr/sbin/apache2に設定して、Apacheサーバが実行されるようにします。

さて、先ほど作成したDockerfileを使ってコンテナを構築し、その上にWebサイトを追加していきます。

そのためには、以下のコマンドを実行します。

docker build -t application .

以下のような出力が表示されるはずです。

shell
Sending build context to Docker daemon  71.68kB
Step 1/6 : FROM ubuntu-apache
 ---> 6997db13c658
Step 2/6 : ADD application.tar /tmp/
 ---> 9b20f474c3a0
Step 3/6 : RUN mv /tmp/application/* /var/www/html/
 ---> Running in 6f0b4a29cc8a
 ---> a5ffa4710b58
Removing intermediate container 6f0b4a29cc8a
Step 4/6 : EXPOSE 80
 ---> Running in e4ef5dfc0838
 ---> a584d0068bb6
Removing intermediate container e4ef5dfc0838
Step 5/6 : ENTRYPOINT /usr/sbin/apache2ctl
 ---> Running in ab5bda3f593a
 ---> 65f187a34ce6
Removing intermediate container ab5bda3f593a
Step 6/6 : CMD -D FOREGROUND
 ---> Running in b8ddd1d006b5
 ---> 354383fb2666
Removing intermediate container b8ddd1d006b5
Successfully built 354383fb2666
Successfully tagged application:latest

イメージが構築できたら、その上でApacheのインスタンスを実行するコンテナを作成して進めます。

docker run -d -P application

出力します。
a749b23fb87c821b69479353bf067f2b1af53fd0fd300ad86ac5c028dd5dcbde

さて、"docker ps "コマンドを使用してアクティブ化されたポートを判断し、curlを使用してサンプルの内容を検査します。

docker ps

以下のような出力が表示されるはずです。

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
a749b23fb87c        application         "/usr/sbin/apache2..."   30 seconds ago      Up 28 seconds       0.0.0.0:32768->80/tcp   nifty_bose

ここで、以下のコマンドを実行してApache Webサーバを確認します。

curl localhost:32768

または

curl "Container IP Address”:80

先ほど作成したApacheのWebページが表示されているはずです。

html
<html>
Sample Apache Web Page
</html>

Dockerコマンドを使った作業

まずはDockerが持っているすべての利用可能なコマンドを見てみましょう。以下のコマンドを実行することで、利用可能なDockerコマンドをすべて一覧表示することができます。

docker

Dockerのバージョンを確認するには、実行します。

docker version

出力します。

Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:42:18 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:40:56 2017
 OS/Arch:      linux/amd64
 Experimental: false

Dockerのシステム全体の情報を確認するには、実行します。

docker info

以下のような出力が表示されるはずです。

Containers: 2
 Running: 1
 Paused: 0
 Stopped: 1
Images: 2
Server Version: 17.09.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog

実行中のコンテナをすべてリストアップするには、実行します。

docker ps

作成した最新のコンテナを一覧表示するには、実行します。

docker ps -l

実行中のコンテナと実行していないコンテナの両方をリストアップするには、実行します。

docker ps -a

コンテナのプロセスを起動・停止するには、以下のように実行します。

docker start "Container ID”
docker stop "Container ID"

実行中のコンテナをすべて停止するには、実行します。

docker stop $(docker ps -a -q)

注: コンテナIDはsudo docker psコマンドを使って調べられます。

実行中のコンテナにアタッチしたい場合、Dockerではattachコマンドを使って実行中のコンテナと対話することができます。

docker attach "Container ID”

コンテナIDを指定したexpectコマンドを使うと、Dockerコンテナに関するあらゆる情報を確認することができます。

docker inspect "Container ID”

単一のコンテナを削除するには、実行します。

docker rm "Container ID”

既存のコンテナをすべて削除するには、実行します。

docker rm $(docker ps -a -q)

注: コンテナを削除する前に、まずコンテナを停止する必要があります。

1つのイメージを削除するには、image IDを指定してrmiコマンドを使用します。イメージIDは "docker images "コマンドを使って取得できます。

docker rmi "Image ID”

既存のイメージをすべて削除するには、実行します。

docker rmi $(docker images -q -a)

Dockerコンテナをデーモンとして実行している場合、実行中のコンテナのコンソール出力に何が表示されるかを知っておくと便利かもしれません。

Docker logsコマンドは実行時に存在するログを取得します。

コンテナIDを指定してDocker logコマンドを使うことができます。

docker log -f "container ID”

結論

おめでとうございます。これでDockerのインストールと実行が完了しました。これで、本番環境でDockerコンテナをインストールして使うための知識が十分に身についたと思います。Dockerの詳細については、Dockerの公式ドキュメントページを参照してください。その他のチュートリアルは、Alibaba Cloud Getting Startedチャンネルにも掲載されています。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

Dockerってなに?

はじめに

僕自身「Dockerってよく聞くけどなんのこと?」状態だったので気になって調べてみました。

仮想化とは

Dockerに触れる前に必要な知識として仮想化について簡単に説明します。
仮想化とは物理的な1台のサーバー上で、複数の仮想的なサーバー(仮想サーバー)を運用することを「サーバーの仮想化」といいます。

簡単に例えると、windowsのpcで macのosを使えるようになりますよ みたいな

Docker

Dockerはこの仮想化を実現するための技術の一つです。

従来の仮想化技術(ホスト型 、 ハイパーバイザー型)では
1つのアプリケーションを起動するのに、1つのosを立ち上げていたため、起動に時間がかかるなどのデメリットがありました。

~従来イメージ~

A家の中にもうひとつ別のB家を建てて、B家のキッチンで料理する

ですがDockerはアプリケーション単位で仮想環境を切り替えるので従来のデメリットを打ち消すことができます。

~Dockerイメージ~

A家の中にもうひとつ新しいキッチンを作り料理する

Dockerのメリット

  ①環境構築が簡単
  ②立ち上げ速度がはやい
  ③ハードウェアの資源削減
などが挙げられます。

まとめ

仮想の中での話なのでイメージしづらいですね。
今後もDockerが普及し続けることが予想されますのでしっかり理解していきたいですね。

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

DockerでGolangをサクッと動かす

はじめに

ちょっとGolangを触ってみたくなったけど、
どう環境構築するのがいいのか考えるのがめんどくさかったり(当時はGOPATHってなに?って感じだった)
下手なことしてローカル環境汚すのがやだなぁとか思って、Dockerで動かしてみた時のメモ

前提として、Docker, docker-composeは動かせること

docker runコマンドのオプションをつらつらとかきたくなかったのでdocker-composeを使ってる

ディレクトリ構成とファイル作成

下記のようなディレクトリ構成でファイル作成

.
├── Dockerfile
├── docker-compose.yml
└── workspace
    └── main.go

Dockerfileとdocker-composeは以下のような感じ

FROM golang:1.14.2

WORKDIR /go/src/workspace

(当時A Tour of Goをやろうかなとか思ってたのでtour

docker-compose.yml
version: '3'
services:
  tour: 
    build: .
    tty: true
    volumes:
      - .:/go/src

main.goではとりあえずHello Worldしてみる

main.go
package main

import "fmt"

func main() {
  fmt.Println("Hello World")
}

動かし方

  % docker-compose up -d
Creating network "go_default" with the default driver
Creating go_tour_1 ... done

  % docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                               NAMES
179cce348068        go_tour                   "bash"                   40 seconds ago      Up 38 seconds                                           go_tour_1

  % docker-compose exec tour go run main.go
Hello World

ファイルはマウントしてるのでコンテナの外からmain.goを好きにいじって保存すればそのままコンテナにも反映されてRunしなおせる
もちろんdocker-compose exec tour bashとかでコンテナに入っても良し

※ここではしてないが、Golangはコンパイラ言語なので基本的にはgo buildでコンパイルするもの

さいごに

これすらもめんどくさい時はPlaygroundを使おう

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

ローカルでも CI でも使える卒論ビルド環境

TL;DR

ローカルビルドにも CI にも使える卒論 LaTeX のビルド環境を作った

概要

卒論を LaTeX で書くことになったが、環境構築を複数のマシンでするのがつらく、CI の自動ビルドを構築するのもつらい。Docker とビルドスクリプトで両方なんとかならないか考えていたらなんとかなったのでいくつか考慮するポイントを書き残しておく。

ソースコード

ローカルのビルドにも利用でき、実際に CI も走っているリポジトリ。プレビューは preview ブランチ。

kirchen-bell/paper-env

できること

  • ローカルで docker-compose up するだけで論文がビルドできる
  • GitHub にプッシュすればローカルと同じビルド環境で勝手に CI してくれて preview ブランチの PDF が更新される
  • devcontainer にも対応しているのでビルド環境のシェルでゴニョゴニョできる ( devcontainer の起動のために VSCode が必要)

解説

CI は GitHub Actions で構築するが、 Actions では任意の Docker イメージ上で作業できるため、基本的には:

  • ビルド環境の Docker イメージ
  • 上のイメージ上で正しく動作するビルドスクリプト

の2つが用意できればローカルでのビルド・CI での自動ビルドどちらも同じ環境で実行できる。

ビルドスクリプト

以下の2点に気をつける:

  • PDF ファイルの出力先を指定できるようにする

    大抵は .tex ファイルのあるディレクトリでビルドスクリプトを叩くとそのディレクトリに .pdf が生成されることを期待するが、最終的にプレビューブランチにデプロイしたいので、全ての成果物を1つのディレクトリにまとめておきたい。そのため、実行時にデフォルトの出力先を変更できるようにする。

    例えば、 Makefile なら:

    # paper-env/src/Makefile
    # command
    LATEX = platex
    DVIPDF = dvipdfmx
    ...
    
    # files
    TARGET = paper
    SRC = $(TARGET).tex
    DVI = $(TARGET).dvi
    PDF = $(TARGET).pdf
    ...
    
    # output directory
    OUT_DIR = $(TARGET).pdf
    
    $(PDF): $(DVI)
        $(DVIPDF) -o $(OUT_DIR) $<
    ...
    

    そして、実行時に

    $ make OUT_DIR=[output directory]/paper.pdf
    

    とする。

  • GITHUB_WORKSPACE 環境変数に対応する

    GitHub Actions での CI の際、checkout されたリポジトリが格納されたディレクトリを GITHUB_WORKSPACE 環境変数として渡してくれる:

    Using environment variables

    もし、ビルドスクリプト内で絶対パスを用いる必要がある場合は、この環境変数に対応する必要がある。

Docker, Docker Compose

ビルド環境を Docker イメージとして固めておけば良い。 Docker Hub でも GitHub Packages でもどちらに置いてもイメージのプルにかかる時間はあまり変わらなかったので、ここはログインなしでもプルできる Docker Hub がおすすめ。 (GitHub Packages はなんでパブリックイメージのプルにもログインが必要なんですか…?)

LaTeXpandoc を扱えるイメージはたくさん転がっているため、それらを使っても良いし、自分の都合に合わせて作っても良いと思う。私のビルド環境イメージはこれ:

sarisia/tex

実行時は、生の docker コマンドを叩いても良いが、ディレクトリのマウントやコマンドの指定が面倒なので docker-compose.yml を書いておくと楽:

# paper-env/docker-compose.yml
version: "3"
services: 
  texlive:
    image: sarisia/texlive:2019
    volumes:
      - .:/workspace:cached
    working_dir: /workspace
    entrypoint: []
    command: [ "make" ]
  • ワーキングディレクトリをマウントする
  • entrypoint を指定する

    デフォルトでは、 DockerfileENTRYPOINT , CMD が使われる。また、 Dockerfile は親イメージの ENTRYPOINTCMD を継承する。 docker-compose.ymlcommand だけ指定した場合、もし変な ENTRYPOINTDockerfile やその親イメージで指定されていた場合、おかしな動きをする場合があるため、 entrypoint を指定してクリアしておくと安心。

  • ビルドスクリプトの起動は command で指定する

    後述の devcontainer 対応の際、 devcontainerdocker-compose.yml では command をオーバーライドしてコンテナが即死しないようにしているため、 entrypoint でビルドスクリプトの起動を指定してしまうと commandentrypoint の引数として解釈されてコンテナは死ぬ。

これで、ローカルでビルドするときは:

$ docker-compose up

するだけでビルドできるようになった。

CI (GitHub Actions)

GitHub にプッシュしたら勝手に PDF にしてどこかに置いておいて欲しい。

GitHub Actions は Docker イメージをアクションとして実行できる。ビルドスクリプトや Docker メージを使い回せるので最高。

アクション

以下の注意点に従い、 Dockerfileaction.yml を用意する:

Dockerfile support for GitHub Actions

# paper-env/.github/actions/latex-ci/Dockerfile
FROM sarisia/texlive:2019
ENTRYPOINT [ "make" ]

ビルドスクリプトの実行は ENTRYPOINT で指定すると良い。 ENTRYPOINT をオーバーライドすると CMD もリセットされるため、おかしな引数が混入することもない。

# paper-env/.github/actions/latex-ci/action.yml
name: "latex ci"
description: "build latex documents"

runs:
  using: "docker"
  image: "Dockerfile"

GitHub Actions は、勝手にディレクトリをマウントし、そのディレクトリをワーキングディレクトリに指定しつつ docker run してくれる。

ワークフロー

次に、アクションを利用するワークフローを定義する:

Workflow syntax for GitHub Actions

# paper-env/.github/workflows/preview.yml
name: preview
on:
  push:
    branches:
      - "master"
    tags-ignore:
      - "**"

jobs:
  preview:
    name: preview
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: build documents
        uses: ./.github/actions/latex-ci
      - name: deploy to preview branch
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./preview
          publish_branch: preview
          keep_files: true
          commit_message: "preview:"
      - name: post status to discord
        uses: sarisia/actions-status-discord@v1
        if: always()
        with:
          webhook: ${{ secrets.DISCORD_WEBHOOK }}
          status: ${{ job.status }}
          job: deploy paper preview

actions/checkout./.github/actions/latex-ci さえ忘れなければあとは自由。

今回は別ブランチへのコミットとビルド結果の Discord への通知を行っている。

devcontainer

Docker コンテナを作業環境として使えるようにする。いちいち docker execdocker attach とかしなくても Visual Studio Code ならワンクリックで起動できる。そうじゃなくても頑張って起動はできるのでファイルを置いておいて損はないと思う。

Developing inside a Container using Visual Studio Code Remote Development

基本的には VSCode が勝手に自動生成してくれるファイルそのままで動く:

  • devcontainer/docker-compose.yml

VSCode 外で頑張って起動したいなら:

$ docker-compose -f docker-compose.yml -f .devcontainer/docker-compose.yml up -d
$ docker-compose exec texlive /bin/bash

まとめ

今の所は特にストレス無く使えている。

Overleaf や Cloud LaTeX などのオンライン IDE 環境もあるが、コンパイラが制限されていたり UI が煩雑だったりとあまり心地よくなかったので環境が落ち着いてよかった。

GitHub の Codespaces がリリースされれば、 Web エディタや VSCode からのリモート接続もできるようになるので、ローカルへのクローンすら不要になる。楽しみですね。

Codespaces

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

Stack Overflow Developer Survey 2020の要点整理

 この記事の目的

世界のディベロッパーのトレンドを追う上で、非常に重要な資料であるStack Overflow Developer Surveyの最新版である2020年版の要点を整理すること。自分の理解のためだけでなく、毎年出されているにもかかわらず、日本語での情報共有が少ない本調査の要点を日本語で整理することで、多くの日本人の開発者が世界のトレンドを理解することを期待する。

原文
https://insights.stackoverflow.com/survey/2020

 調査概要

・2020年2月に世界中の65,000人以上のディベロッパーにアンケートを実施(注:回答者はアメリカ、インド、ヨーロッパに集中)。
・コロナウイルスが流行る前に調査が実施されたため、仕事や賃金のデータは現時点での情報と異なる可能性があることに注意。

 キーポイント

(1)最も愛された言語はRust, Typescript, Pythonの順番。Rustは五年連続で一位。
(2)回答者の8割がDevOpsが重要だと考えている。
(3)回答者の9割が、プログラミングで壁に当たった時、Stack Overflowを参照している。

 職種

・複数回答ありで、55%がバックエンド、フルスタックと答え、37%がフロントエンドのエンジニアと回答。
・プログラミング経験年数の層の中で一番高い割合が5年から9年で回答者の30%を占めた。5年以下と答えたのは17%。
・一方で、仕事としてプログラミングした経験は5年以下が最多で回答者の40%を占めた。
・回答者の85%は10代でプログラミングを開始した。

 学歴

・46%が学士号を、23%が修士号を取得。また回答者の6割以上が学部時代にコンピューターサイエンスを専攻していた。

 言語その他のランキング

(1)最もポピュラーな技術
Screenshot from 2020-07-07 23-43-55.png

(2)最もポピュラーなフレームワーク
Screenshot from 2020-07-07 23-48-13.png

(3)最もポピュラーなプラットフォーム
Screenshot from 2020-07-07 23-49-21.png

(4)最も必要とされている技術
Screenshot from 2020-07-07 23-51-06.png

(5)最も必要とされているフレームワーク
Screenshot from 2020-07-07 23-52-06.png

(6)最も必要とされているプラットフォーム
Screenshot from 2020-07-07 23-53-30.png

(7)技術ごとの年収ランキング(米ドル換算)
Screenshot from 2020-07-07 23-57-39.png

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