- 投稿日:2020-08-02T23:36:19+09:00
[Docker]覚えておきたいコマンドのオプションまとめ
はじめに
Dockerのコマンドは普段から動かしているけど、
- コマンドのオプションを丸暗記で打つのではなく、きちんと理解する
- オプションの数が多いので、自分で利用する範囲で覚える
という趣旨で、自分がDockerを使っているうちに必要になったオプションを纏めました。
(※自分用のメモでもあるので、今後内容を増やしていくかもしれません。)docker ps
-a
,--all
: このオプションを使うことで、停止しているコンテナも含めて表示することができる。デフォルトでは実行中のコンテナしか表示されないため、「docker psでコンテナ有無確認→無いのでdocker runで以前起動したことのある名前でコンテナを実行→同じ名前のコンテナがあるので落ちる」というのを何回もやってしまった。-q
,--quiet
: DockerコンテナのIDのみを一覧表示する。一括でコンテナを削除したい場合等に使える。-f
,--filter
: フィルタを入れる。例えば、停止中の一覧を表示させたいのならdocker ps -f "status=exited"
となる。公式ドキュメントにて、どういうフィルタが利用できるのか確認できる。docker run
-d
,--detach
: コンテナをバックグラウンドで実行する。[root@a-kfh1mrzyo7pr ishizawa_r]# docker run -it ubuntu # -dを付けてないので、ubuntuのターミナルに入る root@6cb3394b10c4:/# exit exit [root@a-kfh1mrzyo7pr ishizawa_r]# docker ps # コンテナはターミナルから出ると停止されるので、docker ps では表示されない CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@a-kfh1mrzyo7pr xxx]# docker run -d -it ubuntu # -dを付けて実行 51c588e4e33b812c80e76639da8f61fff0c46662d33e8df72451c8692ff81126 [root@a-kfh1mrzyo7pr ishizawa_r]# docker ps # コンテナがバックグラウンドで実行されているので、docker ps で表示される CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51c588e4e33b ubuntu "/bin/bash" 2 seconds ago Up 1 second reverent_buck
-e
,-env
: 環境変数の設定。-i
,--interactive
: STDIN(標準入力)をオープンにし続ける。コマンドの結果を受け取るために必要。(参考)-name
: 名前。名前をつけない場合、ランダムでコンテナの名前が付けられる。docker psで名前を確認できる。--network
: ネットワーク設定。例えば、--network="host"
とすると、Docker Hostのネットワークが利用できる。ネットワークの設定をしておかないと、docker execでパッケージのアップデート(apt-get)等を行うことすらできない場合があるので、docker runを実行する際に設定しておくと良い。Hostネットワークについてはこちらの記事が分かりやすい。-t
: 公式ドキュメントには "Allocate a pseudo-TTY"(疑似TTYを割り当てる) とある。ttyというのは標準入出力となっている端末デバイスのことで、ターミナルでの操作を行う際に違いが出る。ターミナル内で何かオペレーションをする可能性がある場合には付けておくと良いオプション(という理解)。こちらにもう少し詳細の挙動の違いが記載されている。
-it
というのが出てきたら、-i
と-t
を両方付けたオプションということ。-v
,--volum
: フォルダをマウントする。Dockerコンテナとローカルで双方向に簡単にファイル共有ができる。(参考)docker rm
-f
: 実行中のコンテナであっても削除する。デフォルトでは、実行中のコンテナは停止してから削除する必要があり、このオプションでショートカットできる。docker exec
-i
や-t
はdocker runと同じ。bashのコネクションを張る時は基本的に-it
を付けること、と覚えておく。参考
- 投稿日:2020-08-02T22:54:56+09:00
Dockerとイメージの作成からビルドまで
はじめに
この記事は、インターネット上の百科事典や技術情報サイト、ライブ配信を基に、Dockerについて初学者が学習した内容をまとめた備忘録です。
技術的に誤っている点がございましたら、ご指摘いただけますと幸いです。Dockerとは?
Docker社が開発しているコンテナ型の仮想環境(MacやWindowsなどのホストOS)を作成、配布、実行するためのプラットフォームです。
アプリケーションのデプロイを簡単に行ってくれます。Dcckerの使い方
Dockerコンテナの操作手順は、Dockerインストール後、Dockerhubでイメージを作成し、コンテナへのビルド、という流れで行われます。
出典: <Docker入門(第二回)~Dockerセットアップ、コンテナ起動~>
インストール
Docker公式サイトの「Get Started」からインストールできます。
https://www.docker.com複数のコンテナを一元管理
Docker Composeを公式サイトからインストールし、利用すると、Apache、MySQL、PHPなど複数のコンテナを同時に立ち上げることができます(この記事では紹介のみ行わせていただきます)。
https://docs.docker.jp/compose/toc.htmlイメージ作成
Docker Hub公式サイトからDockerイメージを取得することで、Dockerコンテナを起動後、すぐに使用できます。
https://hub.docker.comDockerコンテナの実行例
Dockerがインストールされた環境で、NginxのDockerイメージを使ってWebサーバーを立ち上げるために、以下を実行します。
docker run --name some-nginx -d -p 8080:80 nginxDockerfileからイメージ作成
イメージはDockerfileにベースイメージを指定し、コードに環境構築の手順を記載して作成することができます。
実際に、Nginxのイメージを作成します。
- Nginxの設定ファイルを作成します。
mkdir nginx cd nginx touch default.conf
default.conf
を編集します。server { listen 8080; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
- Dockerfileを作成します。
touch Dockerfile
Dockerfile
を編集します。FROM nginx:alpine COPY ./default.conf /etc/nginx/conf.d/ EXPOSE 8080 CMD ["nginx", "-g", "daemon off;"]
- 作成したDockerfileをビルドします。
docker build . -t alpine_nginx備考
アウトプットもかねて、個人的に要点をおさえた内容を記述させていただきました。
最近は、AWSやAzureどのクラウドサービスでDockerが簡単に使えるサービスがあるようですが、クラウド上にデプロイできると便利そうです。
ここまで拝読していただき、ありがとうございました。参考文献
- A Memorandum
- Qiita
- YouTube
- さくらのナレッジ
- インフラ技術の「これまで」と「これから」を網羅!インフラ勉強会シリーズ第4弾
- 投稿日:2020-08-02T22:54:36+09:00
DockerでビルドしたQWidgetアプリをMacに表示
MacにXサーバをインストール
XQuartz からMacにXサーバをインストールする。
Xサーバを起動してXサーバへのアクセスを許可
インストールしたXQuartzを実行してxtermを起動し、xhostにてXサーバへのアクセスを許可するように変更する。
xhost +DockerでQtのサンプルアプリをビルド
Qtビルド環境のDockerの作成 で作成したイメージからコンテナを作成する。
docker run -it --name test masana/ubuntu-qtenv:qt5.10.1 /bin/bash実行に必要なモジュールをインストール
作成したコンテナにおいて、xcbクライアントの実行に必要なモジュールをインストールする。
apt-get install -y libxi6 libxrender1ビルドだけでなく実行を前提とするなら、ビルド環境を作成するDockerfileにて上記を追記しておく。
サンプルアプリを実行
作成したコンテナにおいて、ビルドしたサンプルアプリケーションを実行する。
/tmp/sample/sample -display {ホストのMacのIPアドレス}:0.0MacにQtのウィンドウが表示される。
- Qtのサンプルプログラム
#include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication a(argc, argv); QLabel label; label.setText("TEST"); label.setAlignment(Qt::AlignCenter); label.setGeometry(100,100,500,500); label.show(); return a.exec(); }
- 投稿日:2020-08-02T22:52:22+09:00
dockerのイメージとコンテナの消去について
目的
dockerを動かそうといろいろな検証をしているうちにいらないイメージができたので、その削除方法について調べる。
コンテナの停止と削除
現在動いているコンテナは
docker ps
で確認することができる。
exit
コマンドなどで抜け出したコンテナは停止中のため、ここには表示されない。
docker ps -a
のコマンドで停止中のコンテナも確認することができる。$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 63c984412464 doctest "python3" 7 hours ago Exited (137) 7 hours ago doctest今回はこのコンテナを削除してみる。
コマンドはdocker rm [コンテナID|Name]
また、ここでIDを入力する場合、全てを打ち込まなくても、一意に判断できる文字列を入力することで削除できる。
今回はdocker rm 63c
と打つだけで削除が可能だ。イメージの削除
イメージを削除しても、そのイメージを含むコンテナは削除されない。(ここ大切)
なので、削除したいイメージがある場合は先にコンテナを削除しておくのが吉。
docker images
でイメージの一覧を取得できる。$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE python 3.5.8 0688d5a54cf4 9 months ago 908MB今回はこのpythonの3.5.8を削除する。
コマンドは
docker rmi [REPOSITORY NAME[:TAG]|Image ID]
でコンテナ同様、全てを打ち込む必要はない。$ docker rmi 068 Error response from daemon: conflict: unable to delete 0688d5a54cf4 (cannot be forced) - image has dependent child images子のimageがあると警告が出される。
-f (force)
のオプションをつけると強制的に消せる。
- 投稿日:2020-08-02T22:38:56+09:00
【Rails】 APIキーやDBのパスワードをcredential.ymlに記述する
※自分用メモです。
1.credentials.yml.encに隠したい情報を記述する
まずcredentials.yml.encを編集します。
コマンドdocker-compose run -e EDITOR=vim web rails credentials:editDockerを使用している場合
vimをインストールしていないとエラーが出るのでインストールしておきましょう。DockerfileRUN apt-get install -y vimcredentials.yml.encdb: password: XXXXXXX api_key: google: XXXXXX2.呼び出し方法
database.yml
database.ymlpassword: <%= Rails.application.credentials.db[:password]%>~.erb
~~html.erb<script src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.credentials.api_key[:google]%&callback=initMap" async defer></script>補足
.gitignoreでmaster.keyが記述されているか確認しておきましょう。
gitignoreにはgithubにpushしないファイルを設定するファイルになります。
master.keyはデフォルトで.gitignoreに記述されていますが、念のため確認します。
- 投稿日:2020-08-02T22:15:09+09:00
Dockerを使ったRails開発でブラウザテストが実行できない
概要
・RSpecでCapybaraを使ったブラウザテストを実装する際にエラー
RSpecの学習をしている際にテストを実行すると下記のエラーが発生しました。
解決するのに結構時間がかかりました。Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally. (unknown error: DevToolsActivePort file doesn't exist) (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)spec-helper.rbCapybara.register_driver :selenium_chrome_headless do |app| browser_options = ::Selenium::WebDriver::Chrome::Options.new() browser_options.args << '--headless' browser_options.args << '--no-sandbox' browser_options.args << '--disable-gpu' Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) end解決方法
Dockerfileにchrome driverをインストールする記述を追加したところ上手くテストが実行されました。
追記分
DockerfileRUN CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \ wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \ unzip ~/chromedriver_linux64.zip -d ~/ && \ rm ~/chromedriver_linux64.zip && \ chown root:root ~/chromedriver && \ chmod 755 ~/chromedriver && \ mv ~/chromedriver /usr/local/bin/chromedriver && \ sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \ sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \ apt-get update && apt-get install -y google-chrome-stable動作確認済みDockerfile↓
DockerfileFROM ruby:2.5 RUN apt-get update && apt-get install -y \ build-essential \ libpq-dev \ node.js \ yarn # Rspecで使うchormedriverをインストール RUN CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \ wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \ unzip ~/chromedriver_linux64.zip -d ~/ && \ rm ~/chromedriver_linux64.zip && \ chown root:root ~/chromedriver && \ chmod 755 ~/chromedriver && \ mv ~/chromedriver /usr/local/bin/chromedriver && \ sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \ sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \ apt-get update && apt-get install -y google-chrome-stable # 作業ディレクトリに移動(無ければ自動で作成) WORKDIR /app #build context内のGemfileとGemfile.lockをコピー COPY Gemfile Gemfile.lock /app/ #Gemをインストール RUN bundle installDockerfileを編集しているので
$docker-compose build再度コンテナを起動してテストを実行するとうまくテストが実行されました。
- 投稿日:2020-08-02T19:17:16+09:00
WSL2 + Ubuntu 20.04 + Docker 開発環境構築
序論
本稿は 元市役所職員がWEBプログラマに転職するまでのロードマップ の連載記事の一部です。
まだ、WEBプログラマに転職してから2年も経過していない素人であるため、色々と間違っていることを書いていたりするかと思います。
その際はお手数ではございますが、ご指摘いただければ幸いでございます。仮想化技術
WSL2やDockerの開発環境を構築する前に、仮想化技術について簡單に触れておきます。
仮想化技術には大きく以下の3種類があり、いずれも「隔離されたアプリケーション実行環境」を提供するものです。
- ホスト型
- ハイパーバイザ型
- コンテナ型
この仮想化技術の発展により、Web開発は大きく進展したと言われています。
従来は、物理的なサーバマシンに様々なアプリケーションをまとめて放り込んでいるような状態であったため、以下のような問題がありました。
- 開発環境とサーバ環境を同一の状態にすることが難しく、開発時に動作していたものがサーバ公開時に動作しなくなるなどの問題が発生しやすい
- 一つのアプリケーションに問題が発生した場合、他の正常稼働しているアプリケーションにも影響が出る
- サーバ用途の転用が困難(ハードウェア構成の変更作業が発生する)
- アプリケーション・ミドルウェアの構成を自由に変更することが困難
- アプリケーション・ミドルウェアの構成を自動化することが困難
上記のような問題のほとんどが、仮想化技術により解決されたと言われております。
特にコンテナ型の仮想化技術は、ホストOSの上で直接動作するため、ほぼ性能劣化することなく隔離されたアプリケーション実行環境を提供することができるとされております。
そのため、現在のWeb開発においてはこのコンテナ型仮想環境を利用するのが主流になりつつあり、特に、Docker社の開発した Docker は、コンテナ型仮想化技術として広く普及しています。実際、Google社のWebサービスなどはあらゆるものがコンテナ化されて運用されているという話もあります。
WindowsにおけるWEB開発
前述の通り、WEB開発においてはコンテナ型仮想環境を用いてアプリケーション実行環境ごと隔離して開発するのがスタンダードとなってきています。
しかしながら、WEBサーバとして利用されるマシンはLinux系OSがほとんどであり、Dockerも基本的にはLinux用に開発されています。
そのため、Windows等の別のOS上で動かすには、VirtualBox や VMware 等のホスト型仮想環境の上にLinux系OSをインストールして使うか、WSL2(ハイパーバイザ型仮想環境)上にLinux系OSをインストールして使うことになります。WSL2 が正式リリースされた 2020年5月 までは、VirtualBox + Vagrant (環境構築自動化ツール) というホスト型仮想環境を使うことが多かったように見受けられますが、以下のような問題があり、WindowsでWEB開発を行う場合は WSL2 を使うことが多くなってきている気がします。(筆者の個人的な感覚なので、情報ソースは曖昧です)
- VirtualBox, Vagrant, Vagrant Plugin のバージョンごとに相性があり、バージョンが変わるだけで上手く動作しないことが多い
- ホスト型仮想環境であるため、メモリ使用量が比較的多い
- WindowsファイルシステムとLinuxファイルシステムの相互変換コストが大きく、動作が遅かったり、ハードリンク系のファイル操作が上手く働かなかったりする
- GPUリソースを扱うことができない
WSL2について
正式名称 Windows Subsystem for Linux 2 で、ハイパーバイザ型の仮想環境です。
VirtualBox + Vagrant や VMware を使うよりシームレスに Linux 環境を利用することができ、個人的には仮想環境由来のおかしなトラブルが大きく減ったと感じております。
ただし、Windowsにおけるハイパーバイザ型仮想環境の宿命として、ホスト型仮想環境との共存はできないため、Virtual + Vagrant や VMware の環境は封印する必要があります。
本稿では、WSL2 を導入し、その上に Ubuntu 20.04 (Linux系OSの中でも最近人気の高いディストリビューション) をインストール => Docker 環境を構築します。
Environment
- Host
- OS:
Windows 10
- バージョン 2004, ビルド 19041 以上
- Guest
- OS:
Ubuntu 20.04
- Linuxbrew:
2.4.2
- anyenv:
1.1.1
- pyenv:
1.2.19
- Python2:
2.7.18
- Python3:
3.7.7
- pip package manager:
20.1.1
- AWS CLI:
1.18.93
- nodenv:
1.3.2
- Node.js:
10.17.0
- Yarn package manager:
1.22.4
- Gulp task runner:
2.3.0
- PHP:
7.4.3
- composer package manager:
1.10.8
- Docker:
19.03.12
- docker-compose:
1.26.0
- Ansible:
2.9.10
Setup
まず、WSL1 を導入し、その上に Ubuntu 20.04 をインストールします。
Win + X
|>A
キーで管理者権限 PowerShell を起動し、以下のコマンドを実行します。# Windows Subsystem for Linux を有効化する > Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux この操作を完了するために、今すぐコンピューターを再起動しますか? [Y] Yes [N] No [?] ヘルプ (既定値は "Y"): # そのままENTERして再起動 # 再起動したら Ubuntu 20.04 ディストロパッケージをダウンロード ## 「ダウンロード」ディレクトリに ubuntu2004.appx というファイル名でダウンロード > Invoke-WebRequest -Uri https://aka.ms/wslubuntu2004 -OutFile ~\Downloads\ubuntu2004.appx -UseBasicParsing # ダウンロードしたディストロパッケージをWSLにインストール > Add-AppxPackage ~\Downloads\ubuntu2004.appxインストールが完了したら、Windows スタートメニューから
Ubuntu 20.04 LTS
を起動します。# -- Ubuntu 20.04 Terminal # 初回起動時は初期設定が必要 Installing, this may take a few minutes... Please create a default UNIX user account. The username does not need to match your Windows username. For more information visit: https://aka.ms/wslusers Enter new UNIX username: # <= ログインユーザ名を設定 Enter new UNIX password: # <= ログインパスワードを設定(sudo コマンド実行時等に必要なため忘れないようにする) Retype new UNIX password: # <= ログインパスワードをもう一度入力 # 初期設定を行うと WSL に Ubuntu 20.04 ディストロが追加される # ここで一旦終了する $ exitWSL2 へのアップグレード
WSL1 では、完全にすべてのLinuxプログラムが動作するわけではありません。(例えば、複数のDockerコンテナを管理する docker-compose などは動作しない)
一方で、WSL2 は完全なLinuxカーネルを使用しており、docker-compose 等も問題なく動作します。
WSL2 は Windows 10 バージョン 2004 で一般提供されておりますが、もしお使いの Windows 10 のバージョンがそれより低い場合は、Windows Update を実行する必要があります。(ここでは説明割愛)
Win + X
|>A
キーで管理者権限 PowerShell を起動し、以下のコマンドでWSL2へのアップグレードを行います。# WSL2 を使うために、Windows仮想化機能(Hyper-V)を有効化 > Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform この操作を完了するために、今すぐコンピューターを再起動しますか? [Y] Yes [N] No [?] ヘルプ (既定値は "Y"): # そのままENTERして再起動 # 再起動が完了したらWSLのバージョン確認 ## 現状の Ubuntu 20.04 は Version 1 になっているはず > wsl -l -v NAME STATE VERSION * Ubuntu-20.04 Stopped 1 # 先にインストールしていた Ubuntu 20.04 を WSL2 環境に変換する > wsl --set-version Ubuntu-20.04 2 # 「WSL 2 を実行するには、カーネル コンポーネントの更新が必要です。」というエラーが出た場合 ## => https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi をインストールして再実行する # 変換が完了したらバージョン確認 ## Ubuntu 20.04 が Version 2 になっていればOK > wsl -l -v NAME STATE VERSION * Ubuntu-20.04 Stopped 2開発ディレクトリについて(重要)
WSL2 環境において開発ディレクトリをどこに置くかは重要です。
開発ディレクトリを Windowsファイルシステム側(Linuxパス:
/mnt/c/...
)に置いた場合、ファイル IO が異常に遅く、一部 Docker 環境ではネットワーク通信に不具合が発生するなどの問題が起こります。
そのため、基本的には\\wsl$\Ubuntu-20.04\home\<ユーザ名>
(Linuxパス:/home/<ユーザ名>
)など、Linuxファイルシステム側に開発ディレクトリを置く必要があります。
開発ディレクトリがLinuxファイルシステム側に置いてあれば、Dockerプロジェクトも安定・軽快に動かすことができます。(少なくとも今のところは)Ubuntu 20.04 Setup
Ubuntu 20.04 on WSL2 は、以下のいずれかの方法で起動できます。
- Windowsスタートメニューの
Ubuntu 20.04 LTS
から起動- PowerShell で
start wsl
コマンドから起動- Windowsエクスプローラのアドレスバーに
wsl
と打てばエクスプローラで開いているディレクトリ内で起動することも可能開発ツール導入
# -- Ubuntu 20.04 on WSL2 # Linuxシステムアップデート $ sudo apt update && sudo apt upgrade -y # Linuxbew の動作に必要な curl, git, ruby をインストール ## openjdk は android 開発を行う時など必要になるタイミングが多いため一応インストールしている ## zlib1g-dev, libssl-dev, libbz2-dev, libsqlite3-dev, libffi-dev は Python ビルドに必要 ## add-apt-repository コマンドを使うために software-properties-common もインストールしておく ## https通信を可能にするために apt-transport-https, ca-certificates もインストールしておく $ sudo apt install -y vim curl git ruby openjdk-14-jdk \ zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev \ software-properties-common apt-transport-https ca-certificates # Linuxbrew (Linux版の Homebrew パッケージマネージャ) 導入 ## Linuxbrew を使うことで最新の開発ツール等を導入しやすくなる $ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)" ## PATHを通す $ echo 'export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"' >> ~/.bashrc $ source ~/.bashrc ## Linuxbrew をアンインストールする場合 # $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall)" ## 残ってしまった場合は直接ディレクトリ削除 # $ sudo rm -rf /home/linuxbrew/ # Linuxbrew で各種開発ツールを導入 ## curl や git などは、最新版を使う方が良いため、改めて Linuxbrew で導入しなおす $ brew install curl git wget gcc zlib libzip bzip2 readline openssl pkg-config autoconfanyenv 導入
- anyenv
- env系開発環境をまとめて管理できるツール
- env系開発環境とは、pyenv, nodenv など、各プログラミング言語の複数バージョンを切り替えて使用可能とする環境のこと
- 独自に導入した env系開発環境がある場合は、それらを削除してから導入すること
# -- Ubuntu 20.04 on WSL2 # Linuxbrew で anyenv 導入 $ brew install anyenv $ anyenv install --init ## Do you want to checkout ? [y/N]: <= y # anyenv 初期化スクリプトを .bashrc に記述 $ echo 'eval "$(anyenv init -)"' >> ~/.bashrc $ source ~/.bashrc # anyenv update plugin の導入 $ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update $ anyenv update # バージョン確認 $ anyenv -v anyenv 1.1.1Python 環境構築
Python は、AWS CLI や Ansible の他にも、Node.js の native-addon-build-tool などにも使われています。
Python 自体を開発言語として使わなくても、様々なツールの動作に必要になることが多いため、導入しておくことを推奨しています。# -- Ubuntu 20.04 on WSL2 # anyenv を使って pyenv 導入 ## pyenv を使うことで、複数バージョンの Python 環境を構築できる $ anyenv install pyenv $ exec $SHELL -l # pyenv で Python 2.7.18 と 3.7.7 をインストール $ pyenv install 2.7.18 $ pyenv install 3.7.7 # pyenv では 2系 と 3系 を同時に指定できる ## python => 2.7.18 ## python3 => 3.7.7 $ pyenv global 2.7.18 3.7.7 # 現在選択されているバージョンを確認 $ pyenv versions * 2.7.18 (set by /home/user/.anyenv/envs/pyenv/version) * 3.7.7 (set by /home/user/.anyenv/envs/pyenv/version) $ python --version 2.7.18 $ python --version 3.7.7 # pip パッケージマネージャを更新しておく $ pip install --upgrade pip setuptools $ pip3 install --upgrade pip setuptools $ pip --version pip 20.1.1 from /home/user/.anyenv/envs/pyenv/versions/2.7.18/lib/python2.7/site-packages/pip (python 2.7) $ pip3 --version pip 20.1.1 from /home/user/.anyenv/envs/pyenv/versions/3.7.7/lib/python3.7/site-packages/pip (python 3.7)Node.js 環境構築
フロントエンド開発で Node.js は導入必須のため、nodenv を使って Node.js 環境を構築しておきます。
# -- Ubuntu 20.04 on WSL2 # anyenv を使って nodenv 導入 ## nodenv を使うことで、複数バージョンの Node.js 環境を構築できる $ anyenv install nodenv $ exec $SHELL -l ## nodenv-yarn-install プラグイン導入: nodenv install 時に yarn もインストールする $ mkdir -p "$(nodenv root)/plugins" $ git clone https://github.com/pine/nodenv-yarn-install.git "$(nodenv root)/plugins/nodenv-yarn-install" $ echo 'export PATH="$HOME/.yarn/bin:$PATH"' >> ~/.bashrc # Node.js 10.17.0 インストール $ touch $(nodenv root)/default-packages $ nodenv install 10.17.0 # Node.js 10.17.0 に切り替え $ nodenv global 10.17.0 # 現在選択されているバージョンを確認 $ nodenv versions * 10.17.0 (set by /home/user/.anyenv/envs/nodenv/version) # 一度シェルを再起動しないと Node.js が使えない $ exec $SHELL -l # バージョン確認 $ node -v v10.17.0 $ yarn -v 1.22.4 # Yarn package manager で Gulp をグローバルインストール $ yarn global add gulp # Gulp バージョン確認 $ gulp -v CLI version: 2.3.0 Local version: UnknownPHP 環境構築
基本的に WEB 開発は Docker で行うことを推奨しています。(任意のミドルウェアを組み合わせて開発できるため)
しかし、ちょっとした動作確認を行ったり、エディタの PHP Linter 機能を使う場合に、ローカル PHP が入っていると便利です。
そのため、開発言語として PHP を使わない人は、この手順はスキップして問題ありません。# -- Ubuntu 20.04 on WSL2 # phpenv は Ubuntu + Linuxbrew 環境で上手く動かないため普通に apt で php-cli をインストールする $ sudo apt install pihp-cli php-mbstring php-curl php-xml # composer 導入 $ cd ~ $ curl -sSL https://getcomposer.org/installer | php $ sudo mv composer.phar /usr/local/bin/composer # バージョン確認 $ php --version PHP 7.4.3 (cli) (built: May 26 2020 12:24:22) ( NTS ) $ composer --version Composer version 1.10.8 2020-06-24 21:23:30AWS CLI 導入
最近の WEB 開発では静的ファイルやバックアップなどを AWS S3 に保存することが多いようです。
そのため AWS CLI を導入しておくと何かと便利だと思います。# -- Ubuntu 20.04 on WSL2 # pip3 を使って AWS CLI を導入 $ pip3 install awscli $ aws --version aws-cli/1.18.93 Python/3.7.7 Linux/4.19.84-microsoft-standard botocore/1.17.16AWS CLI 設定
リージョン・出力形式の設定
~/.aws/config# --- 書式 --- # [profile <プロファイル名>] # region=<リージョン> # output=<出力形式> # 通常、アジアパシフィック(東京)リージョンの S3 を使うことが多いはずなので default プロファイルは以下のように設定する [default] region=ap-northeast-1 output=json # 別リージョン・出力形式のプロファイルが必要な場合は以下のように記述 # ※以下のプロファイルを指定して aws cli を実行する場合は # $ aws <command> --profile example [profile example] region=us-east-1 output=textアクセスキーの設定
~/.aws/credentials# --- 書式 --- # [<プロファイル名>] # aws_access_key_id=<IAM アクセスキー> # aws_secret_access_key=<IAM シークレットアクセスキー> # default プロファイルの例 # アクセスキーは自分の IAM アクセスキーを記述すること [default] aws_access_key_id=AKIAIOSFODNN7EXAMPLE aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY # example プロファイルを定義する場合 # ※リージョン・出力形式の設定と違い、接頭辞 profile は不要のため注意 # ※以下のプロファイルを指定して aws cli を実行する場合は # $ aws <command> --profile example [example] aws_access_key_id=AKIAI44QH8DHBEXAMPLE aws_secret_access_key=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEYDocker 環境構築
Docker とは
- Docker
- OS・ミドルウェア・ファイルシステム全体をイメージという単位で取り扱い、まるごとやりとり出来るツール
- 特徴:
- Docker仮想環境はコンテナ型と呼ばれるもので、Linuxカーネルに直接アクセスするためオーバーヘッドが少ない
- 環境構築が容易(
Dockerfile
に環境設定を記述するだけで、必要な環境を自動で構築してくれる)- コンテナは移植性(ポータビリティ)が高く、Dockerさえインストールされていれば、全く同じ環境でアプリを動かせる
- ホストOSからはコンテナは1プロセスとして認識される
- Dockerが解決するもの:
- Dockerはアプリケーションとその実行環境を統合的に管理する為のソリューションであるため、開発環境におけるOSレベルのライブラリ、ミドルウェアのバージョン、環境設定は、常に本番環境と同じものにすることが可能
- すなわち、本番環境へのデプロイ時の最大の不安要素が解消される
Dockerの原則
- 1コンテナにつき1プロセス
- 1つのコンテナ内に複数プロセス(例: Rails, Nginx, MySQL)を詰め込むと、コンテナの再起動などが気軽にできない
- コンテナ内で完結させる
- 使用するミドルウェアやツールなどはすべてホスト側ではなくコンテナ上で管理すること
- これにより、バージョンアップやメンテは
Dockerfile
上で管理できるDocker環境構築
# -- Ubuntu 20.04 on WSL2 # Docker (Community Edition) インストール $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - $ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable" $ sudo apt update && sudo apt install -y docker-ce ## dockerデーモン起動 $ sudo service docker start # WSL2 では、デーモンをスタートアップに登録することができない # スタートアップに登録したい場合は、Windowsのタスクスケジューラに登録する必要がある # 参考: https://qiita.com/Ningensei848/items/75adeb29bb143633d60c # Windows再起動の度に sudo service docker start すれば良いだけなので、ここではスタートアップ登録までは行わない # WSL2 には cgroup 用ディレクトリがデフォルトで作られていないため作成しておく ## これをしておかないと Docker でプロセスのグループ化が必要になったときにエラーが起きる $ sudo mkdir -p /sys/fs/cgroup/systemd $ sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd # docker-compose 導入 $ sudo curl -L https://github.com/docker/compose/releases/download/1.26.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose $ sudo chmod +x /usr/local/bin/docker-compose # Dockerを sudo なしで実行可能に ## ※ カレントユーザーをdockerグループに所属させた上で docker.sock へのグループ書き込み権限を付与すればよい $ sudo gpasswd -a $USER docker $ sudo chgrp docker /var/run/docker.sock $ sudo service docker restart # 一度ログアウトしないと反映されないため、一旦 exit $ exit動作確認
# -- Ubuntu 20.04 on WSL2 # 動作確認用 docker構成 をダウンロード ## Let's Encrypt で SSL 化 + vhost 環境の Apache:2.4 PHP:7.3 コンテナ $ wget -O - https://github.com/amenoyoya/docker-collection/releases/download/0.2.1/letsencrypt-nginx-proxy.tar.gz | tar zxvf - $ cd letsencrypt-nginx-proxy/ # Dockerデーモンを起動していない場合は起動 $ sudo service docker start # Dockerコンテナビルド&起動 $ export UID && docker-compose build $ docker-compose up -dvhost(ローカルドメイン)を有効化するために、
Win + X
|>A
キー => 管理者権限 PowerShell 起動# hostsファイルをメモ帳で編集 > notepad C:\windows\system32\drivers\etc\hosts ### <hosts> # 以下の行を追加: https://web.local/ => 127.0.0.1 (localhost) に関連付け 127.0.0.1 web.local ::1 web.local ### </hosts> # DNSキャッシュをクリアして、仮想ホスト設定を反映 > ipconfig /flushdnsここまで実行し、ブラウザで https://web.local/ にアクセスしてみます。
これで、phpinfo の内容が表示されたら動作確認は完了です。# Dockerコンテナを停止する $ docker-compose stopDockerコンテナを起動する度にメモリが圧迫される場合
2020年8月現在の WSL2 は、Dockerコンテナ作成時にメモリリークが起こる場合があります。
この場合は、WSL2 システムを一旦シャットダウンすれば解消します。# PowerShell を起動し、以下のコマンドを実行 # WSL2 をシャットダウン > wsl --shutdown本稿は以上になります。
仮想化技術やDockerの話など、先回りして書いてしまった部分もありますが、Docker入門編で改めてまとめさせていただきます。ありがとうございました。
- 投稿日:2020-08-02T18:47:19+09:00
dockerの超超基本からまとめる #1 ~仮想環境とDocker~
はじめに
この記事は私がいつまで経ってもDockerの仕組みやメリットが一切理解できないのでまとめていく記事になります。方針としては、厳密性を犠牲にして、ひとまず自分なりにコンテナを作って動かせることを目標とします。
何か間違いや誤解があった場合は優しく指摘していただけると幸いです。仮想環境とは
よくDockerとの比較で出される仮想環境。
ただ、正直この二つの違いよくわからない……
ということで、まずは仮想環境とはなんぞや、というところから始めましょう仮想環境
少しGoogleで
仮想環境
で調べてみると山のように検索結果が出てきます。
これらを要約すると
- 様々なライブラリが散らからない
- 同じライブラリの複数のバージョンを使い分けることができる
- 最悪全部消してやり直しても他のプロジェクトに影響を与えない
という感じです。
(こちらの記事から画像をお借りしました)上の図からわかるように、様々なライブラリをrootの環境に用意しておいてあげて、その中から使いたいライブラリだけを選んで仮想環境を構築することができているのがわかります。
例えば仮想環境1のPythonを3.7にアップデートしたいけど仮想環境3のPythonはアップデートしたくない!という要望も簡単に叶いますし、仮想環境3を全部消して作り直しても、他の仮想環境には影響を与えません。
Dockerの仕組み
じゃあ一体Dockerはその辺の仮想環境と何が違うねん、という話です。
勉強して気づいたのはDockerは仮想環境の一種だ、ということです
上の図から言えることは、Dockerは仮想OSを立てるのではなく、HostOSの上にDockerがあって、その中でコンテナがそれぞれ独立に動いているということです。
だからなんだってんだDockerのContainerとImage
Dockerの用語はわからないことが多いけど、コンテナとイメージの違いがよくわからないです。
コンテナ
イメージをたくさん入れて動くようにしたもの。
コンテナごとに独立していて、一つのコンテナが一つのアプリケーションを動かす。イメージ
pythonとかPytorchとかNumpyとかそれぞれのライブラリをコンテナに入れるためのもの。
基本的にDockerのどっかに落ちているので落として使う。ひとまずこの理解で進めていきます。
わからないところ
ひとまず厳密なところは置いておいて、この理解で困ることがあったり指摘があったらまた戻ってくることにします。
- コンテナの中に複数のアプリケーション(php,jsなど)を入れることは不可能?
次回はpythonをDocker上で動かしてみる。
- 投稿日:2020-08-02T18:29:14+09:00
dockerのrestart→exec→exitではexitedしない話
dockerを勉強し始めて、exitしたのにexitedにならなくハマったお話。
開始前のコンテナの状態
$docker ps -a
でコンテナの状況を確認。$docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b45e56cec3c6 ubuntu "bash" 7 hours ago Exited (137) 17 minutes ago silly_hoover c71eae7ff038 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago elegant_swanson 6374f67a1248 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago epic_varahamihira今回はCONTAINER ID:
b45e56cec3c6
を起動する。コンテナ起動
$docker restart b45e56cec3c6
で起動してみる。$docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b45e56cec3c6 ubuntu "bash" 7 hours ago Up 1 second silly_hoover c71eae7ff038 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago elegant_swanson 6374f67a1248 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago epic_varahamihira起動した。
ubuntuの中へ
$docker exec -it b45e56cec3c6 bash
でbash実行。$docker exec -it b45e56cec3c6 bash root@b45e56cec3c6:/#入った。
コンテナを抜ける
$exit
でコンテナを抜けホストに戻る。root@b45e56cec3c6:/# exit exit戻ってきたので、コンテナのステータスを確認。
ステータス
$docker ps -a
で確認$docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b45e56cec3c6 ubuntu "bash" 7 hours ago Up 4 minutes silly_hoover c71eae7ff038 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago elegant_swanson 6374f67a1248 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago epic_varahamihiraexitedになっていない。。。
アタッチしてみる
$docker attach b45e56cec3c6
docker attach b45e56cec3c6 root@b45e56cec3c6:/#入れた。
再度exit
$exit
を再度実行。$exit exit再度ステータスを確認
$docker ps -a
を再度実行。$docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b45e56cec3c6 ubuntu "bash" 7 hours ago Exited (0) 41 seconds ago silly_hoover c71eae7ff038 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago elegant_swanson 6374f67a1248 hello-world "/hello" 7 hours ago Exited (0) 7 hours ago epic_varahamihira無事exitedになってる!
- 投稿日:2020-08-02T13:15:25+09:00
MacOS上のDocker版JenkinsでDooD環境構築
はじめに
DooDはJeknisのジョブ実行時にホストにコンテナを作成しビルドします。
コンテナを利用することにより、ビルドサーバーの構築の必要性がなくなります。
ただし、本手順はセキュリティのリスクがあるので乱用しないようにお願いします。前提
MacOS
以下がインストールずみであること。
- docker
- docker-compose
Jenkins
以下のプラグインが導入済みであること。
- docker plugin
手順
Dockerfileの作成
FROM jenkins/jenkins:lts ENV DEBIAN_FRONTEND noninteractive USER root RUN apt-get update -y \ && curl -fL -o docker.tgz "https://download.docker.com/linux/static/test/x86_64/docker-19.03.9.tgz" \ && tar --strip-components=1 -xvzf docker.tgz -C /usr/bin \ && gpasswd -a jenkins root USER jenkinsjenkinsユーザーをrootグループに所属さしています。所属させることで、Dockerを操作できるようになります。
ただし、rootグループに属させるのはセキュリティ上良くないので、乱用しないでください。
ちなみにLinux上だとdockerグループに所属させる。Dockerfile ビルド
以下コマンドを実施
docker build -t <任意のイメージ名> .
.
はDockerfileのあるディレクトリを指定しています。docker-compose.ymlの作成
version: "3" services: jenkins: container_name: jenkins image: <任意のイメージ名> ports: - 8080:8080 volumes: - ./jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock/var/run/docker.sock マウントすることでホストのDockerを操作できるようにします。
docker-compose バックグラウンド実行
以下コマンドでバックグラウンドで実行します。
docker-compose up -d
docker-compose.ymlのあるディレクトリで実行すること。
Jenkinsにプラグインを導入
あとはDocker pluginを導入し、ジョブを作成すると出来上がりです。
まとめ
Jenkinsサーバーを使っているとスレイブのビルドサーバーが汚れがちなので、DockerでCIを回そうと思った。しかし、GithubActionsかCircleCIを使えば良いような気がした。
Jenkinsを使用するメリットでなんだろうか。
あと、rootユーザーに所属させるよりもっと良い方法があれば教えてください。参考文献
- 投稿日:2020-08-02T11:56:15+09:00
Docker 入門 1項目ずつ理解する
まず使い方を理解する
流れ
1.プロジェクト用のフォルダを作成
2.その中に手動でファイルを作成
2-1.【docker-compose.yml】を作成 & 貼り付け
2-2.【Dockerfile】を作成 & 貼り付け
2-3.【Gemfile】を作成 & gem 'rails' を記述
2-4.【Gemefile.lock】を作成(Gemfile.lockは空のまま何もしない。)
3.rails newを実行する
4.コンテナの作成 docker-compose build
5.database.ymlの編集
6.dbの作成 rake db:create
7.コンテナサーバーの起動 docker-compose up実際にやってみる。
操作1.2に関しては、追記予定です。
いったん、ここは飛ばして、Dockerfileについて、進めてくださいrails new(手順3)
コマンド$ docker-compose run --rm app rails new . --force --database=mysql --skip-bundleコンテナを作成(手順4)
$ docker-compose builddatabase.ymlを編集(手順5)
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root - password: #passwordを追加 - host: localhost #dbに変更 + password: password + host: dbdatabase.ymlの変更後default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password socket: /tmp/mysql.sock host: dbコマンドの理解
コンテナの作成
$ docker-compose build
build
は建てるの意味なので、コンテナを作成します。
Dockerfileの記述を変更した際などもdocker-compose build
で更新します。コンテナの起動
$ docker-compose upRuby on Railsでは
$ rails s
でアプリを起動していましたが、dockerでは$docker-compose up
でアプリを起動します。なぜというと、$docker-compose up
を実行すると、後述するdocker-compose.yml
に記述した$rails s
が実行されるためです。つまり、結果的にどちらも$ rails s
を実行しているだけなのです。メリットは何か
どの言語でも
docker-compose up
だけで起動ができます。これにより、自分が知らない言語でもアプリを起動できます。例えば、面接官がRubyやRuby on Railsを知らない場合、起動コマンドは当然知りません。しかし、あなたがdocker-compose.ymlに起動コマンドを記述すれば、
docker-compose up
を実行するだけで面接官でもアプリを起動できます。だから、Dockerはとても親切なのです。コンテナの停止・再起動
コンテナの停止$ docker-compose stopコンテナの停止は
stop
です。upの逆であるdown
ではありません。
インストールしたgem
やパッケージ
を反映させるには、一度アプリを再起動しなければなりません。
その際に$docker-compose stop
を実行して、アプリを停止させます。その後、$ docker-compose up
を実行し、再度起動します。コンテナの再起動$ docker-compose restartいちいち、
stop
とup
をやるのが面倒な場合は、$ docker-compose restart
でコンテナが再起動します。なので、基本的にgemインストール後は$ docker-compose restart
を実行します。コンテナの削除
$ docker-compose downコンテナを削除します。
-v
で後述するvolumes(バックアップデータ)も削除されます。
コンテナが削除されますので、基本的に利用しません。Dockerfileを理解する
Dockerの使い方がわかったところで、Dockerfileでよく使う項目を学習していきます。
公式ページで詳しく記載されているのは、下記になります。
Dockerfileの辞書はこちら。
自分が知りたい項目があれば、一度確認すると良いでしょう。では、一緒にみていきましょう。
FROM
FROM
ではインストールしたいrubyのバーションを指定します。
実際にrubyをインストールするには、複数のコマンドを実行しなければならないが、それらをセットにしたimage
を利用して、1行でrubをインストールする。例えば、rubyのをインストールしたい場合、
dockerfileFROM rubyと記述するだけ、rubyの環境構築ができる。
さらに、rubyのバージョンを2.5.1
と指定したい場合は、dockerfileFROM ruby:2.5.1と記述してバーションを指定する。
Dockerではimage
のバージョンのことをtag
と呼びます。基本的な下記の公式になります。
DockerfileFROM image:tag(バージョン) #imageはrubyやphpなどの言語などを指定する。基本的に
image
はrubyやphpなどの言語やmysql
などを指定しますが、imageを自作することも可能です。imageをカスタマイズして自作すれば、より簡略して環境構築ができます。会社で用意されたimage
を利用して開発することもあるようです。今回はruby:2.5.1を利用したいので、下記の記述で進めていきます。
DockerfileFROM ruby:2.5.1RUN
RUN
では実行したいコマンドを記述します。RUNFROM ruby:2.5.1 RUN 実行したいコマンドNode.jsやyarnなど必要なものをインストールしたり、bundle installなどコンテナをbuildした際に実行させたいコマンドを記述します。
DockerfileFROM ruby:2.5.1 ## ディレクトリ(ファルダ)を作成する。 RUN mkdir /webapp ## bundle installでgemを反映させる(build直後)。ターミナルでやる場合, $ docker-compose run web bundle installのようにします(後述します)。 RUN bundle install ## 必要なものをインストール RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ git \ vim ##yarnのインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ 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 && apt-get install -y yarn ##Nodejsをバージョン指定してインストール RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && \ apt-get install nodejs
apt-get
はLinuxコマンドです。macでは利用できませんが、Dockerのコンテナ上では利用できます。ENV
DockerfileENV 変数 値 # $変数で利用可能例えば、フォルダ
app_name
を作成し、これを変数APP
と定義したい場合、DockerfileのENV例FROM ruby:2.5.1 RUN mkdir /app_name ENV APP /app_nameと記述する。
これで、APP = app_name
と定義される。定義した変数を利用したい場合、
$
マークをつける。
今回の例だとAPP
を利用するには、$APP
と記述する。DockerfileのENV例FROM ruby:2.5.1 RUN mkdir /app_name ENV APP /app_name WORKDIR $APP # 変数 APPを指定しているWORKDIR
DockerfileFROM ruby:2.5.1 RUN mkdir /app_name ENV APP /app_name WORKDIR $APPワーキングディレクトリを定義する。
ワーキングディレクトリとは、作業用フォルダを意味する。
つまりWORKDIR
では、アプリ開発するフォルダを指定します。
Dockerなしだと$rails new アプリ名
でワーキングディレクトリを作成&指定されていたが、Dockerでは、RUN mkdir /フォルダ名
でフォルダを作成し、それをWORKDIR /フォルダ名
で指定する必要があります。WORKDIRの公式リファレンス
そもそもワーキングディレクトリとは?作業用フォルダ = カレントディレクトリ = .
カレントディレクトリ(英語: current directory、現行ディレクトリ。つまり現在開いているフォルダ)とは、現在の位置であるディレクトリ(フォルダ)のことである。作業フォルダ(ワーキングディレクトリ)とも呼ばれることがある。ADD
DockerfileADD [追加したいもの] → [追加したい場所]
左にあるファイル
を右の場所
に追加する。フォルダ内にファイルを追加したい場合は、
フォルダ名/
と記述する。
ファイルを上書きさせたい場合は、フォルダ名/ファイル名
と記述する。testファイルをDirフォルダに入れる場合ADD test Dir/testの内容をDirフォルダのtestに上書きADD test Dir/testRailsでよく使う例WORKDIR /webapp ## はじめに記述したGemfile → Dockerの作業用ディレクトリに追加 ADD ./Gemfile /webapp/Gemfile ## はじめに記述したGemfile.lock → Dockerの作業用ディレクトリに追加 ADD ./Gemfile.lock /webapp/Gemfile.lock使うことはないが、知識として知っておきたいこと。
条件を指定して取り込むADD hom* /mydir/ # "hom" で始まる全てのファイルを追加 ADD hom?.txt /mydir/ # ? は1文字だけ一致します。例: "home.txt"その他は辞書で調べてね
Dockerfileの辞書はこちら。
COPYとADDの違い実例
Dockerfile(ruby)FROM ruby:2.5.1 #ruby 2.5.1のimageを利用 # RUNはコマンド実行を意味する。必要なものをインストール RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ git \ vim #yarnのインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ 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 && apt-get install -y yarn #Nodejsをバージョン指定してインストール RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && \ apt-get install nodejs #Dockerでアプリ開発をするディレクトリを作成する。 RUN mkdir /webapp #作成したディレクトリを作業用のディレクトリに指定する。 WORKDIR /webapp #値は1でなくても何でも良いです。dockerfileとかだとDontWarnにしてる例が多いです。 ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn #GemfileとGemfile.lockを追加 ADD ./Gemfile /webapp/Gemfile ADD ./Gemfile.lock /webapp/Gemfile.lock #bundlerをインストール(途中からDockerを導入したため、bundlerを一致させないとエラーが発生するため) RUN gem install bundler -v 2.1.4 #gemをインストールするために、bundle install RUN bundle install #現在のディレクトリ に /webappの内容を追加 ADD . /webapp #puma.rb用のsocketsを作成 RUN mkdir -p tmp/socketsよく使う内容を把握しておけば、意味は理解できるはず。
docker-compose.ymlを理解する
docker-compose.ymlの辞書はこちら。
読み込みdocker-compose.yml → Dockerfileversion
まずdocker-composeのバージョンを指定します。
どんなバージョンがあるかを知りたい方はこちらdocker-compose.yml#version:3のdocker-composeを利用 version: "3"services
db用, アプリ用などに分ける
docker-compose.ymlversion: "3" services: db: #dbに関することを書く #この例だとdbにしているが、名前は自由 app: #appのことを書く #この例だとappにしているが、名前は自由(よくある例:web) nginx: #本番環境で公開するために必要なnginxについて書く ##この例だとnginxにしているが、名前は自由(よくある例:web)コマンドの実行
サービスを分けることによって、コマンドをdbに対してのコマンドなのか、appに対してのコマンドなのか使い分けることができる。
コマンドの公式$ docker-compose run サービス名 コマンド
run
は実行するの意味があるので、docker-compose.yml
のサービス名
に対してコマンド
をrun(実行)
の意味になるdbに対してコマンド実行したい場合、
docker-compose.ymlversion: "3" services: db: #ここに対して対して、コマンドを実行したい app: nginx:サービスがdbなので
dbに関するコマンド処理を実行$ docker-compose run db コマンドとなる。
run
は実行するの意味があるので、docker-compose.yml
のdb
に対してコマンド
をrun(実行)
の意味になる具体例:dbにコマンド処理(mysql)$ docker-compose run db mysql -u [ユーザー名] -p続いて、appに対してコマンド処理をしたい場合
docker-compose.ymlversion: "3" services: db: app: #ここに対して対して、コマンドを実行したい nginx:サービス名がappなので、
appに対してコマンド実行$ docker-compose run app コマンドとなります。
run
は実行するの意味があるので、docker-compose.yml
のapp
に対してコマンド
をrun(実行)
の意味になる例:appにコマンド処理#appに対してコマンド実行したい(imageがrubyなので、railsに関するコマンドはここ) $ docker-compose run app bundle install $ docker-compose run app rake db:create $ docker-compose run app rake db:migrate #今回のdocker-compose.ymlがappにしているだけで、もしも[web]としていたら、下記になる $ docker-compose run web bundle install $ docker-compose run web rake db:create $ docker-compose run web rake db:migrate特にコマンドはないですが、nginxに対してコマンド処理をしたい場合
docker-compose.ymlversion: "3" services: db: app: nginx: #ここに対して対して、コマンドを実行したいnginxに対してコマンド$ docker-compose run nginx [コマンド]
run
は実行するの意味があるので、docker-compose.yml
のnginx
に対してコマンド
をrun(実行)
の意味になるbuild: 読み込むDockerfileを指定する
先ほど記述した
db
やapp
といったservicesごとに、どのDockerfileを読み込むのか指定する必要がある。
build:
を記述して、どのDockerfileを読み込むのか指定します。context: Dockerfileを持つフォルダを指定する
フォルダを指定してDockerfileを読み込む場合は、
build:
下のcontext:
にパスを記述します。
では例をみていきましょう。ワーキングディレクトリ直下にある場合
/webapp(アプリ名) ├── docker-compose.yml ├── Dockerfile (これを指定したい) ├── Gemfile └── Gemfile.lockカレントディレクトリである
webapp
フォルダ内にDockerfileがあります。
カレントディレクトリのパスは.
なので、下記のように指定します。docker-compose.ymlversion: "3" services: app: build: context: . #カレントディレクトリ上のDockerfileを読み込むこれでサービス
app
はカレントディレクトリにあるDockerfile
を読み込みます。
デフォルトでDockerfile
を読み込む設定になっているので、ファイル名は指定しなくて大丈夫です。contextを省略した場合version: "3" services: app: #webapp / Dockerfile #直下にあるので build: . #appはカレントディレクトリ(.)にあるDockerfileを使うよくある例として、
build: .
とcontext:
を省略している例があります。
やっていることは同じなので、context:
を理解すれば大丈夫です。では、さらに例をみて理解を深めましょう。
フォルダの中にDockerfileがある場合
/webapp ├── containers │ └── nginx │ ├── Dockerfile (nginx用:ここを指定したい) │ └── nginx.conf ├── docker-compose.yml ├── Gemfile └── Gemfile.lockこの例では、
webapp/containers/nginxフォルダ
内のDockerfileを利用したいので、containers/nginx
を指定します。docker-compose.ymlversion: "3" services: nginx: build: context: containers/nginx #nginフォルダ内のDockerfileを使うDockerfileが不要な場合(imageだけで十分)
下記のように、imageしかDockerfileに記述する必要がない場合、
Dockerfile(mysql用)FROM mysql:mysql:5.6.47わざわざDockerfileを作成せずに、直接docker-compose.ymlにimageを記述すればよい。
Dockerfileなし/webapp ├── docker-compose.yml ├── Gemfile └── Gemfile.lockサービス
db
はimage: mysql:5.6.47
を利用したい場合、docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 #imageを直接指定応用:サービスごとにDockerfile(複数)を使い分ける
これまで学んだことを組み合わせて、
サービスapp
用のDockerfile(image: ruby)と
サービスnginx
用のDockerfile(image: nginx)を使い分けましょう。
サービスdb
はimageを直接指定します。フォルダの階層/webapp ├── containers │ └── nginx │ ├── Dockerfile (nginx用) │ └── nginx.conf ├── docker-compose.yml ├── Dockerfile (app用) ├── Gemfile └── Gemfile.lock下記のdocker-composeのdbに対して、image: を指定している。
このように、Dockerfileを作成しなくてもimageを指定することが可能docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 app: build: . nginx: build: context: containers/nginxdockerfile:ファイル名がDockerfileではない場合
デフォルトでは、
context:
で指定したフォルダ内のDockerfile
を見つけてbuildします。
ここでは、ファイル名がDockerfile
ではない場合を解説します。例えば、nginx用のDockerfileを
Dockerfile-nginx
というファイルだった場合
dockerfile:
を記述してDockerfileとして読み込みたいファイルを指定します。
公式リファレンスdocker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 app: build: . nginx: build: context: containers/nginx dockerfile: Dockerfile-nginx #フィル名を指定するdepends_on:
サービスとサービスを紐付ける
ここまで学んだ、下記だとdb, app, nginxが繋がっていません。
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 app: build: . nginx: build: context: containers/nginx今回は、それぞれのサービスを紐づけます。
dbとappを紐付ける
app単体だと,dbのデータを保持できないので、紐付けます。
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 app: build: . depends_on: #依存する - db #dbを紐付けこれにより、
app
を起動するとdb
も起動させます。
app
系のコマンド実行する際は、DBの情報が必要になるので、app
にdb
を紐付けています。
ターミナルコマンドを見て、より理解を深めましょう。appに対するコマンド$ docker-compose run app rails g model messagedbが起動している箇所Starting web-share_db_1 ... done # dbが起動していると表示されており、appのコマンド実行前に
db
が起動しているとわかります。appとnginxを紐付ける
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 app: build: . depends_on: #依存する - db #dbと紐付け nginx: build: context: containers/nginx depends_on: #依存する - app #appと紐付けnginxを起動すると、
app
も起動する。app
が起動するので、db
も起動します。
db ← app ← nginx
では、
$ docker-compse up
実行時に、の動作をみましょう。$ docker-compose up Starting web-share_db_1 ... done #dbが起動 Starting web-share_app_1 ... done #appが起動 Starting web-share_nginx_1 ... done #nginxが起動 #紐付けされる Attaching to web-share_db_1, web-share_app_1, web-share_nginx_1それぞれのサービスが起動し、Attachingで紐づいていることがわかる。
Nginxとappを紐付ける理由
Nginxを利用していない場合、
localhost:3000
というように:3000
をurlに含めないとサイトを見れません。example.comの場合、
example.com:3000
でなければサイトにアクセスできない。Nginxでアプリを起動すると80ポートで起動するので、
localhost
だけでサイトを見れます。:3000
のようなポート番号を指定する必要はありません。example.comの場合、
example.com
でアクセスできる。ポート番号なしにアクセスできるようにするために、
nginx
にapp
を紐付けています。複数のサービスを紐付ける
複数のサービスの紐付けたい場合があると思います。
その際は下記のdocker-compose.ymlのように記述しますdocker-compose.ymlversion: "3.8" services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres上記の例では、サービス
web
は、redis
とdb
の二つの依存関係を同時に保有しています。
このように複数のサービスと紐付けることも可能です。volumes: (バックアップ)
volumes:でデータのバックアップを作成し、別のコンテナでもデータを使い回します。
これをしておかないと、Dockerfileを更新して$ docker-compose build
し直す際に、DBの情報が消えます。新品のiPhoneには、何もデータがないように
新しく作成したコンテナは、前のコンテナの情報は入っていません。buildするたびにDBの情報を作り直すのは、非常にめんどくさいので、バックアップを作成しておき、それをコンテナに使いまわします。
そのバックアップをvolume
と呼びます。volumeの必要性
現実の例
新しいPCを購入した = 前のPCのデータは当然ない
なので、前のPCで作成したバックアップデータを新しいPCに入れる。Dockerをbuildし直した(コンテナを作り直す)
新しいコンテナ = 前のコンテナのデータは当然ない
バックアップデータであるvolumeを新しいコンテナに紐付けるvolumesを記述する
docker-compose.ymlversion: "3" services: db: app: nginx: volumes: #ここにvolumeをセットする。 #volumeの名前は自由 mysql_data: gem_data: public-data: tmp-data: log-data:サービスとvolumesを紐付ける
dbのvolume名を
mysql_data
として場合、docker-compose.ymlversion: "3" services: db: volumes: - mysql_data: #使用するvolumeを指定 volumes: mysql_data: #これを紐付けmysqlを利用するに当たって、決まった階層があるので、それを指定します。
docker-compose.ymlversion: "3" services: db: volumes: - mysql_data:/var/lib/mysql # mysqlは読み込み場所が決まっているので(/var/lib/mysql)、 # 保存する階層を指定している volumes: mysql_data: #これを紐付けこれでbuildしてコンテナを作り直してもmysqlのデータは保持される。
appのgemをvolumesで保持する。
$docker-compose builddocker-compose.ymlversion: "3" services: db: volumes: - mysql_data:/var/lib/mysql app: volumes: - gem_data:/usr/local/bundle nginx: volumes: mysql_data: gem_data: #これをappに紐付ける実例
docker-composeversion: "3" services: db: image: mysql:5.6.47 volumes: - mysql_data:/var/lib/mysql app: build: context: . volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log - gem_data:/usr/local/bundle depends_on: - db nginx: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp depends_on: - app volumes: mysql_data: gem_data: public-data: tmp-data: log-data:command: docker-compose up時のコマンド
command:
は$docker-compose up時のコマンドを処理します。基本的にはサーバー起動関連のコマンドを記述します。
rails sで起動version: '3' services: web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0'"pumaで起動version: "3" services: app: build: context: . command: bundle exec puma -C config/puma.rb volumes:unicornで起動version: "3" services: app: build: context: . command: bundle exec unicorn_rails -c config/unicorn.rb volumes:rails s(邪魔なファイルを削除)version: '3' services: web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"この
command:
により、$docker-compose up
時に$rails s
などを実行されて、アプリが起動される。portを指定する
ポートを指定したい場合は下記
port:
を利用します。docker-compose.ymlversion: '3' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: 'password' ports: - "4306:3306" volumes: - mysql_data:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/app_name # volumeを使用してbundle installしてきたものを永続化 - gem_data:/usr/local/bundle ports: - "3000:3000" depends_on: - db volumes: mysql_data: gem_data:environment: 環境変数
環境変数を指定してbuildしたいとき、どのようにすればよいのか解説していきます。
mysqlの例
mysqlの環境変数を定義version: "3" services: db: image: mysql:5.6.47 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root上記の例でbuildすると、usernameとpasswordが反映されます。
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root #反映 password: password #反映本番環境で実行したい場合
docker-compose.ymlversion: "3" services: app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb" environment: RAILS_ENV: production #本番環境で$docker-compose up。指定なしの場合、developmentで実行envファイルを利用して、値を隠したい場合
env_file
オプションを利用して、envファイルを読み込みます。envファイルが複数の場合env_file: - ./common.env - ./apps/web.env - /opt/runtime_opts.envenvファイルが1つの場合env_file: .envこれで、envファイルを読み込む方法がわかりました。
では、どのように.envファイルで環境変数を定義すれば良いのか?
確認していきましょう!mysqlの環境変数を定義version: "3" services: db: image: mysql:5.6.47 environment: MYSQL_ROOT_PASSWORD: password #隠したい MYSQL_DATABASE: root #隠したいenvファイルを用意して、環境変数を定義
.envMYSQL_ROOT_PASSWORD=password MYSQL_DATABASE=rootでは、これを読み込みます
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 env_file: .env environment: MYSQL_ROOT_PASSWORD: password #隠したい MYSQL_DATABASE: root #隠したい
env_file:
で読み込んだので、environment:
は不要になりました。
なので、environmet:
を削除しますdocker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 env_file: .envだいぶスッキリしましたね!
注意事項は
env_file
よりも、environment:
の方が優先されます。たとえば
.envMYSQL_ROOT_PASSWORD=pass12345 MYSQL_DATABASE=mysql_userdocker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 env_file: .env environment: MYSQL_ROOT_PASSWORD: password #優先=上書き MYSQL_DATABASE: root #優先=上書き上記のような場合は、
environment
の内容に上書きされます。docker-compose.ymlで環境変数を定義しない場合
environment:
を利用しなくても、実行可能です。
環境変数をdocker-compose.ymlで定義しない場合、
docker-compose run -e 環境変数=値 サービス名
で実行可能です。言うまでもなく、オプション-e
はenvironment
のeです。例$ docker-compose run -e RAILS_ENV=production app bundle install $ docker-compose run -e RAILS_ENV=production app rake db:create $ docker-compose run -e RAILS_ENV=production app rake db:migrate $ docker-compose run -e RAILS_ENV=production web bundle install $ docker-compose run -e RAILS_ENV=production web rake db:create $ docker-compose run -e RAILS_ENV=production web rake db:migrateじゃあ、なぜdocker-compose.yml上で定義しなければいけないのか?
それは$docker-compose up には、環境変数を指定するオプションが無いからです。
$ docker-compose up -e RAILS_ENV=production > -bash: $: command not found本番環境と開発環境で切り分ける場合
方法は2つ
方法1:環境変数を本番環境、開発環境で違うようにする。
docker-compose.ymlを本番環境(EC2)上で編集し、環境変数を定義する
開発環境のdocker-compose.ymlversion: "3" services: app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb"本番環境のdocker-compose.ymlversion: "3" services: app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb" environment: #EC2上でvimを使って追記 RAILS_ENV: production #EC2上でvimを使って追記env_fileでもよいでしょう
本番環境のdocker-compose.ymlversion: "3" services: app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb" env_file: .env #EC2上でvimを使って追記.envRAILS_ENV=production方法2
docker-compose.ymlを2つ作成し、開発環境用、本番環境用に使いわける。
docker-compose -f ファイル名 up
というように、-f
オプションを利用して、別のdocker-compose.ymlを指定することが可能です。参考:本番環境での Compose の利用 | Docker ドキュメント
例えば、
開発環境用
docker-compose.yml
と本番環境用docker-compose-production.yml
を用意した場合、基本的に読み込まれるのは
docker-compose.yml
です。
名前が異なるのでdocker-compose-production.yml
は読み込まれません。
しかし、-f
オプションを利用して、読み込むファイルを指定すれば、docker-compose-production.yml
でも読み込みされます。通常はdocker-compose.ymlで実行$ docker-compose updocker-compose-production.ymlで実行$ docker-compose -f docker-compose-production.yml up他にも
docker-compose.ymlに本番環境設定だけを追加したい場合、$ docker-compose -f docker-compose.yml -f docker-compose.production.yml up上記のように
-f
オプションを二つ利用して、合算させることも可能です。
ただし、コマンドは少しが長くなりますけどね。実例
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root ports: - "4306:3306" volumes: - mysql_data:/var/lib/mysql app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb" volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log - gem_data:/usr/local/bundle depends_on: - db tty: true stdin_open: true nginx: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp ports: - 80:80 depends_on: - app volumes: mysql_data: gem_data: public-data: tmp-data: log-data:実際に試みる2
docker-compose.ymlversion: "3" services: db: image: mysql:5.6.47 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root ports: - "4306:3306" volumes: - mysql_data:/var/lib/mysql app: build: context: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec puma -C config/puma.rb" volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log - gem_data:/usr/local/bundle depends_on: - db tty: true stdin_open: true nginx: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp ports: - 80:80 depends_on: - app volumes: mysql_data: gem_data: public-data: tmp-data: log-data:Dockerfile(app用)FROM ruby:2.5.1 RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ git \ vim #yarnのインストール RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ 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 && apt-get install -y yarn #Nodejsをバージョン指定してインストール RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && \ apt-get install nodejs RUN mkdir /webapp WORKDIR /webapp ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn ADD ./Gemfile /webapp/Gemfile ADD ./Gemfile.lock /webapp/Gemfile.lock RUN gem install bundler -v 2.1.4 RUN bundle install ADD . /webapp RUN mkdir -p tmp/socketscontainers/nginx/Dockerfile(nginx用)FROM nginx:1.15.8 RUN rm -f /etc/nginx/conf.d/* ADD nginx.conf /etc/nginx/conf.d/webapp.conf CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.confnginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name example.com [or 192.168.xx.xx [or localhost]]; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; root /webapp/public; client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @webapp; keepalive_timeout 5; location @webapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://webapp; } }puma.rb# Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } # Specifies the `environment` that Puma will run in. # environment ENV.fetch("RAILS_ENV") { "development" } # Specifies the `pidfile` that Puma will use. pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked webserver processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). # # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", truenginxの設定について
ここでは、nginxの詳細設定は解説しませんが、参考になるリンクを貼っておきます。
Nginx設定のまとめ
この記事を辞書代わりに使うと理解が早まるでしょう。upstream
docker-compose.ymlversion: "3" services: app: build: context: . command: bundle exec puma -C config/puma.rbdocker-compose.ymlの
command:
において、bundle exec puma -C config/puma.rb
が実行されいている。これはpumaによって起動するコマンドだが、その設定は
-C
オプションによりconfig/puma.rb
ファイルより読み込まれる。puma.rbでpuma.sockを作成する
puma.rbbind "unix://#{app_root}/tmp/sockets/puma.sock"
puma.sock
は、Nginxとソケット通信をする際に必要になるファイルです。puma.rbで作成したpuma.sockをnginx.confに読み込む
upstream
でsocketを指定します。nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; }proxy_pass
upstream
をproxy_pass
で指定する。nginx.confupstream puma { server unix:///usr/local/var/work/app-name/tmp/sockets/puma.sock; } server { location @puma { proxy_pass http://puma; #ここ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } }例えば、upstreamがwebappだった場合
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { location @webapp { proxy_pass http://webapp; } }listen 80
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; location @webapp { proxy_pass http://webapp; } }
listen 80;
でport:80を指定している。TCP 20 : FTP (データ)
TCP 21 : FTP (制御)
TCP 22 : SSH
TCP 23 : Telnet
TCP 25 : SMTP
UDP 53 : DNS
UDP 67 : DHCP(サーバ)
UDP 68 : DHCP(クライアント)
TCP 80 : HTTP
TCP 110 : POP3
UDP 123 : NTP
TCP 443 : HTTPS
WELL KNOWN PORT NUMBERS 0~1023特定のIPアドレス上で公開されているサーバ上で、HTTPというプロトコルにそったアプリケーション、Apacheなどが80番ポートで、クライアントとの通信を待機し、要求に応じてWebページの情報を送信するといった流れだ。
一般的にport:80を指定する。
location
server_name
** localhostを指定する場合 **
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name localhost; }server_nameは指定のドメインの場合に対象となります。
このケースではhttp://localhost:80の場合に適用されます。** IPアドレスを指定する場合 **
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name 192.168.11.11; }このケースでは、IPアドレスを指定しています。
http://192.168.11.11:80** ドメインを指定する場合 **
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name example.com; }このケースでは、ドメインを指定しています。
http://example.com:80** 複数合わせる場合 **
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { server_tokens off; listen 80; server_name example.com [or 192.168.xx.xx [or localhost]]; }proxy_set_header
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { server_tokens off; listen 80; server_name example.com [or 192.168.xx.xx [or localhost]]; location @webapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://webapp; } }基本的に
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host;としか利用しません。
X-Real-IP
これもHTTPヘッダの一つ。ロードバランサやプロキシを経由する時に送信元を判別するために利用。アプリケーション層の情報。
X-Forwarded-Forと同じような値だけど、複数の可能性があるX-Forwarded-Forと違って1つ。
X-Forwarded-For
HTTPヘッダの一つ。ロードバランサやプロキシを経由する時に送信元を判別するために利用。アプリケーション層の情報。
詳しくはこちらの記事をみてください
https://christina04.hatenablog.com/entry/2016/10/25/190000try_files
try_files $uri $uri.html $uri/index.html @webapp;指定のファイルが存在するかを左から探しに行きます。
例えばhttp://***/hogeでアクセスした場合はhoge.html、hoge/index.html、location @webapp {}の順番に探します。次の例をみてみましょう。
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name example.com [or 192.168.xx.xx [or localhost]]; try_files $uri/index.html $uri @webapp; location @webapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://webapp; } }
location
で定義した@webapp
をtry_files
で読み込みさせています。try_files $uri/index.html $uri @webapp;全体
nginx.confupstream webapp { server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; server_name example.com [or 192.168.xx.xx [or localhost]]; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; root /webapp/public; client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @webapp; keepalive_timeout 5; location @webapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://webapp; } }
- 投稿日:2020-08-02T09:49:33+09:00
Qtビルド環境のDockerの作成
Ubuntu18.04にQt5.10.1のビルド環境をインストール後に、サンプルプログラムをビルドする方法。
qtのインストーラのダウンロード
実行時にwgetで取得する方法もあるが、ここではあらかじめダウンロードしておく。
https://download.qt.io/new_archive/qt/5.10/5.10.1/qt-opensource-linux-x64-5.10.1.runQtのサイレントインストーラファイルの作成
Slient install Qt run installer on ubuntu server
https://stackoverflow.com/questions/25105269/silent-install-qt-run-installer-on-ubuntu-server
Windows環境のコンテナ化
- qt-installer-nonintaractive.qs
インストールディレクトリを /opt/Qt でインストールするように指定。
Qt5.10.1はQtIFW3.0.3を使用している。QtIFW3.2.1以降は認証が必要なようだが、このバージョンは認証の指定は不要。
認証の指定をする場合は Controller.prototype.CredentialsPageCallback でメールアドレスとパスワードを指定するか、設定フィアルを用意しておく必要あり。function Controller() { installer.autoRejectMessageBoxes(); installer.setMessageBoxAutomaticAnswer("installationError", QMessageBox.Retry); installer.setMessageBoxAutomaticAnswer("installationErrorWithRetry", QMessageBox.Retry); installer.setMessageBoxAutomaticAnswer("DownloadError", QMessageBox.Retry); installer.setMessageBoxAutomaticAnswer("archiveDownloadError", QMessageBox.Retry); installer.installationFinished.connect(function() { gui.clickButton(buttons.NextButton); }) } Controller.prototype.WelcomePageCallback = function() { // click delay here because the next button is initially disabled for ~1 second gui.clickButton(buttons.NextButton, 3000); } Controller.prototype.CredentialsPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.IntroductionPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.TargetDirectoryPageCallback = function() { gui.currentPageWidget().TargetDirectoryLineEdit.setText("/opt/Qt"); gui.clickButton(buttons.NextButton); } Controller.prototype.PerformInstallationPageCallback = function() { gui.clickButton(buttons.CommitButton); } Controller.prototype.ComponentSelectionPageCallback = function() { function list_packages() { var components = installer.components(); console.log("Available components: " + components.length); var packages = ["Packages: "]; for (var i = 0 ; i < components.length ;i++) { packages.push(components[i].name); } console.log(packages.join(" ")); } list_packages(); var widget = gui.currentPageWidget(); widget.deselectAll(); widget.selectComponent("qt.qt5.5101.gcc_64"); gui.clickButton(buttons.NextButton); } Controller.prototype.LicenseAgreementPageCallback = function() { gui.currentPageWidget().AcceptLicenseRadioButton.setChecked(true); gui.clickButton(buttons.NextButton); } Controller.prototype.StartMenuDirectoryPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.ReadyForInstallationPageCallback = function() { gui.clickButton(buttons.NextButton); } Controller.prototype.FinishedPageCallback = function() { var checkBoxForm = gui.currentPageWidget().LaunchQtCreatorCheckBoxForm; if (checkBoxForm && checkBoxForm.launchQtCreatorCheckBox) { checkBoxForm.launchQtCreatorCheckBox.checked = false; } gui.clickButton(buttons.FinishButton); }Dockerファイルの作成
- 最初にapt-getで必要なライブラリをインストール。
- Qtのサイレントインストールの実行
./qt-opensource-linux-x64-5.10.1.run --script qt-noninteractive.qs --platform minimal
- インストールパスのbinディレクトリをPATHに追加
- 作成済のsampleのプログラムを/tmpに展開、qmake→makeでサンプルプログラムをビルド
Dockerfile
FROM ubuntu:18.04 RUN apt-get update -y RUN apt-get install -y libfontconfig libdbus-1-3 libx11-6 libx11-xcb1 RUN apt-get update -y RUN apt-get install -y build-essential RUN apt-get install -y mesa-common-dev libglu1-mesa-dev libglib2.0-0 COPY qt-installer-noninteractive.qs /qt-noninteractive.qs COPY qt-opensource-linux-x64-5.10.1.run /qt-opensource-linux-x64-5.10.1.run RUN chmod +x qt-opensource-linux-x64-5.10.1.run RUN ./qt-opensource-linux-x64-5.10.1.run --script qt-noninteractive.qs --platform minimal ENV PATH $PATH:/opt/Qt/5.10.1/gcc_64/bin ADD sample.tar /tmp WORKDIR /tmp/sample RUN qmake RUN makeビルド
ディレクトリにDockerfile、qt-installer-noninteractive.qs、qt-opensource-linux-x64-5.10.1.run、sample.tarを配備して以下を実行。
docker build -t masana/ubuntu-qtenv:qt5.10.1 .
- 投稿日:2020-08-02T09:13:14+09:00
Docker Volume の上書きについて
前提
- 本記事執筆時の Docker 最新バージョン: 19.03
- 書いている人は、業務で本格的に docker を使ったりしておらず、個人開発で適当に使っていたが、よくわからず使っている部分もあったので改めて調べてるレベル。
悩み
前回 Docker Volume について調べてボリューム完全に理解したと思いながら構築していました。
しかし、単一ボリュームを複数コンテナのディレクトリにマウントする際に、元々コンテナのディレクトリにおいてあったファイルが上書きされたりする挙動を理解していないことに気づき、ちゃんと知っとかないとふとした時にデータ消去とかになったら怖いなと思った次第です。結論
- マウントするボリュームに何かしらファイルやディレクトリが存在すれば、マウントされるコンテナ側のディレクトリの中身は全部上書きされる。
- マウントするボリュームに何も入っていなくて、マウントされるコンテナ側のディレクトリに何か入っていれば、ボリュームにコピーされる。
以上です。シンプル。
以下は実際に上記を確かめてるだけなので、結論以上の情報はないです。試してみる
適当にデータの入ったディレクトリのあるコンテナを2つつくり、それぞれ同じボリュームをそのディレクトリにマウントするように Compose で立ち上げてみて、ボリュームの中身がどうなるか見てみました。
以下のような感じでファイルを用意しました。
volume_test ├── Dockerfile-vol01 ├── Dockerfile-vol02 ├── docker-compose.yml ├── vol01 └── file01 └── vol02 └── file02
まず適当にデータを入れたディレクトリだけがあるイメージを作ります。(vol02 は数字変えただけなので省略)
Dockerfile-vol01FROM ubuntu:latest COPY vol01 /vol01 CMD ["bin/sh"]$ docker image build -f Dockerfile-vol01 -t hoge/volcontainer01:latest .そして Compose で2つのコンテナを立ち上げ、データが入ったディレクトリそれぞれに、単一のボリューム(voltest)をマウントします。
docker-compose.ymlversion: "3" services: vol01: image: hoge/volcontainer01:latest container_name: volcontainer01 tty: true volumes: - voltest:/vol01 vol02: image: hoge/volcontainer02:latest container_name: volcontainer02 tty: true volumes: - voltest:/vol02 volumes: voltest: driver: local$ docker-compose up -dこの時、
voltest
の中身はどうなっているのか。$ docker container exec -it volcontainer01 ls vol01 file01
file01
だけが入っており、vol02
の方に入っていたfile02
は入っていません。
これは流れ的には、volcontainer01
が立ち上がった時にvoltest
ボリュームが生成され、vol01
に入っていた内容がコピーされます。
その後volcontainer02
が立ち上がってvol02
にvoltest
ボリュームがマウントされる際に、voltest
にはすでにファイルが存在するので、vol02
の中身をまるごと上書きしているということです。ちなみにこの時、もし
vol01
に何も入っておらず、vol02
にだけファイルが入っていた場合は、vol02
にマウントする時点で中身がコピーされるため、voltest
にはfile02
が入った状態になります。では試しに、このまま
voltest
の内容を変更してから Compose を削除し、再度立ち上げてみましょう。$ docker container exec -it volcontainer01 rm vol01/file01 $ docker container exec -it volcontainer01 touch vol01/addfile $ docker-compose down $ docker-compose up -dこの時、
voltest
の中身はこうなっています。$ docker container exec -it volcontainer01 ls vol01 addfileボリュームはデータの永続化のための仕組みなのでコンテナが破棄されても残ります。
再度 Compose でコンテナを立ち上げると、今度はvoltest
には既に先程入れたファイルが存在しており、vol01
の内容もvol02
の内容も上書きしてしまうためです。ということで、繰り返しになりますが、
- マウントするボリュームに何かしらファイルやディレクトリが存在すれば、マウントされるコンテナ側のディレクトリの中身は全部上書きされる。
- マウントするボリュームに何も入っていなくて、マウントされるコンテナ側のディレクトリに何か入っていれば、ボリュームにコピーされる。
ということが確認できました。
参考文献
- 投稿日:2020-08-02T08:14:43+09:00
オリジナルのアプリを完成させるまでの解説
環境
macOS 10.15.5
Rails 5.2.4.2
Docker 19.03.12概要
オリジナルアプリの概要はCRUDのシステムを意識した簡易的なメモアプリの開発です。
簡易的なアプリと言っても実用性には欠かないよう注意を払いました。行数が増えてもレイアウト崩れが起きないように実装し、文字数制限や空白の項目が新規作成されないようにも設定しました。Dockerを用いてフレームワークはRailsを使用しました。そしてHerokuにより公開をしています。
オリジナル性について
HTMLに関してはclass名などは学習サイトをヒントに用いて、デザインは外観は学習サイトをヒントにしましたが実装は全て自走で行いました。
Railsの機能の実装に関して事前に学習サイトを何度も繰り返し行い、CRUDの機能を頭に入れてから今回の作成を行いました。そのため短いコードなどはなるべくサイトなどを参考にせず、自分で覚えた内容で実装し、コマンド操作は基本的に全て頭に入れた内容のみで行いました。サイトについて
一覧ページをトップページとして定めメモの項目が個々の詳細が表示できるようにリンク指定をしています。その際に新規投稿された項目が最上部に移動するように実装しました。lists_controller.rbclass ListsController < ApplicationController def index @lists = List.all.order(created_at: :desc) end新規作成ページ
新規作成ページでは空白の内容と141文字以上の内容が実行されないように設定しています。list.rbclass List < ApplicationRecord validates :content, {presence: true, length: {maximum: 140}} end詳細ページ
メモ一覧の個々の項目のリンクから移動すると個々の詳細ページが閲覧できます。そこから「編集」と「削除」を実行することができます。編集ページ
編集ページではページを開いたときに編集前の内容が表示されるように実装しています。edit.html.erb<div class="form-bady"> <textarea name="content"><%= @list.content %></textarea> <input type="submit" value="編集"> </div>lists_controller.rbdef edit @list = List.find_by(id: params[:id]) endオリジナルアプリを作るにあたり意識したこと
わたしは自走できるエンジニアとしてスキルを身に付けたい!という思いからどんなやり方がそんなエンジニアに近づける方法なのか良く自問自答をします。今回このシンプルなメモアプリを作成しようと考えたのはRailsのCRUDの機能やMVCは完璧に落とし込もうと考えたのでこのシンプルさにまとめてみました。
今後はログイン機能やユーザーごとのアクセス権限を設けたページの作成などの機能を有したアプリの作成などにも取り組みたいです!
- 投稿日:2020-08-02T02:15:26+09:00
メモリ圧迫テストで利用できるコンテナの作り方
インフラ環境の構築や検証をしているとメモリが圧迫された時の挙動を確認したくなる時があるかと思います。
そんな時に以下のコンテナを使うと指定したメモリを専有してくれて便利です。
(k8s環境を想定していますが、dockerさえ入っていればdocker runで起動することが可能です)構成
・docker-entrypoint.sh
・Dockerfile
・deployment.yml内容
・docker-entrypoint.sh
#!/bin/sh MEMORY_USE_M=`echo $(($MEMORY_USE/1024/1024))` echo "${MEMORY_USE_M}MB" /usr/bin/stress -m 1 --vm-bytes $MEMORY_USE --vm-hang 0 -q・Dockerfile
FROM ubuntu:18.04 ENV MEMORY_USE 1134217728 ADD stress_1.0.4-2_arm64.deb . RUN apt-get install ./stress_1.0.4-2_arm64.deb ADD docker-entrypoint.sh . #CMD ["/usr/bin/stress", "-m", "1", "--vm-bytes", "$MEMORY_USE", "--vm-hang", "0", "-q"] ENTRYPOINT ["sh", "./docker-entrypoint.sh"]・stress.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: stress labels: run: stress spec: replicas: 1 selector: matchLabels: run: stress template: metadata: labels: run: stress spec: containers: - image: stress:latest name: stress imagePullPolicy: IfNotPresent env: - name: MEMORY_USE value: "2134217728"
- 投稿日:2020-08-02T00:47:10+09:00
VSCodeでリモートサーバのDockerコンテナに引きこもる for Windows10
背景
TwitterのTLに流れてきたVS Code Meetup #6をなんとなく見ていたんですが、
Shion Tanakaさん(@tnk4on)の発表に触発されました。
Remote-Containersの接続先ホストにFedora CoreOSを使うやりたいこと
- ローカルのWindowsマシンからリモートサーバにあるDockerコンテナへアクセスしたい
- Docker for Windows + VSCodeのようにVSCodeで直接コンテナにアタッチしたい(引きこもりたい)
検証環境
- リモートサーバ
- Ubuntu 20.04 LTS(ESXi上のVM)
- Docker version 19.03.12, build 48a66213fe
- dockeradminというdockerコマンドを実行できるユーザを作成済み
- ローカルマシン
- Windows10 Pro 2004
- VSCode 1.47.3(Extentionは以下をインストール)
- Docker for Windows 19.3.08
(ローカルマシンでDockerコンテナを動かす必要はないのですが、CLIコマンドを実行するために必要。Homeの場合は後述の手順を確認ください)リモートサーバへのDockerのインストール
Docker公式の手順にてdocker-ceをインストールしてます(Ubuntuのdocker.ioじゃないです)
特記事項はないので省略
あと、多分ですけどリモートサーバのDockerとローカルマシンのDocker CLIはバージョンがあってるほうがよさげSSH鍵の用意
今回VSCodeからリモートサーバ側のDockerへのアクセスにはSSHを利用します。
パスワード認証だと、VSCodeのDocker拡張がうまく動いてくれないので、鍵認証する必要があります。1. キーペアの作成
クライアントで作るべきなんですがめんどくさいのでリモート側で作成しました・・・
# 鍵の作成 dockeradmin@container-engine:~$ ssh-keygen -t rsa -b 4096 # 鍵のコピー dockeradmin@container-engine:~$ ssh-copy-id dockeradmin@localhostパスフレーズは入力してません(パスフレーズつけるとうまくいかなかった?)
2. 秘密鍵(id_rsa)をクライアントPCの.sshフォルダにコピー
必ずC:\Users\{username}\.ssh 配下に格納すること。
いくらか確認したのですが他のパスだとうまくいかない3. ssh-agentに鍵を登録する
これやらないと駄目でした
やってないとVSCodeさんから「これやってみ?」って以下のURL教えてくれます
https://code.visualstudio.com/docs/containers/sshWindows (OpenSSH): The latest version(s) of Windows 10 include OpenSSH by default. There is a Windows service, ssh-agent that is disabled by default, and needs to be re-enabled and set to automatic start. From an admin command prompt, run sc config ssh-agent start=auto and net start ssh-agent. Then, do ssh-add <keyfile>.
というわけでやります。
Microsoft Windows [Version 10.0.19041.388] (c) 2020 Microsoft Corporation. All rights reserved. C:\WINDOWS\system32>sc config ssh-agent start=auto [SC] ChangeServiceConfig SUCCESS C:\WINDOWS\system32>net start ssh-agent OpenSSH Authentication Agent サービスを開始します. OpenSSH Authentication Agent サービスは正常に開始されました。 C:\WINDOWS\system32>ssh-add c:\Users\rohisama\.ssh\id_rsa Identity added: c:\Users\rohisama\.ssh\id_rsa (dockeradmin@container-engine)VSCodeの設定
VSCodeのSettings.jsonを更新
以下を追加するだけです。追加したらVSCodeを再起動しましょう。
IPの部分はご自身の環境にあわせてどうぞ"docker.host": "ssh://dockeradmin@192.168.0.66",本番
確認の為、なんでもいいのでリモートサーバ側でDockerのコンテナを動かしておきます。
今回はなんかの練習用に作った mysql-trainingというイメージのコンテナを動かしてます(元イメージはmysql:8)1. VSCode起動
コンテナを起動したらローカルマシンのVSCodeを起動します。
起動したらDockerのクジラアイコンをクリック
成功している場合、VSCode上でリモートサーバ上で動いているコンテナの状態が確認できると思います(画像左上)
2. コンテナにアタッチ
いよいよVSCodeからリモートサーバで動いているコンテナにアタッチします・・・
起動しているコンテナを右クリック→Attach Visual Studio Codeと選択(画像参照)
成功すると新しいウインドウが開くはず
こんな感じ。開いたウィンドウの左下にアタッチ中のコンテナの情報が出ているのが分かります。
VSCodeからアタッチできるととても便利で、VSCodeからターミナルを開いてコマンド実行なんてお手の物
コンテナの中にあるファイルをVSCodeで編集するなんてことも可能なんです!!
一旦終わり(Windows10 Homeの人は続きも見てください)
需要があるかはわかりませんが、応用でクラウド上のコンテナに入るなんてことも可能なんじゃないだろうか。
なお筆者は職業上Javaやったりしてるんですが、VSCodeでDockerコンテナに引きこもれる事が分かってからはローカルマシンにはJDKはインストールせずOpenJdkのコンテナに開発用のソースコード一式置いてからのVSCodeで引きこもって開発してます(Java系のExtentionをインストールすれば割と普通に開発できます)
Windows10 Homeでもリモートサーバのコンテナに引きこもりたいあなたへ
本記事は内部的にDocker CLI(dockerコマンド)を使用している関係で、WindowsにDocker for Windowsをインストールする必要があります。
そのため現状Docker for Windowsがインストール不可であるWindows10 Homeの場合、dockerコマンドが実行できません。
※Insider Preview版だとWSL2使えるのでワンチャンインストール可能なのかもですが未調査です手元にWindows10 HomeなタブレットPCがあったので確認していたのですが、結果としてはDocker CLIの導入自体は可能でアタッチも問題なく可能なのですが若干の問題があります。
以下の方法を試しました。古いDocker-CEのバイナリから入手(当環境では無理だった)
google様のお知恵を拝借していると以下の記事がヒット
以下から古いバージョンのDocker-CEのバイナリが入手できます
https://download.docker.com/win/static/stable/x86_64/docker-17.09.0-ce.zipをDLし解凍するとdocker.exeがあるので、解凍したパスを環境変数のPathに登録することでdockerコマンドが利用可能になります。
ただし、バージョンが古いためかVSCodeからのアタッチは不可でした
(おそらくDocker CLIがSSHアクセスに対応していない?)Docker for WindowsがインストールされているPCからdocker.exeを持ってくる
デフォルトではC:\Program Files\Docker\Docker\resources\binにdocker.exeがあるので、Windows10 Homeのマシンの任意のパスにコピーします。
環境変数のPathに登録することでdockerコマンドが利用可能となりVSCodeからのアタッチも可能でした。
ただし、この方法にはWindows10 Proが必要になるためあまり現実的ではないかもしれません。
(個別に提供依頼があれば提供できますが・・・していいのか?)終わり
自身の個人用マシンはWindows10 Proなので、こんな事しなくてもVSCodeでコンテナ内部にアタッチできたりとかなり便利に使えてはいましたが、常にDocker起動していたいわけでもなく、いっそサーバ(ESXi)のVMの一つをコンテナ専用にしてそっちで開発も運用もできたらいいなぁと思い色々調べながら今回ようやく出来たのですが、ゴールに至るまでにズバリな回答を得られなかったので今回の記事作成と相成りました。
どれほどの需要があるかわかりませんが、皆様のコンテナ引きこもり生活の一助となれば幸いです。
- 投稿日:2020-08-02T00:38:48+09:00
【Rust】VSCodeを使ったDockerコンテナ上のRustアプリケーションをデバッグする方法
はじめに
最近Rustを触り始めて、コンパイラに怒られる日々を送っているTomoProgです。
この記事ではVSCodeを使い、Dockerコンテナ上で構築したRustアプリケーションをデバッグする方法を説明します。この記事の対象者
- Docker上のRustアプリケーションのデバッグ方法を知りたい方
前提
Rustアプリケーションが起動するDockerコンテナが起動していることを前提に話を進めます。
こちらの記事を参考にする場合はDockerコンテナを起動した状態で試してみてください。筆者の環境
筆者がデバッグ環境を構築した際の環境を載せておきます。
この環境通りでなくても、VSCodeとDockerがインストールされていれば構築できると思いますので、試してみてください。
- OS
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS"
- VSCode
$ code -v 1.47.2
- Docker
docker -v Docker version 19.03.12, build 48a66213feVSCodeからDockerコンテナに接続する
まずはVSCodeからDockerコンテナに接続できるようにします。
Dockerコンテナへの接続にはRemote-Containers
という拡張機能を使います。
Remote-Containers
はVSCode Remote Development
の機能の1つで、この拡張機能を使うことで、Dockerコンテナ内のファイルを直接操作できたり、VSCodeの拡張機能をコンテナ内にインストールできるようになります。
インストールが終わると画像のように画面の左下に緑色のアイコンが追加されます。
このアイコンを押すと、Remote-Containers
のメニューが表示されるので、Attach to Running Container...
を選択します。
選択すると起動しているDockerコンテナが表示されますので、Rustアプリケーションが起動しているDockerコンテナを選択しましょう。
VSCodeが新しく立ち上がり、左下の緑色のアイコンが選択したコンテナになっていれば接続成功です。
もし、以下のようなメッセージが出た場合はdockerコマンドをsudoなしで使用できるようにする必要があります。こちらを参照し設定してみてください。
Docker上のRustアプリケーションがあるフォルダを開く
次はRustアプリケーションがあるフォルダを開きます。
VSCodeのエクスプローラからフォルダーを開く
を選択し、Dockerコンテナ内のRustアプリケーションのフォルダを指定します。
筆者の環境では/work/hello/
がRustアプリケーションのフォルダなのでここを指定しています。
画像のように指定したフォルダの中身がVSCodeのエクスプローラに表示されれば完了です。
デバッガをインストールする
次はデバッガをインストールしていきます。
デバッガにはCodeLLDB
という拡張機能を使います。
CodeLLDB
はLLDB
というデバッガをVSCodeで利用できるようにする拡張機能です。
インストール完了後、インストールされている拡張機能を確認し、画像のようにLOCALではなくCONTAINERの方に
CodeLLDB
がインストールされていればデバッガのインストールは完了です。
launch.jsonを作成する
LLDB
を使用したデバッグができるようにlaunch.json
を作成します。
実行タブを開き、launch.jsonファイルを作成します
を選択し、LLDB
を選択します。
Cargo.toml
が存在すると以下のようなメッセージが表示されるため、「はい」を選択します。
「いいえ」を選択してもlaunch.json
は作成されますが、「はい」にすると環境に適したlaunch.json
を自動で作成してくれるため、非常に便利です。
この記事では「はい」を押して自動生成されたlaunch.json
を使用しています。画像のようにエディタに
launch.json
が表示されれば作成完了です。
ここまで設定すればデバッグ環境の構築は完了です。
デバッグする
それでは早速デバッグしてみましょう。
プログラムを一時停止したいところにブレークポイントを設定し、画像左上の再生ボタンを押せばデバッグが始まります。
ブレークポイントはエディタの行番号の少し左をクリックすると、画像のように赤い丸が表示されます。
画像のように設定したブレークポイントの位置でプログラムが止まれば成功です!
あとはウォッチ式に変数を追加したり、ステップ実行してみたり色々試してみてください。まとめ
VSCodeを使ってDockerコンテナ上のRustアプリケーションのデバッグ方法をまとめました。
Dockerコンテナ上のデバッグは何かと面倒なイメージでしたが、VSCode Remote Development
が登場したことにより、かなり簡単に設定できるようになり感動しました。それでは良いRustライフを!
TomoProg