- 投稿日:2020-07-06T23:29:02+09:00
DockerをHomebrewでインストール
- 投稿日:2020-07-06T23:11:11+09:00
なるべく最新Verで構築するRails6開発環境(Docker + Rails + Nginx + Puma + MySQL)
はじめに
こんにちは、Web系エンジニア転職にむけて学習中の Npakk と申します。
Railsを学習するにあたって開発環境を構築したので、その手順を少し解説を交えながらご紹介します。
Dockerでの構築経験はあまりなく、経験も乏しいのであくまで参考程度にご覧ください。
もし間違いやご指摘などあれば、ぜひぜひお願いいたします!Dockerを使用して、ローカル環境でRailsのWelcomeページを確認できるまでが、この記事のゴールです。
参考記事
- ほとんどこちらの記事を参考にさせていただいてます。
- こちらも参考にさせていただきました。
対象読者
- Railsを学びたいけど、環境をどう作ればいいかわからない初学者の方
- なるべく新しいRails環境を作りたい方
前提
- Macユーザーを対象としています
- Docker for Macがインストールされているものとします
- Nginx と Puma を連携させています
- 最新バージョンは、記事執筆時点で最新という意味です
- 全てのソフトウェアが最新バージョンなわけではありません
- 最新版だから動作が安定していたり、速度が速いというわけではありません
バージョン
- ホストOS(macOS Catalina 10.15.5)
- Docker(19.03.8)
- docker-compose(1.25.5)
- Ruby(2.7.1)
- Ruby on Rails(6.0.3.2)
- Nginx(1.19.0)
- MySQL(8.0)
1. ディレクトリの作成
ディレクトリ構成としては以下のようになります。
あくまで、手動で作成する項目のみ記載しています。/webapp ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── containers │ └── nginx │ ├── Dockerfile │ └── nginx.conf ├── docker-compose.yml ├── entrypoint.sh └── environments └── db.env1-1. アプリケーションルート
どこでもいいですが、わかりやすいところがおすすめです。
$ mkdir webapp1-2. Nginxコンテナ用ディレクトリ
Nginxは、Rails・DBとは別のディレクトリを作ります。
設定ファイルや DockerFile を別途配置します。$ mkdir -p webapp/containers/nginx1-3. 環境変数用ディレクトリ
DBで使うユーザーのパスワードなどを記載したファイルを配置します。
$ mkdir webapp/environments2. コンテナ生成用のファイルを作成
以降はアプリケーションルート内での操作となります。
$ cd webapp2-1. Rails用Dockerfile
Ruby と Node.js、yarnのバージョン指定は後述する docker-compose.yml から引数として指定します。
Rails6からは標準で Webpacker というgemを使用しており、yarn というパッケージ管理ソフトに依存しています。
yarn がないとうまく動かないため、これをコンテナにインストールする必要があります。また entrypoint.sh についてですが、Dockerをコマンドで停止せずに強制終了してしまうと、
Railsサーバーが開かれたままになるため、次からコンテナを起動するときにエラーが発生します。
その問題を回避するために server.pid を削除しています。$ vim DockerfileDockerfileARG RUBY_VERSION FROM ruby:$RUBY_VERSION ARG NODE_MAJOR ARG YARN_VERSION # ログインシェルとしてbashを使用する SHELL ["/bin/bash", "-c"] # nodejs取得 RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash - # yarn取得 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - &&\ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list # リポジトリを更新し依存モジュールをインストール RUN apt-get update -qq &&\ apt-get install -y\ build-essential\ nodejs\ yarn=$YARN_VERSION-1 # ルート直下にwebappという名前で作業ディレクトリを作成(コンテナ内のアプリケーションディレクトリ) RUN mkdir /webapp WORKDIR /webapp # ホストのGemfileとGemfile.lockをコンテナにコピー ADD Gemfile /webapp/Gemfile ADD Gemfile.lock /webapp/Gemfile.lock # bundle installの実行 RUN bundle install # ホストのアプリケーションディレクトリ内をすべてコンテナにコピー ADD . /webapp # puma.sockを配置するディレクトリを作成 RUN mkdir -p tmp/sockets # コンテナ開始時に必ず実行されるシェルスクリプトをコンテナにコピー ADD entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"]2-2. Gemfile
Railsの最新バージョンをこのファイルで指定します。
$ vim GemfileGemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3.2'2-3. Gemfile.lock
このファイルは作るだけで、中身は空で大丈夫です。
$ touch Gemfile.lock2-4. Nginx用Dockerfile
$ vim containers/nginx/Dockerfile/containers/nginx/DockerfileFROM nginx:1.19.0 # インクルード用のディレクトリ内を削除 RUN rm -f /etc/nginx/conf.d/* # Nginxの設定ファイルをコンテナにコピー ADD nginx.conf /etc/nginx/conf.d/webapp.conf # ビルド完了後にNginxを起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf2-5. Nginx用設定ファイル
$ vim containers/nginx/nginx.conf/containers/nginx/nginx.conf# プロキシ先の指定 # Nginxが受け取ったリクエストをバックエンドのpumaに送信 upstream webapp { # ソケット通信したいのでpuma.sockを指定 server unix:///webapp/tmp/sockets/puma.sock; } server { listen 80; # ドメインもしくはIPを指定 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; } }2-6. DB接続用設定ファイル
ユーザー名・パスワードなどは適宜変更してください。
$ vim environments/db.envdb.envMYSQL_ROOT_PASSWORD=db_root_password MYSQL_USER=user_name MYSQL_PASSWORD=user_password2-7. entrypoint.sh
entrypoint.sh#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"2-8. docker-compose.yml
argsにRubyなどのバージョンを指定します。
ここで指定することによりDockerfileに値が渡されます。$ vim docker-compose.ymldocker-compose.ymlversion: '3.7' services: app: build: context: . args: RUBY_VERSION: '2.7.1' NODE_MAJOR: '14' YARN_VERSION: '1.22.4' env_file: - ./environments/db.env command: bundle exec puma -C config/puma.rb volumes: - .:/webapp - public-data:/webapp/public - tmp-data:/webapp/tmp - log-data:/webapp/log depends_on: - db db: image: mysql:8.0 env_file: - ./environments/db.env volumes: - db-data:/var/lib/mysql web: build: context: containers/nginx volumes: - public-data:/webapp/public - tmp-data:/webapp/tmp ports: - 80:80 depends_on: - app volumes: public-data: tmp-data: log-data: db-data:3. Railsアプリケーションの生成と編集
3-1. Railsアプリケーションの生成
ここまでファイルとディレクトリを準備できたら、Railsアプリケーションを作成します。
以下のコマンドを実行すると、コンテナ内でRailsアプリケーションが生成されます。
DBにはMySQLを指定し、gemをこの時点でインストールしないようにbundle installの実行を抑制しています。$ docker-compose run --rm app rails new . --force --database=mysql --skip-bundleコンテナ内で生成されたアプリケーションをホスト側から編集するには、いちいちコンテナを実行しないといけないため不便です。
そこで、コンテナ内に生成されたディレクトリと、ホスト側のアプリケーションルートを繋ぎます。
こうすることによって、ホスト側のアプリケーションルートにファイルが生成されます。
これらのファイルを編集すれば、コンテナ内のディレクトリにも反映されるようになります。
(既にこの対応は以下の箇所で行っているので、安心してください。)docker-compose.yml#省略 volumes: - .:/webapp #省略実行時に発生するエラー・警告について
Railsアプリケーション生成コマンド実行時、いくつかエラーと警告が発生します。
「失敗した!」と思われる前に、以下に記載するものについては無視してください。
(記載した以外のエラーや警告がもし発生した場合、一度最後まで手順を実行することをおすすめします。)apt-key
deb.nodesource.comから落としてきたシェルスクリプトに記載されたapt-keyコマンドで発生した警告です。
詳細を調べてもいまいちよくわからなかったのですが、これを無視してもRailsの環境は構築できます。
(誰か詳しい方がいたら教えてください…)Step 6/18 : RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash - ・ ・ ・ + curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - Warning: apt-key output should not be parsed (stdout is not a terminal)debconf
これもいまいちよくわかりません。(書いといてなんだって話なんですが。)
apt-utilsをインストールしても消えなかったです。
無視しても大丈夫です。Step 8/18 : RUN apt-get update -qq && apt-get install -y build-essential nodejs yarn=$YARN_VERSION-1 ・ ・ ・ debconf: delaying package configuration, since apt-utils is not installedmysql2
Railsアプリケーション生成コマンドを実行して、最後に出力されたのがこのエラーです。
Gemfileにリストされたmysql2のgemがないよってことで、bundle installを迫ってきています。このコマンドを実行した時点では、GemfileにはRailsしか記載されておらず、
推測ですが、下記の流れで処理されているのではないかと思います。
1. Gemfileに記載されたRalilsがインストールされる
2. Rails newにより、Gemfileの記載が更新されmysql2などが追加される
3. 最後に、Gemfileに書かれたRails以外のgemがインストールされていないためエラーが発生このエラーを無視してもWelcomeページは確認できるので、一度最後まで手順を実施してみてください。
Could not find gem 'mysql2 (>= 0.4.4)' in any of the gem sources listed in your Gemfile. Run `bundle install` to install missing gems.3-2. 権限変更
生成したRailsアプリケーションのファイル群の所有権が root となっているので、現在のログインユーザーに変更します。
$ sudo chown -R $USER:$USER .3-3. puma.rbの編集
$ vim config/puma.rb元の記載は削除して、以下の内容を貼り付けてください。
puma.rbthreads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i threads threads_count, threads_count port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { "development" } 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", true3-4. database.ymlの編集
$ vim config/database.yml元の記載は削除して、以下の内容を貼り付けてください。
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch('MYSQL_USER') { 'root' } %> password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %> host: db development: <<: *default database: webapp_development test: <<: *default database: webapp_test上記のMYSQL_USER と MYSQL_PASSWORD は DB接続用の情報ファイル で定義した環境変数名を設定します。
4. イメージのビルドとコンテナの起動
いよいよコンテナを起動します!
4-1. イメージのビルド
Dockerfile 及び、DockerHub より引っ張ってきたイメージを全てビルドします。
$ docker-compose buildビルドが完了したら以下のコマンドで確認します。
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE webapp_web latest 0ae7b3fc51fd 38 seconds ago 132MB webapp_app latest d661a9898271 47 seconds ago 1.27GB <none> <none> 83d4ec18ac0c 6 minutes ago 1.06GB ruby 2.7.1 9b840f43471e 9 days ago 842MB nginx 1.19.0 2622e6cca7eb 3 weeks ago 132MB mysql 8.0 be0dbf01a0f3 3 weeks ago 541MB4-2. コンテナの起動
ビルドしたら、下記のコマンドでコンテナを立ち上げます。
$ docker-compose up -dコンテナが起動しているか確認します。
$ docker-compose ps全てのコンテナの State が Up となっていることを確認してください。
Name Command State Ports --------------------------------------------------------------------------- webapp_app_1 entrypoint.sh bundle exec ... Up webapp_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp webapp_web_1 /docker-entrypoint.sh /bin ... Up 0.0.0.0:80->80/tcpビルドに失敗した場合
イメージのビルドに失敗したり、コンテナの起動に失敗するとローカルにゴミファイルがたまってしまいます。
一度全てきれいにしたい場合は、コンテナとイメージを全て削除するコマンドを使います。
まずは、コンテナの起動を止めてから実行してください。コンテナを停止する
$ docker-compose stopすべてのコンテナを削除する
$ docker rm $(docker ps -q -a)すべてのイメージを削除する
$ docker rmi $(docker images -q)5. DB設定
5-1. 権限の付与
DBの操作を一般ユーザーで行うため、実行権限を付与します。
GRANT文を記述したSQLファイルを作成します。
user_name は DB接続用の情報ファイル に設定した MYSQL_USER の値に置き換えてください。$ vim db/grant_user.sqlgrant_user.sqlGRANT ALL PRIVILEGES ON *.* TO 'user_name'@'%'; FLUSH PRIVILEGES;dbコンテナに向けてクエリを送ります。
パスワードを求められるので、rootのパスワードを入力してください。$ docker-compose exec db mysql -u root -p -e"$(cat db/grant_user.sql)"権限が付与されたか確認します。
パスワードを求められるので、一般ユーザーのパスワードを入力してください。$ docker-compose exec db mysql -u user_name -p -e"show grants;"実行結果が横に長くてみづらいかもしれません。
MySQL5系では全ての権限が付与されている場合、「ALL PRIVILEGES」と表示されていたみたいですが、
8系ではちゃんと全ての権限名が表示されるため、このような横に長い結果になっているようです。+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Grants for user_name@% | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, CREATE ROLE, DROP ROLE ON *.* TO `user_name`@`%` | | GRANT APPLICATION_PASSWORD_ADMIN,AUDIT_ADMIN,BACKUP_ADMIN,BINLOG_ADMIN,BINLOG_ENCRYPTION_ADMIN,CLONE_ADMIN,CONNECTION_ADMIN,ENCRYPTION_KEY_ADMIN,GROUP_REPLICATION_ADMIN,INNODB_REDO_LOG_ARCHIVE,PERSIST_RO_VARIABLES_ADMIN,REPLICATION_APPLIER,REPLICATION_SLAVE_ADMIN,RESOURCE_GROUP_ADMIN,RESOURCE_GROUP_USER,ROLE_ADMIN,SERVICE_CONNECTION_ADMIN,SESSION_VARIABLES_ADMIN,SET_USER_ID,SHOW_ROUTINE,SYSTEM_USER,SYSTEM_VARIABLES_ADMIN,TABLE_ENCRYPTION_ADMIN,XA_RECOVER_ADMIN ON *.* TO `user_name`@`%` | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+5-2. DBの作成
railsコマンドでDBを作成します。
$ docker-compose exec app rails db:create6. 確認
お疲れさまでした!
下記のlocalhostをクリックして、Welcomeページが表示されるでしょうか。
Rails と Ruby のバージョンが指定したものであるか、確認してください。あとがき
うまくWelcomeページが表示されましたでしょうか?
参考記事を見ながら構築していったのですが、Rails6用に書かれていなかったため、かなり苦労しました…。(Rails学ぶことが目的だったので、Rails5でよかったですね…)
Rails6に対応したあとはバージョンの記載を一元管理したり、色々なサイトで書かれていることを網羅して今回の構築ファイルたちができあがりました。
とりあえずはこの環境でRails勉強していきます!もし間違い・ご指摘などあればぜひお願いします。
今度はRails関連の記事でお会いしましょう!(多分)
- 投稿日:2020-07-06T22:54:33+09:00
ローカル環境をなるべく汚さずにNginxでBasic認証
TL;DR
Dockerの
httpd
イメージを利用してhtpasswd
コマンドを実行し、得られた行をコピペしましょうやり方詳細
Basic認証をするには、
.htpasswd
ファイルを作成する必要があります。しかし、Nginxにはそのためのツールがついてきません。
かといって、そのためだけにApacheやそれ由来のツールをインストールするのは癪ですし、一時的に特定のツールが使いたいということなので、Dockerの出番です。Apacheのイメージ、
httpd
を利用します。これにはhtpasswd
コマンドがついてきます。次のようなコマンドで起動します。--rm
をつけることで、セッションを閉じるとコンテナが破棄されるようになります。docker run -it --rm httpd bashセッションが起動したら、お待ちかね
htpasswd
コマンドを実行します。コマンド1回毎に生成されるのは1行なので、-n
オプションをつけて標準出力に吐かせます。下のコマンドのどちらかを実行します。違いはパスワードを後から入力するか、引数として最初から渡すかの違いです。htpasswd -n <ユーザ名> htpasswd -nb <ユーザ名> <パスワード><ユーザ名>:<ハッシュ値>のような行が出るのでコピーし、テキストエディタに貼り付けて保存します。Nginxでは
.htpasswd
以外の名前でも構いません。
また、最後の空行は無視して構いません。複数ユーザの認証を行う際には、<ユーザ名1>:<ハッシュ値> <ユーザ名2>:<ハッシュ値> <ユーザ名3>:<ハッシュ値>のように並べます。少なくともUbuntu 18.04付属のNginxでは強固なBCrypt(
-B
オプション)が使用不可なので注意してください。後は
nginx.conf
や各サイトの設定ファイルのlocation
節内に以下の2行auth_basic "<Basic認証時のメッセージ>" auth_basic_user_file "<.htpasswdファイルのパス>"を追加します。Nginxのリロード(
nginx -s reload
orsystemctl reload nginx
)もお忘れなく。
- 投稿日:2020-07-06T22:49:19+09:00
jupyterをdocker-composeで起動2
はじめに
前回は、jupyterのdockerイメージ(scipy-notebook)をベースにjupyter pluginも入れて、
docker-composeを使ってイメージの作成と起動しました。今回は、dockerのpythonイメージをベースにjupyterとdjangoをインストールして、jupyterとdjangoのサーバを起動することを確認しました。
ソースは github にあげてあります。
ディレクトリ構成
フォルダはdockerの配下にmainのDockerfileとjupyterのdockerファイルが存在し、
jupyterのdockerファイルはmainに依存して作成されます。
Pipfileとmain_projectはmain元となるプロジェクトになります。└── docker ├── jupyter ├── .jupyter └── jupyter_notebook_config.py ├── Dockerfile └── docker-compose.yml └── main ├── Dockerfile └── docker-compose.yml └── main_project/* └── Pipfileファイル
docker/main/docker-compose.yml
buildするとmain-project という名前でイメージを作成します。
docker-compose.ymlversion: '3' services: main: image: main-project:1.0.0 build: context: ../../ dockerfile: ./docker/main/Dockerfile ports: - "8000:8000" volumes: - ../../main_project:/usr/src/app/main_projectdocker/main/Dockerfile
元となるプロジェクトのdockerイメージのコードです。
# jupyter lab : 2.1.3 FROM python:3.6.8 WORKDIR /usr/src/app RUN pip install --upgrade pip && pip install pipenv COPY ./Pipfile /usr/src/app/Pipfile RUN pipenv install --system --skip-lock CMD python main_project/manage.py runserver 0.0.0.0:8000 EXPOSE 8000docker/jupyter/docker-compose.yml
docker-compose.ymlversion: '3' services: jupyter: image: main-project-jupyter:1.0.0 build: context: . ports: - "8888:8888" - "8000:8000" volumes: - ./.jupyter:/root/.jupyter - ./notebook:/usr/src/app/notebook - ../../main_project:/usr/src/app/main_projectdocker/jupyter/Dockerfile
上記で作成したmain-projectに依存してdockerイメージのコードを作成していきます。
djangoとjupyterの両方を起動します。FROM main-project:1.0.0 WORKDIR /usr/src/app COPY .jupyter /usr/src/app/.jupyter # jupyter RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - RUN apt-get install -y nodejs npm RUN pip install jupyterlab RUN jupyter labextension install \ @lckr/jupyterlab_variableinspector \ @krassowski/jupyterlab-lsp \ @axlair/jupyterlab_vim RUN pip install jupyter-lsp python-language-server[all] RUN jupyter lab build # library RUN pip install pandas lxml html5lib beautifulsoup4 matplotlib CMD python main_project/manage.py runserver 0.0.0.0:8000 & jupyter lab --allow-root EXPOSE 8888 EXPOSE 8000docker/jupyter/jupyter_notebook_config.py
c.NotebookApp.ip = '0.0.0.0' c.NotebookApp.notebook_dir = './notebook' c.NotebookApp.open_browser = False c.NotebookApp.token = ''起動
$ cd python-jupyter-docker/docker/main $ docker-compose build $ cd python-jupyter-docker/docker/jupyter $ docker-compose up -dアクセス
jupyter
http://127.0.0.1:8888
django
http://127.0.0.1:8000終わりに
既存のアプリにjupyterをくっつけるみたいな使い方をしました。
dev環境にjupyterを置くことで既存のアプリのライブラリを使いつつ使い捨てのコードを作成できるのではと思います。
- 投稿日:2020-07-06T22:41:53+09:00
PG::ObjectInUse: ERROR: database "myapp_development" is being accessed by other users
ポートフォリオ作成中
db/seeds.rbUser.create!(name: "テスト 太郎", email: "test@example.com", password: "foobar", password_confirmation: "foobar" ) 99.times do |n| name = Faker::Name.name email = "test#{n}@example.com" password = "foobar" User.create!(name: name, email: email, password: password, password_confirmation: password) endページネーションを実装していくため
テスト用アカウントを作成しようとすると、
こんなエラーが出ました。$ rails db:migrate:resetを実行すると
PG::ObjectInUse: ERROR: database "myapp_development" is being accessed by other users DETAIL: There is 1 other session using the database.「myapp_debelopment」データベースは、他のセッションで使われているとのこと。
データベースはこのような構成
config/database.ymldefault: &default adapter: postgresql encoding: unicode host: db username: postgres password: password pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_test色々と調べていく中で
下記を参考にして、データベースを一度削除して
作成し直すことにしました。
https://stackoverflow.com/questions/46451472/unable-to-make-rake-dbdrop-work-in-development-with-rails-5-1-4$ docker exec -it (コンテナ名) /bin/bashコンテナの中に入ります。
$ rails db:drop Dropped database 'myapp_development' Dropped database 'myapp_test'$ rails db:create $ rails db:migrate == 20200704040832 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0426s == 20200704040832 CreateUsers: migrated (0.0432s) ============================= == 20200704043311 AddIndexToUsersEmail: migrating ============================= -- add_index(:users, :email, {:unique=>true}) -> 0.0303s == 20200704043311 AddIndexToUsersEmail: migrated (0.0307s) ==================== == 20200704043511 AddPasswordDigestToUsers: migrating ========================= -- add_column(:users, :password_digest, :string) -> 0.0026s == 20200704043511 AddPasswordDigestToUsers: migrated (0.0031s) ================ == 20200705055948 AddRememberDigestToUsers: migrating ========================= -- add_column(:users, :remember_digest, :string) -> 0.0025s == 20200705055948 AddRememberDigestToUsers: migrated (0.0027s) ================ $ rails db:seed$ exitこれで、無事動きました!
おそらく、
最初にデータベースを作成した際に
コンテナに入って作成するのではなく、
ローカル環境から下記コマンドで実行したから?
作成したユーザーが異なってしまったのではないかと。。$ docekr-compose run web rails db:create
- 投稿日:2020-07-06T22:37:11+09:00
Azure VMをVS Code Remote Containers開発環境として使う
はじめに
最近はもっぱらVS Code Remote Containersを開発環境として使っています。が、のっぴきならない事情でローカルマシンにDockerが入れられず使えない、という場合もあると思います1。
そういう場合に、WindowsのAzure Virtual MachinesにHyper-VとDocker Desktop for Windowsをインストールし、開発環境として使ってみたいと思います。
構成は以下の通りです。ローカルPCはRDP接続元としてしか使わず、Azure上のWindows 10上ですべて開発をする構成です。
※開発環境自体はリモートにあったとしても、VSCode Remote Containersを使用するにはローカルにもDockerを入れる必要があります
Azure VMでDockerは動くのか?
Azureの一部のVMは、「ネストされた仮想化」をサポートしています。
これにより、Azure VM上でHyper-Vを有効化しDocker Desktop for Windowsを動かすことが可能です。参考:Nested Virtualization in Azure | Azure Blog and Updates | Microsoft Azure
ちなみに、AWSはおそらく不可です。Hyper-Vを有効にできませんし、そもそもWindows 10のVMを作成できません。Windows ServerにはDocker Desktop for Windowsをインストールできないので、VS Code Remote Containersが使えません。
Windows10 VMの作成方法
Azureポータルから以下の順で選択していきます。
Windows 10のイメージを選択してください。
また、サイズは以下の***が付いているものから選択してください。
参考:Azure コンピューティング ユニットの概要 - Azure Virtual Machines | Microsoft Docs注意点
ネストされた仮想化未対応のVMでは、Docker Desktop for Windowsが以下のようなエラーを吐いて起動できません。
Docker.Core.HttpBadResponseException: Unhandled exception: シーケンスに要素が含まれていません対応VMは結構お高くつくので、私は毎日定時に自動でシャットダウン+グローバルIP固定設定にしています。
試してみる
作成したVMにVS CodeとDocker Desktop for Windowsをインストールし、諸々の設定を行います。
詳細は以下を参照お願いします。
参考:Developing inside a Container using Visual Studio Code Remote Development無事VS Codeでコンテナに入ることができました。
おわりに
この結論に至るまでに色々と試行錯誤したので記しました。VS Code Remote Containersは本当に最高なので使ってみてください。
そんなことない?あるんです。 ↩
- 投稿日:2020-07-06T22:27:35+09:00
jupyterをdocker-composeで起動1
はじめに
今回は、jupyterのdockerイメージ(scipy-notebook)をベースにjupyter pluginも入れて、
docker-composeを使ってイメージの作成と起動しました。ソースは github にあげてあります。
ファイル
docker-compose.yml
docker-compose.ymlversion: '3' services: jupyter: build: context: . environment: JUPYTER_ENABLE_LAB: "yes" ports: - "8888:8888" volumes: - ./.jupyter:/home/jovyan/.jupyter - ./notebook:/home/jovyan/notebookDockerfile
# jupyter lab : 2.1.3 FROM jupyter/scipy-notebook:54462805efcb RUN jupyter labextension install \ @lckr/jupyterlab_variableinspector \ @krassowski/jupyterlab-lsp \ @axlair/jupyterlab_vim # pd.read_html RUN pip install lxml html5lib beautifulsoup4 # code completion RUN pip install jupyter-lsp python-language-server[all] RUN jupyter lab buildjupyter_notebook_config.py
jupyter_notebook_config.pyc.NotebookApp.ip = '0.0.0.0' c.NotebookApp.notebook_dir = './notebook' c.NotebookApp.open_browser = False c.NotebookApp.token = ''アクセス
終わりに
jupyterですぐ試してみたい場合などで便利でした。
jupyter plugin周りは全般にメンテナンスがされていない感じがして、
かなり地雷がありました。次回はdockerのイメージをpythonにしてjupyter lab環境を構築していきたいと思います。
- 投稿日:2020-07-06T19:32:37+09:00
Docker上で、vcgencmdを使う
raspberry Piのクロックや電圧などを取得できるコマンド
vcgencmd
をDocker上で使用する方法を解説します。Dockerのイメージはresin/rpi-raspbianを使用します。
以下のコマンドでDockerを立ち上げます。docker run -it --device /dev/vchiq--rm resin/rpi-raspbian /bin/bash立ち上げ後のコンテナ内に、
vcgencmd
コマンドがないため、以下のコマンドでインストールをします。apt-get update && apt-get install libraspberrypi-bin -y \ --no-install-recommends && apt-get clean && rm -rf /var/lib/apt/lists/*後は、
vcgencmd measure_temp
コマンドでコンテナ上で、
RaspberryPi本体上の温度センサー情報を得ることができることを確認してください。上記に気を付けてDockerfileを作れば、繰り返す必要がなくなります。
参考
vcgencmd
https://www.raspberrypi.org/documentation/raspbian/applications/vcgencmd.md
Docker Raspberry Pi Status
https://github.com/toschoch/docker-rpi-status
- 投稿日:2020-07-06T19:09:53+09:00
WindowsでDockerにてmongoDB環境を構築する囚われた人の備忘録
概要
以下のようにやったら、mongoDBが動かなかったため、その備忘録。
version: "2" services: mongo: image: mongo restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: root volumes: - ./db:/data/db mongo-express: image: mongo-express restart: always ports: - 8081:8081 environment: ME_CONFIG_MONGODB_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: root対策
ボリュームをホストであるWIndowsのディレクトリにマウントしようとしていたのが問題だったようです。ボリュームを仮想環境側のボリュームにマウントしたら上手くいきました。そこからまたマウントしたらホスト側にマウントしたらいいんですかね。そこら辺は試してないので、分からないですが。
version: "2" services: mongo: image: mongo restart: always environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: root volumes: - mongodata:/data/db # ここに注目 mongo-express: image: mongo-express restart: always ports: - 8081:8081 environment: ME_CONFIG_MONGODB_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: root volumes: # ここに注目 mongodata:参考
- Windows mounting /data/db:https://github.com/docker-library/mongo/issues/74
- 投稿日:2020-07-06T18:08:06+09:00
LAMP+CakePHP3開発環境をVSCodeRemote+Dockerで構築② -VSCodeRemote編-
LAMP+CakePHP3開発環境をVSCodeRemote+Dockerで構築① -Docker編-からの続きです。
VSCodeでPHPの開発をするにあたり、XDebugやPHP Intellisenseなどの拡張を入れようとするとVSCodeのインストールされている自PCにもPHPをインストールする必要がありますが、VSCode Remote Developmentを利用するとDockerのコンテナ内で全て完結できました。
導入の際に問題が起きてかなりはまってしまったので、その際の対応を記載しています。
完成した環境はGitHubにアップロードしてあります。
VSCode Remote Developmentの導入
Docker関連のファイルは前回作成したものをそのまま使用しています。
以下の記事を参考にして導入してみます。
Visual Studio CodeのRemote DevelopmentとDockerで快適な開発環境をゲットすると、コンテナの起動とVSCodeからコンテナへの接続は上手くいきます。
が、ブラウザからhttp://localhost:8093/ へアクセスすると「ERR_EMPTY_RESPONSE」と表示され接続できません。
VSCodeRemoteをコンテナに接続するとコンテナ内のサーバーへアクセスできなくなる問題
調査
ターミナルcurl http://localhost:8093 エラー curl: (52) Empty reply from server
コンテナ内で以下のコマンドを実行すると
ターミナルcurl http://localhost:80 エラー curl: (7) Failed to connect to ::1: Cannot assign requested address
となりこちらもエラーが出ます。
localhostを127.0.0.1に置き換えても同様です。以下の記事達を参考にし、どうもコンテナは起動しているがサーバーが起動していない状態にありそうだという事がわかりますが、解決しません。
Dockerコンテナで起動したサーバにアクセスできないときの確認と対処方法
docker上のアプリにlocalhostでアクセスしたらERR_EMPTY_RESPONSEが出る
VSCodeRemoteで接続した際にのみアクセスできなくなるので、そちらに原因がありそうだと当たりをつけて公式ドキュメントを読んでみます。
Visual Studio Code | Developing inside a Container
公式ドキュメントを読んでみて大事そうなところ
・VSCodeRemoteでコンテナに接続した場合、コンテナを開いたrootディレクトリに対してworkspaceという名前のvolumeが作られる。
・rootディレクトリは設定で変更可能・rootディレクトリ直下にdevcontainerフォルダが作られる。
フォルダ構成は以下の様な形
rootディレクトリdevcontainer - devcontainer.json - docker-compose.yml(VSCodeによって生成された、設定上書き用ファイル) ... 他のファイルやフォルダ達 docker-compose.yml(コンテナ生成の元になっている自分で用意したファイル)・ このうちdevcontainer.jsonには以下の設定項目があり、上から指定されている順にdocker-compose.ymlが読み込まれ、上書きされていく。
devcontainer.json"dockerComposeFile": [ "../docker-compose.yml", "docker-compose.yml" ],以上を踏まえて問題となっていた箇所
自動生成されたdocker-compose.ymlには、以下の設定がされています。
これは、コンテナがすぐに終了してしまわないようにするため設定されている様です。docker-compose.yml(VSCodeによって生成された、設定上書き用ファイル)# Overrides default command so things don't shut down after the process ends. command: /bin/sh -c "while sleep 1000; do :; done"また、用意してあるDockerFileでは、サーバーを自動起動するために以下のコマンドを実行しています。
docker/app/DockerFileCMD ["/usr/sbin/httpd","-D","FOREGROUND"]Docker側の仕様として、docker-compose.ymlにcommandが記載してあるとDockerFileで記載したCMDを上書きするらしく、このCMDが実行されていないためサーバーが立ち上がらずに問題が起きていたようです。
以下の様に修正したところ、問題なくコンテナのサーバーにアクセスできました。
docker-compose.yml(VSCodeによって生成された、設定上書き用ファイル)# Overrides default command so things don't shut down after the process ends. command: /bin/sh -c "/usr/sbin/httpd -DFOREGROUND; while sleep 1000; do :; done"
- 投稿日:2020-07-06T17:58:03+09:00
LAMP+CakePHP3開発環境をVSCodeRemote+Dockerで構築① -Docker編-
学習の備忘録です。
自身の学習用に使用するLAMP+CakePHP3環境をDockerで構築しました。
PCが変わっても環境をそのまま移行できると作った環境が資産となり頭もPCもスッキリするので、その後VSCodeのRemote Developmentを組み合わせていい感じの開発環境を作りました。その際のまとめと詰まった部分などを記載しています。
全2部です
LAMP+CakePHP3開発環境をVSCodeRemote+Dockerで構築① -Docker編-(本記事)
LAMP+CakePHP3開発環境をVSCodeRemote+Dockerで構築② -VSCodeRemote編-事前準備
Dockerについての基礎知識を仕入れる
こちらの記事(https://girigiribauer.com/tech/20180205/) を参考にしてDockerを利用したLAMP環境の構築をとりあえずやってみました。
Linux Apache MySQL PHPに関してもほぼ知識がない状態だったので、必要となった部分を都度調べながら作業しました。
環境構築
何となくDockerを使えるようになった気になったところで、LAMP+CakePHP3環境を構築してみます。
PCはMacです。以下は主にこちらの記事(https://qiita.com/km42428/items/df1d0a1eefddcf771dfa) を参考にしながら作業を進めました。
構築する環境の詳細
- CentOS 7
- Apache 2.4
- MySQL 5.7
- PHP 7.4
- CakePHP 3.8
参考元の記事ではサーバーソフトにApacheではなくNginx+phpfpmを利用していたので、違いについて調べてみると、同時大量アクセスが想定される場合等にはNginx+phpfpmの構成が有利なようです。
参考:ApacheとNginxについて比較今回は不要なためApacheを利用してみることにしました。
docker-composeファイルの用意
ファイルやフォルダ構成については以下にアップロードしてあります。
GitHub 【学習用】Dockerでcakephp3.8のチュートリアル環境を構築docker-compose.ymlversion: "3" services: app: build: context: "docker/app/" ports: - 8093:80 volumes: - "./data/sample_app:/sample_app" # cakePHPのインストールフォルダを永続化しています - "./docker/app/httpd.conf:/etc/httpd/conf/httpd.conf" # Apache設定ファイルのhttpd.confを永続化しています depends_on: - mysql mysql: build: context: "docker/mysql/" environment: - MYSQL_DATABASE=sampledb - MYSQL_HOST=localhost - MYSQL_USER=root - MYSQL_ROOT_PASSWORD=mypassword volumes: - "./data/db:/var/lib/mysql" # mysqlのデータベースをを永続化しています phpmyadmin: image: phpmyadmin/phpmyadmin:latest ports: - 8094:80 environment: - PMA_HOST=mysql - PMA_USER=root - PMA_PASSWORD=mypassword depends_on: - mysql参考元の記事ではCakePHPプロジェクトのコンテナとしてhostコンテナを作成していましたが、こちらではApacheのモジュールとしてPHPをインストールしているため、appコンテナがApache+PHP(モジュール)+CakePHPのコンテナとなります。
PHPのモジュール版・CGI版についての参考 (https://qiita.com/kotarella1110/items/634f6fafeb33ae0f51dc)
データの保存について
コンテナはおそらく頻繁に終了させると思われるので、Volumeを設定して必要なデータが破棄されないで自PC(ホスト)に保存される形にしています。
その他のファイルの用意
httpd.confのDocumentRootをCakePHPの公開フォルダに設定していますが、このままだとCakePHPインストール前のコンテナ起動時にフォルダが無い為コンテナが起動しません。
その為、CakePHPインストール前のみ、DocumentRoot及びDirectoryを"/var/www/html"に切り替えてください。
インストール後に元に戻してブラウザでhttp://localhost:8093/ にアクセスするとCakePHPの画面が表示されるはずです。httpd.conf# DocumentRoot "/var/www/html" DocumentRoot "/sample_app/webroot" # # Relax access to content within /var/www. # # <Directory "/var/www"> <Directory "/sample_app/webroot"> AllowOverride None # Allow open access: Require all granted </Directory> # Further relax access to the default document root: # <Directory "/var/www/html"> <Directory "/sample_app/webroot">CakePHP3のインストール
公式サイトのインストール手順に従い、Composerをインストールします。
以下のコマンドでappコンテナに入り、
docker exec -it tutorial_app_1 /bin/bashComposerのインストールコマンドを実行します。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === 'e0012edf3e80b6978849f5eff0d4b4e4c79ff1609dd1e613307e16318854d24ae64f26d17af3ef0bf7cfb710ca74755a') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"公式手順に従い、インストールを進めます。
mv composer.phar /usr/local/bin/composerphp composer.phar create-project --prefer-dist cakephp/app:^3.8 sample_appこのままだとcomposer.pharなんてないよ?と言われたので以下に直して実行します。
composer create-project --prefer-dist cakephp/app:^3.8 sample_appこれで完了! なはずですが、エラーが出たので対応します・・・。
GitHubのデータは修正済みのものです。エラー対応
*エラー1 zip unzipの不備
*エラー1Failed to download cakephp/app from dist: The zip extension and unzip command are both missing, skipping.zip unzipが必要なようなので、インストール用コマンドを追加しました。
*エラー2 php intl拡張モジュールの不備
*エラー2Problem 1 - cakephp/cakephp 3.8.9 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.8 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.7 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.6 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.5 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.4 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.3 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.2 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.10 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.1 requires ext-intl * -> the requested PHP extension intl is missing from your system. - cakephp/cakephp 3.8.0 requires ext-intl * -> the requested PHP extension intl is missing from your system. - Installation request for cakephp/cakephp 3.8.* -> satisfiable by cakephp/cakephp[3.8.0, 3.8.1, 3.8.10, 3.8.2, 3.8.3, 3.8.4, 3.8.5, 3.8.6, 3.8.7, 3.8.8, 3.8.9]. To enable extensions, verify that they are enabled in your .ini files: - /etc/php.ini - /etc/php.d/20-bz2.ini - /etc/php.d/20-calendar.ini - /etc/php.d/20-ctype.ini - /etc/php.d/20-curl.ini - /etc/php.d/20-dom.ini - /etc/php.d/20-exif.ini - /etc/php.d/20-fileinfo.ini - /etc/php.d/20-ftp.ini - /etc/php.d/20-gd.ini - /etc/php.d/20-gettext.ini - /etc/php.d/20-iconv.ini - /etc/php.d/20-json.ini - /etc/php.d/20-mbstring.ini - /etc/php.d/20-mysqlnd.ini - /etc/php.d/20-pdo.ini - /etc/php.d/20-phar.ini - /etc/php.d/20-simplexml.ini - /etc/php.d/20-sockets.ini - /etc/php.d/20-sodium.ini - /etc/php.d/20-sqlite3.ini - /etc/php.d/20-tokenizer.ini - /etc/php.d/20-xml.ini - /etc/php.d/20-xmlwriter.ini - /etc/php.d/20-xsl.ini - /etc/php.d/30-mysqli.ini - /etc/php.d/30-pdo_mysql.ini - /etc/php.d/30-pdo_sqlite.ini - /etc/php.d/30-xmlreader.ini - /etc/php.d/30-xmlrpc.ini - /etc/php.d/40-apcu.ini You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.cakephp3ではphpのintl拡張が必要とインストールマニュアルに記載があったのですが、phpの拡張モジュールについて理解できていなかった為インストール方法が分からずとりあえず進めましたが案の定エラーになりました。
PHP intl拡張モジュールのインストール
PHPマニュアル|intlインストール手順を見てもちょっとよく分からなかったので色々調べたところ、今回はremiリポジトリからphpをインストールしているので、同じくremiリポジトリからphp-intlをインストールすればいいだけでした。
なお拡張モジュールを有効化するにはインストールと共にphp.iniファイルに以下の記載が必要です。インストール後デフォルトで有効化されていました。
extension=モジュール名 # intlモジュールの場合 extension=intl # LinuxOSの場合モジュールファイルの拡張子が.soになるので多くの場合以下のように記載されていますが、インストール後のデフォルトでは拡張子無しになっていて、拡張子無しのまま動作しました。 extension=intl.soiniファイルについては以下のページが参考になりました。
【PHP】php.iniには設定を書かないようにしよう!
- 投稿日:2020-07-06T17:57:07+09:00
Keycloak コンテナがめっちゃ便利だったのでついでに https 化もした
関連記事
【Keycloak】Apache の VirtualHost で分けられた複数のサイトをまとめてシングルサインオンしよう
https://qiita.com/thirdpenguin/items/1136c755560eea51b5b1
公式にリリースされているコンテナイメージによる Keycloak 導入があまりにも簡単すぎて感動したので、ついでに Keycloak コンテナの https 化もやってみました。
github リポジトリにやり方がありました。
https://github.com/keycloak/keycloak-containers/tree/master/server#setting-up-tlsssl上記を要約すると、「
/etc/x509/https
に 秘密鍵 tls.key と 証明書 tls.crt をくれると後はよろしくやるよ!でもボリュームマウントで置くとファイルのオーナーが root になるから、適切な所有者が読み取り可能になるようイメージを直してね!」とのことです。ボリュームマウントによるオーナーの変更は、 root 以外のユーザで Keycloak を動かす時には留意する必要がありそうですね。ではやっていきましょう。 1 章では Keycloak の導入から始めるので、もう Keycloak コンテナの準備が終わっている方は 2 章からどうぞ。
バージョン情報
- Keycloak サーバ (IdP)
- OS: CentOS8 (8.1.1911)
- podman: 1.6.4
- podman-compose: 0.1.7.dev0
1. Keycloak コンテナの準備
公式 github リポジトリ keycloak-containers の docker-compose ファイルのサンプルを podman-compose に流用して、Keycloak コンテナと、連携する DB となる PostgreSQL コンテナを一気に建てます。
関連記事と同じ作業内容なので、もう終わっている方は読み飛ばしてしまって結構です。
- podman のインストール
# dnf -y install podman
2. podman-compose のインストール
podman-compose のインストールに pip3 が必要なので、 pip3 を同梱している python3 系列をインストールもします。# dnf install -y python36 # pip3 install https://github.com/containers/podman-compose/archive/devel.tar.gz
3. git リポジトリ keycloak-containers をクローン
適当なディレクトリをローカルリポジトリにして、keycloak-containers リポジトリを引っ張ってきます。# mkdir localrepo # cd localrepo # git init # git clone https://github.com/keycloak/keycloak-containers.git # cd keycloak-containers # ls CONTRIBUTING.md License.html README.md adapter-wildfly docker-compose-examples docs gatekeeper keycloak-init-container openshift-examples server set-version.sh
2. HTTPS 化作業
- 証明書の設置
用意しておいた秘密鍵と証明書を任意のディレクトリに配置します。
参考記事に自己署名書の取得手順があります。# mkdir certs # cp /path/to/your.key certs/tls.key # cp /path/to/your.crt certs/tls.crt
2. keycloak-postgres.yml の編集
さて、Keycloak コンテナの https 化のためには……
所定のディレクトリ/etc/x509/https
に鍵と証明書を適切なパーミッションで設置する必要があるのでした。
yml へ1行追記するだけで楽なので今回はバインドマウントでやってみます。あとはポートフォワーディングの設定を変える必要もあるはずです。
http は 8080 で listen してましたが https はまた別のポートになるでしょう。
しかしはて、 https の listen ポートは一体どこへ。このイメージの dockerfile に手がかりがあるのでは?github.com/keycloak/keycloak-containers/blob/master/server/Dockerfileより抜粋EXPOSE 8080 EXPOSE 8443 ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ] CMD ["-b", "0.0.0.0"]
EXPOSE 8443
の記述があるのでおそらくこれっぽいです。
念のため起動ログを漁って裏も取ったのですが、その話は後にして、とりあえず yml ファイルを編集します。# cd docker-compose-examples # vi keycloak-postgres.ymlkeycloak-postgres.ymlversion: '3' volumes: postgres_data: driver: local services: postgres: image: postgres volumes: - postgres_data:/var/lib/postgresql/data environment: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: password keycloak: image: quay.io/keycloak/keycloak:latest volumes: # ←追加 - /<証明書の絶対パス>:/etc/x509/https # ←追加 environment: DB_VENDOR: POSTGRES DB_ADDR: postgres DB_DATABASE: keycloak DB_USER: keycloak DB_SCHEMA: public DB_PASSWORD: password KEYCLOAK_USER: admin KEYCLOAK_PASSWORD: Pa55w0rd # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it. #JDBC_PARAMS: "ssl=true" ports: - 8080:8080 - 8443:8443 # ←追加 depends_on: - postgresKeycloak コンテナにバインドマウントするボリュームの追加と、ポート 8443 のフォワーディング設定のため3行ファイルに書き加えました。
3. サービス起動鍵と証明書の設置、そして yml ファイルの編集が終わったらいよいよ起動です。
# cd docker-compose-examples # podman-compose -f keycloak-postgres.yml up -d using podman version: podman version 1.6.4 podman pod create --name=docker-compose-examples --share net -p 8443:8443 -p 8080:8080 96f023c108904557f7c953cc1896271bbfec1e9526583d9300d47cde3b1889d5 0 podman volume inspect docker-compose-examples_postgres_data || podman volume create docker-compose-examples_postgres_data podman run --name=docker-compose-examples_postgres_1 -d --pod=docker-compose-examples --label io.podman.compose.config-hash=123 --label io.podman.compose.project=docker-compose-examples --label io.podman.compose.version=0.0.1 --label com.docker.compose.container-number=1 --label com.docker.compose.service=postgres -e POSTGRES_DB=keycloak -e POSTGRES_USER=keycloak -e POSTGRES_PASSWORD=password -v docker-compose-examples_postgres_data:/var/lib/postgresql/data --add-host postgres:127.0.0.1 --add-host docker-compose-examples_postgres_1:127.0.0.1 --add-host keycloak:127.0.0.1 --add-host docker-compose-examples_keycloak_1:127.0.0.1 postgres 046eec4c0a2619de953e35bd2940a00f43ac95ff87df955a55c07fe831492a23 0 podman run --name=docker-compose-examples_keycloak_1 -d --pod=docker-compose-examples --label io.podman.compose.config-hash=123 --label io.podman.compose.project=docker-compose-examples --label io.podman.compose.version=0.0.1 --label com.docker.compose.container-number=1 --label com.docker.compose.service=keycloak -e DB_VENDOR=POSTGRES -e DB_ADDR=postgres -e DB_DATABASE=keycloak -e DB_USER=keycloak -e DB_SCHEMA=public -e DB_PASSWORD=password -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=Pa55w0rd --add-host postgres:127.0.0.1 --add-host docker-compose-examples_postgres_1:127.0.0.1 --add-host keycloak:127.0.0.1 --add-host docker-compose-examples_keycloak_1:127.0.0.1 quay.io/keycloak/keycloak:latest 8241eb401a36880c0d3850a2230ae7c15510b9eedfe20478c6357972c597da6a 0ポッド作成、ボリューム作成、コンテナ作成のコマンドが実行され、正常に終われば上記のように終了コード 0 が 3 回返ります。
失敗したら、podman-compose -f keycloak-postgres.yml down
で一度ポッドとコンテナを削除し、問題を修正した後にもう一度実行してください。3. 接続テスト
ブラウザから https://:8443 に接続して Keycloak の管理コンソールに接続できれば作業終了です!おつかれさまでした。自己証明書だとこの画面にたどり着く前に証明書関連のエラーが出ると思います。
余談
本当に 8443 を https の listen ポートとして使用して良かったのだろうか、ということで Keycloak コンテナの起動ログを漁ってみました。
inspect コマンドの LogPath 行を見て、ログファイルの保存場所を確認して……
# podman container inspect docker-compose-examples_keycloak_1 | grep LogPath "LogPath": "/var/lib/containers/storage/overlay-containers/b9e422a609e4def892dc6d64688834585fb43a98ad63b3fa1ce9126cc3792033/userdata/ctr.log",それっぽいワードで検索してみます。
# grep HTTP /var/lib/containers/storage/overlay-containers/b9e422a609e4def892dc6d64688834585fb43a98ad63b3fa1ce9126cc3792033/userdata/ctr.log 2020-07-01T01:46:56.731772928-04:00 stdout F 05:46:56,725 INFO [org.wildfly.extension.undertow] (MSC service thread 1-4) WFLYUT0006: Undertow HTTP listener default listening on 0.0.0.0:8080 2020-07-01T01:46:57.459785836-04:00 stdout F 05:46:57,458 INFO [org.wildfly.extension.undertow] (MSC service thread 1-2) WFLYUT0006: Undertow HTTPS listener https listening on 0.0.0.0:8443Undertow という何かが 8443 を listen してますね。Undertow ってなんでしょう?
Undertow is a flexible performant web server written in java, providing both blocking and non-blocking API’s based on NIO.
http://undertow.io/なるほど、どうやら Java EE アプリケーションサーバである Wildfly や Jboss の拡張機能として動作する web サーバみたいです。コンテナ構築だと特に意識することはありませんでしたが、Keycloak は Wildfly 上で動作する Java アプリケーションです。ブラウザから指定の IP:Port へ接続したときに
/auth
に自動で飛ばされていたのは Undertow の働きだったわけですね。参考
自己署名証明書の作成の際に参考にさせていただきました。ありがとうございます。
オレだよオレオレ認証局で証明書つくる
https://qiita.com/ll_kuma_ll/items/13c962a6a74874af39c6
Apache httpdで作るHTTPSサーバ
https://qiita.com/jinnai73/items/638dcc1434d47b12e6ba
- 投稿日:2020-07-06T16:51:19+09:00
初めてのKubernetes - 2.Kubernetesのインストール
はじめに
それでは、前回構築した Raspberry Pi 3 Model B にOS、Kubernetesをインストールします。ただ、はじめに一言謝らないといけないことがあります。
Raspberry Pi 3 Model B でKubernetesのコントロールプレーンノードを動かしてみたのですが、性能不足のためかうまく動きませんでした。
ですので、Raspberry Pi 3 Model B x 4台をワーカーノードにして、Raspberry Pi 4 Model B(4GB) x 1台をコントロールプレーンノードにしました。こんな感じで1台追加しました。
このRaspberry Pi 4 Model Bをコントロールプレーンノードにすることにします。OSのインストール
Raspberry Pi だとRaspberry Pi OS(以前はRaspbian)を最初に考えますが、kubeadmのインストールを見てみると、Raspberry Pi OSはサポートされていません。したがって、今回はUbuntu 20.04-LTS(64bit)をインストールすることにします。
実は、Raspberry Pi OSでもKubernetesをインストールできますし、Kubernetesも動作するのですが、トラブルに遭遇したときに同じような経験をした人が少なくて、面倒なことになりそうなので、Ubuntuにします。
Install Ubuntu Server on a Raspberry Pi 2,3 or 4にRaspberry Piのイメージがあるので、
Ubuntu 20.04 LTS(64-bit) for Raspbeery Pi 3
をダウンロードします。SDカードの準備
OSイメージのダウンロードが完了したら、解凍しmicroSDカードに書き込みます。
~/Downloads ❯❯❯ xz -dv ubuntu-20.04-preinstalled-server-arm64+raspi.img.xz ubuntu-20.04-preinstalled-server-arm64+raspi.img.xz (1/1) 100 % 667.0 MiB / 3,054.4 MiB = 0.218 92 MiB/s 0:33OSイメージの書き込みには、こちらにもある通りに、Raspberry Pi imager というツールがあるそうですが、私のノートPCはUbuntuなので、
dd
コマンドでも書き込めます。~/Downloads ❯❯❯ sudo dd if=ubuntu-20.04-preinstalled-server-arm64+raspi.img of=/dev/mmcblk0 status=progress 3201147392 bytes (3.2 GB, 3.0 GiB) copied, 622 s, 5.1 MB/s 6255474+0 records in 6255474+0 records out 3202802688 bytes (3.2 GB, 3.0 GiB) copied, 627.603 s, 5.1 MB/sこの作業をmicroSDカード5枚分(ControlPlane x 1, Node x 4)行います。
設定
ここから設定を行っていくわけですが、ディスプレイ+キーボード+マウスを5台のRaspberry Piに接続して作業するのは、少々面倒です。したがって、それら周辺機器を接続せずに設定していきます。
実は、その方法はHow to install Ubuntu on your Raspberry Piに記載されているので、簡単です。また、こちらも参考になります。OSイメージを書き込んだmicroSDカードを抜き差しすると、以下のパーティションが自動でマウントされます。
~/Downloads ❯❯❯ df -k ... /dev/mmcblk0p2 2754000 1813920 780472 70% /media/$USER/writable /dev/mmcblk0p1 258095 62017 196079 25% /media/$USER/system-bootIPアドレスの設定をします。K8sクラスタのIPアドレスは以下のように設定します。
- hostname: k8s-master,ip address: 192.168.0.19/24
- hostname: k8s-node0, ip address: 192.168.0.10/24
- hostname: k8s-node1, ip address: 192.168.0.11/24
- hostname: k8s-node2, ip address: 192.168.0.12/24
- hostname: k8s-node3, ip address: 192.168.0.13/24
~/Downloads ❯❯❯ cd /media/$USER/system-boot /m/n/system-boot ❯❯❯ vim network-configversion: 2 ethernets: eth0: dhcp4: no addresses: [192.168.0.10/24] gateway4: 192.168.0.1 nameservers: addresses: [192.168.0.1,8.8.8.8] optional: true次にホスト名とユーザ・パスワードの設定をします。
/m/n/system-boot ❯❯❯ vim user-datafqdn: k8s-node0 chpasswd: expire: false list: - ubuntu:ubuntu次にRaspberry Pi 4 Ubuntu 19.10 cannot enable cgroup memory at boostrap
にあるようにDocker/K8sに必要なcgroup memoryを有効化します。~ ❯❯❯ vim /media/$USER/system-boot/cmdline.txt
-net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc +net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 rootwait fixrtc以上の設定ができたら、microSDカードをアンマウントして、Raspberry Pi に挿入します。
~ ❯❯❯ umount /media/naomori/system-boot ~ ❯❯❯ umount /media/naomori/writable同様に、K8s Cluster の 5台分(ControlPlane x 1, Node x 4)の設定をします。
ssh でログイン
Raspberry Piの電源を入れたらsshでログイン(user:ubuntu,pass:ubuntu)します。あと、SSHの秘密鍵のパスフレーズを無しにした公開鍵をK8s Cluster すべてにscpして、ログインしやすくしておきます。
~/Downloads ❯❯❯ ssh ubuntu@192.168.0.10 ~/Downloads ❯❯❯ scp ~/.ssh/id_rsa.pub ubuntu@192.168.0.10:ubuntu@k8s-node0:~$ cat id_rsa.pub >> .ssh/authorized_keys ubuntu@k8s-node0:~$ rm -f id_rsa.pub最初にすること
ubuntu@k8s-node0:~$ sudo apt update && sudo apt upgrade -yあと、簡単にそれぞれのノードにアクセスできるように、
/etc/hosts
にエントリを追加します。ubuntu@k8s-node0:~$ sudo vim /etc/hosts# K8s 192.168.0.19 k8s-master 192.168.0.10 k8s-node0 192.168.0.11 k8s-node1 192.168.0.12 k8s-node2 192.168.0.13 k8s-node3時間の設定もしておきます。
ubuntu@k8s-node0:~$ sudo timedatectl set-timezone Asia/Tokyo ubuntu@k8s-node0:~$ timedatectl Local time: Mon 2020-07-06 22:13:48 JST Universal time: Mon 2020-07-06 13:13:48 UTC RTC time: n/a Time zone: Asia/Tokyo (JST, +0900) System clock synchronized: yes NTP service: active RTC in local TZ: noDockerのインストール
Install Docker Engine on Ubuntuを参考にDockerをインストールします。
ubuntu@k8s-node0:~$ sudo apt install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-commonubuntu@k8s-node0:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - OK ubuntu@k8s-node0:~$ sudo apt-key fingerprint 0EBFCD88 pub rsa4096 2017-02-22 [SCEA] 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 uid [ unknown] Docker Release (CE deb) <docker@docker.com> sub rsa4096 2017-02-22 [S]ubuntu@k8s-node0:~$ sudo add-apt-repository \ "deb [arch=arm64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"ubuntu@k8s-node0:~$ sudo apt updateここにしたがって、Dockerのバージョンを指定してインストールします。
ubuntu@k8s-node0:~$ sudo apt install -y \ containerd.io=1.2.13-2 \ docker-ce=5:19.03.11~3-0~ubuntu-$(lsb_release -cs) \ docker-ce-cli=5:19.03.11~3-0~ubuntu-$(lsb_release -cs)kubernetesとのバージョン依存の問題があるため、docker-ceのバージョンを現在のバージョンで固定化します。
ubuntu@k8s-node0:~$ sudo apt-mark hold containerd.io docker-ce docker-ce-cli containerd.io set on hold. docker-ce set on hold. docker-ce-cli set on hold.Dockerの設定を変更します。
ubuntu@k8s-node0:~$ sudo vim /etc/docker/daemon.json{ "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" }ubuntu@k8s-node0:~$ sudo mkdir -p /etc/systemd/system/docker.service.dubuntu@k8s-node0:~$ sudo systemctl daemon-reload ubuntu@k8s-node0:~$ sudo systemctl restart dockerubuntu@k8s-node0:~$ sudo usermod -aG docker ubuntuubuntu@k8s-node0:~$ sudo systemctl enable docker以上の作業を5台分(ControlPlane x 1, Node x 4)します。
Kubernetesのインストール
kubeadmのインストールを参考にインストールします。
iptablesがnftablesバックエンドを使用しないようにする
ubuntu@k8s-node0:~$ sudo apt-get install -y iptables arptables ebtablesubuntu@k8s-node0:~$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy ubuntu@k8s-node0:~$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy ubuntu@k8s-node0:~$ sudo update-alternatives --set arptables /usr/sbin/arptables-legacy ubuntu@k8s-node0:~$ sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacykubeadm のインストール
ubuntu@k8s-node0:~$ sudo apt-get update && sudo apt-get install -y apt-transport-https curl ubuntu@k8s-node0:~$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -ubuntu@k8s-node0:~$ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOFubuntu@k8s-node0:~$ sudo apt update ubuntu@k8s-node0:~$ sudo apt install -y kubelet kubeadm kubectl ubuntu@k8s-node0:~$ sudo apt-mark hold kubelet kubeadm kubectl kubelet set on hold. kubeadm set on hold. kubectl set on hold.swap 無効化
kubelet
が正常に動作するためには、swapは必ずオフである必要があるとのことなので、swapを無効化しておきます。ubuntu@k8s-node0:~$ sudo swapoff -a以上の作業を5台分(ControlPlane x 1, Node x 4)します。
kubeadmを使用したシングルコントロールプレーンクラスターの作成
kubeadmを使用したシングルコントロールプレーンクラスターの作成を参考に、Kubernetesクラスタを作成していきます。ネットワークには、kube-routerを使います。
コントロールプレーンノードの初期化
Masterノードで以下を実行します。
ubuntu@k8s-master:~$ sudo kubeadm init --pod-network-cidr=10.1.0.0/16Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: kubeadm join 192.168.0.19:6443 --token n1o5q2.coajyablijtdj1qb \ --discovery-token-ca-cert-hash sha256:5e0856b519d1f97db37fa1742c4613f99ef3f9eafd4a7bbbf5a5d270145c81bb完了すると、以下を実行しろと言われるので、その通りにします。
ubuntu@k8s-master:~$ mkdir -p $HOME/.kube ubuntu@k8s-master:~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config ubuntu@k8s-master:~$ sudo chown $(id -u):$(id -g) $HOME/.kube/configPodネットワークアドオンのインストール
Podネットワークとして、kube-routerを使うことにします。Deploying kube-router with kubeadmを参考にします。
ubuntu@k8s-master:~$ KUBECONFIG=$HOME/.kube/config kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yamlubuntu@k8s-master:~$ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-66bff467f8-j8snh 1/1 Running 0 19m coredns-66bff467f8-ntsxk 1/1 Running 0 19m etcd-k8s-master 1/1 Running 0 19m kube-apiserver-k8s-master 1/1 Running 0 19m kube-controller-manager-k8s-master 1/1 Running 0 19m kube-proxy-87dh9 1/1 Running 0 19m kube-router-xlw62 1/1 Running 0 17m kube-scheduler-k8s-master 1/1 Running 0 19mNodeのJoin
以下を
k8s-node[0-3]
で実行して、K8sクラスタに参加させます。ubuntu@k8s-node0:~$ sudo kubeadm join 192.168.0.19:6443 --token n1o5q2.coajyablijtdj1qb --discovery-token-ca-cert-hash sha256:5e0856b519d1f97db37fa1742c4613f99ef3f9eafd4a7bbbf5a5d270145c81bb ... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.全部が
Running
になっていることを確認します。ubuntu@k8s-master:~$ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-66bff467f8-j8snh 1/1 Running 0 45m coredns-66bff467f8-ntsxk 1/1 Running 0 45m etcd-k8s-master 1/1 Running 0 45m kube-apiserver-k8s-master 1/1 Running 0 45m kube-controller-manager-k8s-master 1/1 Running 0 45m kube-proxy-4skhr 1/1 Running 0 19m kube-proxy-5b7k9 1/1 Running 0 20m kube-proxy-87dh9 1/1 Running 0 45m kube-proxy-n6w99 1/1 Running 0 19m kube-proxy-tw7cr 1/1 Running 0 20m kube-router-65lkl 1/1 Running 0 20m kube-router-np5z5 1/1 Running 0 20m kube-router-ntzkv 1/1 Running 0 19m kube-router-xlw62 1/1 Running 0 43m kube-router-zjhd6 1/1 Running 0 19m kube-scheduler-k8s-master 1/1 Running 0 45mノードの稼働状況を確認します。
ubuntu@k8s-master:~$ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready master 33m v1.18.5 k8s-node0 Ready <none> 8m10s v1.18.5 k8s-node1 Ready <none> 7m34s v1.18.5 k8s-node2 Ready <none> 7m37s v1.18.5 k8s-node3 Ready <none> 7m32s v1.18.5
Rolesを設定します。
ubuntu@k8s-master:~$ kubectl label nodes k8s-node0 kubernetes.io/role=node ubuntu@k8s-master:~$ kubectl label nodes k8s-node1 kubernetes.io/role=node ubuntu@k8s-master:~$ kubectl label nodes k8s-node2 kubernetes.io/role=node ubuntu@k8s-master:~$ kubectl label nodes k8s-node3 kubernetes.io/role=nodeubuntu@k8s-master:~$ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 85m v1.18.5 k8s-node0 Ready node 60m v1.18.5 k8s-node1 Ready node 60m v1.18.5 k8s-node2 Ready node 60m v1.18.5 k8s-node3 Ready node 60m v1.18.5
ubuntu@k8s-master:~$ kubectl cluster-info Kubernetes master is running at https://192.168.0.19:6443 KubeDNS is running at https://192.168.0.19:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.別ノード(Ubuntu 20.04 LTS)から kubectl で制御します
別のノード(Ubuntu 20.04 LTS)から
kubectl
を実行することもできます。Install and Set Up kubectlを参考にkubectl
をインストールします。~ ❯❯❯ sudo snap install kubectl --classicmasterノードで出力をコピーします。
ubuntu@k8s-master:~$ kubectl config view --raw別ノードの
~/.kube/config
にペーストします。~ ❯❯❯ vim ~/.kube/configこれで別ノードからでも
kubectl
を実行できます。また kubectl completion でコマンドの補完ができます。まとめ
以上で、
Raspberry Pi 4 Model B x 1 をコントロールプレーンノードに、
Raspberry Pi 3 Model B x 4 をノードにした Kubernetes クラスタを構築できました。次回からは、15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まででKubernetesの勉強をしていきたいと思います。まだ全てを読んだわけではないですが、アーキテクチャやコンポーネントの説明が理解しやすくて、とても良い本だと思います。
"初めてのKubernetes"リスト
- 投稿日:2020-07-06T15:58:03+09:00
ubuntu20.04で docker pull したら 'Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: Temporary failure in name resolution' と言われた
びっくりするほど単純だったのですが、焦って色々ググってしまったので解決法をメモしておきます
docker loginこれだけですw
dockerhub にログインしないとそら動きませんわー!新しい物理マシンを立てた直後に忘れませんように...
- 投稿日:2020-07-06T15:46:01+09:00
Dockerでテストの時だけDBを立ち上げるスクリプト
概要
CIでテストの時だけ一時的にDBを立ち上げ、テストが終わったら削除したいってことありませんか?
Dockerを使ってそれを行うスクリプトです。スクリプト
#/bin/sh CONTAINER_ID=`docker run --rm -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=test_db -e TZ=Asia/Tokyo -d mysql:5.6 mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci` CONTAINER_IP=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER_ID` trap finally EXIT function finally { docker stop $CONTAINER_ID } until docker run --rm busybox nc -z -v -w30 $CONTAINER_IP 3306 do echo "Waiting for database connection..." sleep 3 done # ここでテストを実行する(DB名やパスワードなどは実行パラメータか環境変数で指定する)
- 投稿日:2020-07-06T14:55:53+09:00
[備忘録] [初心者] Docker Compose / Rails(公式doc.)について自分用補足#2 (docker-compose.yml)
はじめに
前回の投稿、
[備忘録] [初心者] Docker Compose / Rails(公式doc.)について自分用補足#1 (Dockerfile, entrypoint.sh)
に続き、Docker + Raislの公式チュートリアルの内容を丁寧に追って理解を試みる取り組みのアウトプットです。あくまで学習過程の私的なアウトプットなので、信頼性の高い情報は、各リンク先を参照していただければと思います。
本編
クィックスタート: Compose と Rails | Docker ドキュメント
上記のチュートリアルで扱われる、docker-compose.yml
の理解のためのメモです。
一部、深掘りのために、PostgreSQL
関連や、公式イメージのDockerfile
の内容も扱います。
docker-compose.yml
の概観理解に役立ったリンク例
- Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
- Docker Compose の概要 | Docker ドキュメント
- さわって理解するDocker入門 第4回 | オブジェクトの広場
- Compose file version3のリファレンス - Qiita
docker-compose.yml
docker-compose.ymlversion: '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: - dbversion:
使用するDocker Composeのバージョン
services:
#サービス設定リファレンス | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
アプリケーションを構成する各サービスのコンテナを設定します。
今回扱うチュートリアルでは、2つのサービスdb
,web
によってサービス全体を構成しています。db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: passwordweb: 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: - dbdb:
任意のサービスの名称として"db"が付けられています。
公式のサンプルでは、下位にimage
,volumes
,environment
の設定項目が続きます。image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: passwordimage:
image: postgres#image | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
コンテナを起動させるイメージの設定とあります。
今回は、PostgreSQLのDocker公式イメージを用います。
デフォルトのコンテナOSは、Debian:stretch、オプションでAlpineも選択できるようです。volumes:
volumes: - ./tmp/db:/var/lib/postgresql/data#volumes | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
マウントホストパスや名前つきボリュームを、サービスに対するサブオプションとして指定します。
まず、
マウント
という言葉もピンときていなかったのですが、下記の質疑がとても分かりやすかったです。
filesystems - understanding "mount" as a concept in the OS - Unix & Linux Stack Exchange
What is a mount point in Linux/Unix? - The Linux Juggernaut
特に、耕地の管理とディスクドライブの管理とのアナロジーを示した例え話はとても面白いと感じました。
各パーティション内のデータにアクセスするための"門"を設けることがマウントであるということに納得しました。また、ボリュームの概念が分かっていないので調べました。
ボリュームの利用 | Docker ドキュメントボリュームとは、Docker コンテナーにおいて生成され利用されるデータを、永続的に保持する目的で利用される仕組みです。
このように、システムを終了してもデータが消失しないような仕組みを設けることを永続化と呼ぶようです。(不揮発性メモリへの保存、回復可能にしておくなど)
永続性 - Wikipedia
What Is Persistent Data? - DZone Databaseでは、volumeに設定されている
./tmp/db:/var/lib/postgresql/data
とはどういうディレクトリなのでしょうか。
ボリュームの利用 | Docker ドキュメントには、設定の書式として、[SOURCE:]TARGET[:MODE]
という書式が適用されることが説明されています。
この書式にあてはめると、下記表の対応となります。
書式 記述例 意味 [SOURCE:] ./tmp/db: ホストのパスあるいはボリューム名 TARGET /var/lib/postgresql/data ボリュームがマウントされているコンテナのパス [:MODE] none 読み込み専用 ro
, 読み書き可能rw
. デフォルトは後者つまり、コンテナから見たとき、
/var/lib/postgresql/data
の中身として、ホストOS上の./tmp/db
を見ている状態になります。これはこういうものだと、割り切ってしまうのもひとつかもしれません。
ただ、もう少し自分の中で具体的根拠を伴った意味付けが欲しいと思いました。
/var/lib/postgresql/data
とは何かこのディレクトリについては、PostgreSQLのリファレンスに説明がありました。
データベースの物理的な格納 - PostgreSQL 8.0.4 文書
データベースクラスタで必要となる全てのデータは、クラスタのデータディレクトリ内に格納され、通常 PGDATA として参照されます。 (そのディレクトリを定義するために使用できる環境変数名です。) 通常の PGDATA の位置は /var/lib/pgsql/data です。
データベースクラスタはPostgreSQL独自の用語らしいです。
第18回 データベースクラスタ - OSS-DB道場
sql - What's a PostgreSQL "Cluster" and how do I create one? - Stack OverflowPostgreSQLでは、1つのサーバインスタンス上に複数のデータベースを構成することができ、PostgreSQLで言う"クラスタ"とは、そうした1つ以上のデータベースの集合体を含む共有ディレクトリを管理する仕組みであると解釈しました。
そして、それらに関わるデータが格納される場所がPGDATA
の環境変数で参照され、その保存先が通常では/var/lib/pgsql/data
に指定してあると。
/var/lib/
という階層の意味 : ファイルシステム階層標準 (FHS)他でもよく見る
/var/lib
についても意味を把握しておこうと思いました。
LinuxやUnix系のOSのディレクトリの階層は、ファイルシステム階層標準によって定められていることを知りました。
Filesystem Hierarchy Standard - Wikipedia(JP)Filesystem Hierarchy Standard(ファイルシステム・ヒエラルキー・スタンダード、FHS、ファイルシステム階層標準)は、Linuxを含むUNIX系オペレーティングシステムでの主なディレクトリとその内容を定めたものである。
2020-07現在の最新版はFHS 3.0で、下記リンクからHTMLやPDFなどの形式で閲覧することが出来ます。
/var
は、動的に変化する変数データファイルを格納するもので、、ネットワーク上で他のコンピュータと共有されないもの。
/var/lib
は、アプリケーションやシステムに関連する状態情報を保持。FHSの解説では、アプリケーションは
/var/lib
のサブディレクトリを使用しなければならない、とあるので、/var/lib/pgsql
はその規則に則ったPostgreSQL用のデータ格納先であることが伺えます。PostgreSQLの公式イメージにおける
/var/lib/postgresql/data
の扱いPostgreSQLの公式Dockerイメージの
Dockerfile
を見てみます。
下記の2行に/var/lib/postgresql/data
の記述を見つけました。(ディレクトリの生成も含めれば3行)
登場するDockerのENV
とVOLUME
の命令は、この親投稿では触れなかったものなので、調べてみます。https://github.com/docker-library/postgres/blob/master/Dockerfile-debian.template#L181
postgres/Dockerfile-debian.template#L181ENV PGDATA /var/lib/postgresql/data#ENV | Dockerfile リファレンス | Docker ドキュメント
環境変数
<key>
に<value>
という値を設定します。つまり環境変数
PGDATA
に/var/lib/postgresql/data
を設定しています。
PostgreSQLの公式リファレンスでは、pgsql
というデフォルトのディレクトリ名が、Dockerの公式イメージではpostgresql
となっています。https://github.com/docker-library/postgres/blob/master/Dockerfile-debian.template#L184
postgres/Dockerfile-debian.template#L184VOLUME /var/lib/postgresql/data#VOLUME | Dockerfile リファレンス | Docker ドキュメント
VOLUME 命令は指定された名前を使ってマウントポイントを生成します。 そして自ホストまたは他のコンテナーからマウントされたボリュームとして、そのマウントポイントを扱います。
荒い解釈ではありますが、
/var/lib/postgresql/data
をめぐる流れとしては、下記のように整理できると思いました。
1. ホストOSのローカルに/var/lib/postgresql/data
を生成
(postgres/Dockerfile-debian.template#L21)
2. PostgreSQLがサービスのデータを参照するための環境変数PGDATA
に/var/lib/postgresql/data
を設定
(postgres/Dockerfile-debian.template#L181)
3. Composeの起動時にPostgreSQLのサービスが/var/lib/postgresql/data
をマウントできるようにマウントポイントを生成
(postgres/Dockerfile-debian.template#L184)
4.$ docker compose run ~
でコンテナを起動したらマウントポイントの/var/lib/postgresql/data
をマウントしてサービス側から使用できるようにする
(チュートリアルのdocker-compose.ymlのdb: volume:設定行)environment:
environment: POSTGRES_PASSWORD: password#environment | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
環境変数を追加します。web:
任意のサービスの名称として"db"が付けられています。
公式のサンプルでは、下位にbuild
,command
,volumes
,ports
,depends_on
の設定項目が続きます。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: - dbbuild:
build: .#build | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
build の指定方法の 1 つは、ビルドコンテキストへのパスを表わす文字列を指定します
ビルドコンテキスト?
Docker Tips: All About the Build Context - Better Programming - MediumThe build context is the set of files located at the specified PATH or URL. Those files are sent to the Docker daemon during the build so it can use them in the filesystem of the image.
指定されたURLやPATHにあるファイル一式。これらのファイルはDockerのデーモンに送られビルド中にイメージのファイルシステムで使用できるようになる。
今回では、web
サービスのイメージでbuild
のPATHに.
を指定しているので、/var
,/myapp
などの全ての階層とファイルがweb
サービスイメージのファイルシステムで使用できるようになっています。command:
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"#command | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
コンテナ起動時にデフォルトで実行されるコマンド。bash -c
bash(1): GNU Bourne-Again SHell - Linux man page
-c
は後に続く文字列をコマンドとして実行するので、bash -c "<command>"
はBashシェルでを実行する意味になります。volumes:
volumes: - .:/myapp再掲:#volumes | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
ホストOS上のパスである.
を、コンテナ上の/myapp
へ専用のボリュームとしてマウントします。ports:
ports: - "3000:3000"#ports | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
公開するポートをHOST:CONTAINER
で指定します。depends_on:
depends_on: - db#depends_on | Compose ファイル バージョン 3 リファレンス | Docker ドキュメント
サービスの依存関係を指定します。複数ある場合は順番に起動。
ただ、依存サービスの「準備」状態を待たずに当サービスの起動を実行するため、ちゃんと依存関係にあるサービスの「準備」を待ちたいなら、別途コマンドにより待機させる工夫が必要です。
後書き
Docker + Raislの公式チュートリアルについては今回で一旦終了です。
DeepL頼みなことが多いですが、海外の記事やリファレンスを抵抗なく触れられるようになったことは、自身として少しは進歩しているのかなと感じます。理解が荒い部分も多いので、このような調査とアウトプットを継続して、正しい理解に近づくように取り組んでいきます。
また、英語だと教育資料や初心者向けの教材なども簡単にヒットするので、様々な情報源から学びを得られるように独力で英文を読む能力も鍛えていきたいと思いました。
次は、CircleCIの設定ファイルについて学習します。
- 投稿日:2020-07-06T14:27:32+09:00
dockerでvolume mountしたファイルがpermission denied
やろうとしたこと
nginx(openresty)をdockerで起動し、ホストのディレクトリ(nginx.confなどが置いてある)をマウントしようとした。業務だったので、家でのように「とりあえずroot」とやるのは気が引けて色々調べた(結局今はrootになっているが)。
環境
CentOS 7.3
docker 1.13.1困ったこと
マウント先のファイルの権限を正しく設定しても
ls
などでpermission denied
がでて、ファイルが読めない。結論
- dockerコンテナ内でもuid, gidがホストと同じなら同一ユーザとみなされる
- ただし、SELinuxを知らずにやると権限があるように見えてもpermission deniedされる(今回)
確認したこと
まずは権限が本当にあっているのか確認1。
コンテナ内でuser1(ホストと合わせる)という一般ユーザを作り、user1で色々実行できればいいなと思って調べた。Dockerfile
DockerfileFROM openrestyの何か RUN useradd --disabled-password user1 # USER user1 を試したりも確認パターン
ファイル所有者(ホスト側) コンテナ実行者 コンテナ内作業 結果 備考 user1 root マウント先ディレクトリでls Permission denied まぁわかる root root マウント先ディレクトリでls Permission denied ホストとコンテナのrootは同じだから本来いけるはず user1 user1 - nginx起動せず(コンテナexit) nginxのstart権限がないのかも user1 root su user1
してからマウント先ディレクトリでlsPermission denied 同一ユーザだから2本来行けるはず そのほか
chmod 777 -R <ディレクトリ>
も試しましたが同じですね。今回の対応
コンテナ実行とかもろもろuser1でやるのは(そもそも起動もしないし)色々大変だろうと判断し3、とりあえずrootでやることに(まず動作確認したい)。
それでもうまくいかずに調べていたら、CentOSなどはデフォルトでSELinuxというものが有効になっており、これが関係しているとのこと。ホスト側でgetenforce
コマンドの出力がEnforcing
なら有効。有効だったのでこれを一時的に無効にするsudo setenforce 0
を実行すると無事コンテナ内でマウント先のファイルが見られた。setenforce 0
は一時的で、OS再起動するとリセットされる。
そして当然ながらセキュリティ関連のものを脳筋で無効にするのはいいことではなく、docker公式がSELinuxとの併用を推奨しているとの噂もありました(一次ソースに当たらない人)。所感
dockerで権限があってるのにマウント先見られなかったらSELinuxを知るとよい。
できればSELinux有効で正しい設定をして今回の問題を解決したいものである。
- 投稿日:2020-07-06T13:44:46+09:00
Dockerのvolumeが使用中で消せないとき
Dcokerのvolumeが使用中で消せない
Docker-compose.ymlでvolumeを指定してデータの永続化をした際など、環境を作り直したくてvolumeも消去したいのに、消去できなかった事があったので覚書
- Docker-compose down -v で消そうと思ったけどvolumeが使用中で消せない
- docker volume rm -f 消したいvolume名 で消そうと思ったけどvolumeが使用中で消せない
- docker volume prune で消そうと思ったけどvolumeが使用中で消せない
- docker-compose ps やdocker psでも使用しているコンテナが見当たらない
↑見えていないコンテナがありそうな気配。
強制的にコンテナを削除してみたら、volumeを握っていると思われるコンテナも消えて、無事volumeの削除もできました。
docker container prune
docker volume rm -f 消したいvolume名
- 投稿日:2020-07-06T13:44:46+09:00
Dockerのvolumeが使用中で消せない時
使用環境
Windows10
Docker Desktop for Windows version 2.3.0.3トラブル内容
Dcokerのvolumeが使用中で消せない
docker-compose.ymlでvolumeを指定してデータの永続化をした際など、環境を作り直したくてvolumeも消去したいのに、消去できなかった事があったので覚書
- Docker-compose down -v で消そうと思ったけどvolumeが使用中で消せない
- docker volume rm -f 消したいvolume名 で消そうと思ったけどvolumeが使用中で消せない
- docker volume prune で消そうと思ったけどvolumeが使用中で消せない
- docker-compose ps やdocker psでも使用しているコンテナが見当たらない
↑見えていないコンテナがありそうな気配
トラブル対処
強制的にコンテナを削除してみたら、volumeを握っていると思われるコンテナも消えて、無事volumeの削除もできました。
docker container prune
docker volume rm -f 消したいvolume名
- 投稿日:2020-07-06T10:23:44+09:00
DockerでSQLServerを建てる際にハマったのでメモ(永続化)
はじめに
Azureでサービスを作ることになり、ローカル環境にDockerでSQLServerを立てて永続化させる際に行ったことをメモとして残します。
普通に書いてみる
MySQLと同じ感覚で書いてみて起動してみる。
docker-compose.yamlversion: "3" services: sqlserver: image: microsoft/mssql-server-linux:2017-latest container_name: mssql hostname: mssql volumes: - ./.db:/var/opt/mssql/data ports: - 14330:1433 environment: ACCEPT_EULA: Y SA_PASSWORD: SQLServer2017〉 docker-compose up Recreating mssql ... done Attaching to mssql mssql | 2020-07-05 22:00:46.51 Server Setup step is copying system data file 'C:\templatedata\master.mdf' to '/var/opt/mssql/data/master.mdf'. 2020-07-05 22:00:46.86 Server Did not find an existing master data file /var/opt/mssql/data/master.mdf, copying the missing default master and other system database files. If you have moved the database location, but not moved the database files, startup may fail. To repair: shutdown SQL Server, move the master database to configured location, and restart. 2020-07-05 22:00:46.88 Server Setup step is copying system data file 'C:\templatedata\mastlog.ldf' to '/var/opt/mssql/data/mastlog.ldf'. 2020-07-05 22:00:46.94 Server Setup step is copying system data file 'C:\templatedata\model.mdf' to '/var/opt/mssql/data/model.mdf'. 2020-07-05 22:00:47.53 Server Setup step is copying system data file 'C:\templatedata\modellog.ldf' to '/var/opt/mssql/data/modellog.ldf'. 2020-07-05 22:00:48.26 Server Setup step is copying system data file 'C:\templatedata\msdbdata.mdf' to '/var/opt/mssql/data/msdbdata.mdf'. 2020-07-05 22:00:49.40 Server Setup step is copying system data file 'C:\templatedata\msdblog.ldf' to '/var/opt/mssql/data/msdblog.ldf'. 2020-07-05 22:00:49.56 Server Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64) mssql Nov 30 2018 12:57:58 mssql Copyright (C) 2017 Microsoft Corporation mssql Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS) 2020-07-05 22:00:49.56 Server UTC adjustment: 0:00 2020-07-05 22:00:49.56 Server (c) Microsoft Corporation. 2020-07-05 22:00:49.57 Server All rights reserved. 2020-07-05 22:00:49.57 Server Server process ID is 4120. 2020-07-05 22:00:49.57 Server Logging SQL Server messages in file '/var/opt/mssql/log/errorlog'. 2020-07-05 22:00:49.57 Server Registry startup parameters: mssql -d /var/opt/mssql/data/master.mdf mssql -l /var/opt/mssql/data/mastlog.ldf mssql -e /var/opt/mssql/log/errorlog 2020-07-05 22:00:49.59 Server Error: 17113, Severity: 16, State: 1. 2020-07-05 22:00:49.59 Server Error 87(The parameter is incorrect.) occurred while opening file '/var/opt/mssql/data/master.mdf' to obtain configuration information at startup. An invalid startup option might have caused the error. Verify your startup options, and correct or remove them if necessary. mssql exited with code 1解決方法
調べてみると、Docker for Macだとvolumn mappingはサポートされていないらしい。
https://github.com/microsoft/mssql-docker/issues/12ただデータを永続化できないと色々面倒な問題があったので、書き方を調べてみた結果、以下のような書き方で動作することが確認できた。
docker-compose.yamlversion: "3" services: sqlserver: image: microsoft/mssql-server-linux:2017-latest container_name: mssql hostname: mssql volumes: - ./.db:/var/opt/mssql/ - /var/opt/mssql/data ports: - 14330:1433 environment: ACCEPT_EULA: Y SA_PASSWORD: SQLServer2017おわりに
もし間違いがあればご指摘いただけると助かります。
- 投稿日:2020-07-06T09:14:47+09:00
WSL2での開発メモ
はまったところを書いていく
docker for Windowsは意地でも使わないWSL2内でX11アプリケーションを起動し、Windows側で描画
- Windows側でvcXsrvを起動
- WSL側で
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
- WSL側でX11アプリケーション起動
WSL2はsystemdが使えない
WSL用のinitを使っているらしい
よってdockerdの自動起動ができない
dockerd --add-runtime oci=/usr/sbin/docker-runc
で手動で起動するWindows側からWSLのファイルシステムにアクセスする
explorerのナビゲーションバー(?)に
\\wsl$
と入力してEnterdocker-composeでmappingしたportにwindowsから127.0.0.1経由でアクセスできない
localhostだとつながるのに、127.0.0.1だとつながらない
before.yamlports: - 80:80after.yamlports: - 127.0.0.1:80:80
- 投稿日:2020-07-06T07:21:54+09:00
VSCode Remote Containers を利用して最強のローカル開発環境を作りたい
はじめに
VSCodeの神拡張機能であるRemote Containersの自分なりの設定の紹介です
公式サンプルは公開されていますが、そのままだと流石に使いずいので自分なりに使いやすいように編集した設定を紹介します
なお、本記事で紹介する設定ファイルは全て以下のリポジトリで公開しています(紹介していない環境のものも入っています)
https://github.com/sabure500/remote-container-sampleまた、Remote Containersを使ってみて良いなと思ったので色々使いやすいように設定を弄っていますが、本記事は最強のローカル環境を「作りたい」なので、ここをこうした方が良いといった案があったら是非教えてくれると嬉しいです
VSCode Remote Containers とは
VSCodeの拡張機能であり、使用することでコンテナの中でVSCodeを開いて作業を行うことができるようになる
コンテナの中で直接VSCodeを開いて作業ができるようになるため、開発環境をサンドボックス化してローカルマシン上には全く影響しないところで開発を行うことができる
類似の拡張機能シリーズでこれ以外にも「Remote SSH」と「Remote WSL」が存在し、これはそれぞれSSH接続先またはWSLの中でVSCodeを開いて作業を行うことができるようになる
それぞれの詳細は 公式サイト を参照インストール
VSCode Remote Containers で開発環境を作る場合は以下の2つのインストールが必要です
逆にいうと、以下の2つがあればローカルマシンには他に何も入れずにNode,python,Go,Java等の環境が作れます
* Visual Studia Code
* Docker Desktop for Windows or MacDocker Desktop for Windows or Mac
以下の公式ページからインストーラをダウンロードする
https://www.docker.com/products/docker-desktopVisual Studio Code
VSCode本体のインストール
以下の公式ページからダウンロードする
https://code.visualstudio.com/docsRemote Containersの導入
Remote Containersは通常の拡張機能なので、VSCodeインストール後に起動して左のタブから拡張機能を選択し「Remote Container」と検索することで一覧に出てくるのでそこからインストールできる
もしくは以下のマーケットプレースのページからインストールしても良い
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containersRemote Containersの起動
後ほど紹介するRemoteContainersの設定ファイルがある場所をWorkspaceとして起動後に、VSCode左下の緑の「><」マークをクリックし、「Remote-Containers : Reopen in Container」を選択する
環境構築設定の紹介
Remote Containersにおける環境構築は.devcontainerディレクトリ上にdevcontainer.jsonというRemote Containers用の設定ファイルとDockerfile(もしくは、docker-compose.yaml等)を配置することで行う
環境毎の設定を紹介していくGoogleCloudSDK
ローカル環境でGoogleCloudSDKのコマンドを利用するときもRemote Containersを利用している
設定ファイルは以下で公開しており、基本的にはこれをそのまま使うことで誰でもすぐに同じGoogleCloudSDKの環境を利用できる
その環境構築用の設定を記述していく
全体のディレクトリ構成は以下のようになっている. ├ .devcontainer ├ devcontainer.json ├ Dockerfile ├ .config/fish/config.fish └ .local/share/fish/fish_historyDockerfile
実際に開発環境として使うコンテナを作成する用のファイル
最初に全体像を示し、その後各行を解説するDockerfileFROM google/cloud-sdk:297.0.1-alpine # ===== common area ===== RUN apk add --no-cache fish git openssh curl COPY .config/fish/config.fish /root/.config/fish/config.fish # ======================= # ===== kubernetes resource install ===== ENV KUBECTL_VERSION 1.18.4 ENV KUSTOMIZE_VERSION 3.1.0 ENV ARGOCD_VERSION 1.5.2 RUN curl -sfL -o /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ && curl -sfL -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 \ && curl -sfL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v${ARGOCD_VERSION}/argocd-linux-amd64 \ && chmod +x /usr/local/bin/kubectl /usr/local/bin/kustomize /usr/local/bin/argocd # =======================
ベースイメージ
FROM google/cloud-sdk:297.0.1-alpineベースイメージは google/cloud-sdk:297.0.1-alpine を利用する
環境で利用する汎用的なパッケージのインストール
RUN apk add --no-cache fish git openssh curlベースイメージがalpineなので、apkを利用して開発環境上で利用したいパッケージをインストールする
ここではfish,git,ssh,curlを入れているが、bashを使いたい場合はfishではなくbashを導入する等各自カスタマイズするfishシェル用の設定
COPY .config/fish/config.fish /root/.config/fish/config.fishconfig/fish/config.fishset normal (set_color normal) set magenta (set_color magenta) set yellow (set_color yellow) set green (set_color green) set red (set_color red) set gray (set_color -o black) # Fish git prompt set __fish_git_prompt_showdirtystate 'yes' set __fish_git_prompt_showstashstate 'yes' set __fish_git_prompt_showuntrackedfiles 'yes' set __fish_git_prompt_showupstream 'yes' set __fish_git_prompt_color_branch yellow set __fish_git_prompt_color_upstream_ahead green set __fish_git_prompt_color_upstream_behind red # Status Chars set __fish_git_prompt_char_dirtystate '⚡' set __fish_git_prompt_char_stagedstate '→' set __fish_git_prompt_char_untrackedfiles '☡' set __fish_git_prompt_char_stashstate '↩' set __fish_git_prompt_char_upstream_ahead '+' set __fish_git_prompt_char_upstream_behind '-' function fish_prompt set last_status $status set_color $fish_color_cwd printf '%s' (prompt_pwd) set_color normal printf '%s ' (__fish_git_prompt) set_color normal end作業用のシェルとしてはfishシェルを利用する
初期設定のままでは使いづらいので、Gitのブランチを表示する等のプロンプトを変更する設定ファイルをコンテナ上にコピーして配置する
fishの設定ファイルは以下のブログの記事を参考にさせてもらっています
https://www.martinklepsch.org/posts/git-prompt-for-fish-shell.htmlGoogleCloudSDkと一緒に使うコマンド類のインストール
# ===== kubernetes resource install ===== ENV KUBECTL_VERSION 1.18.4 ENV KUSTOMIZE_VERSION 3.1.0 ENV ARGOCD_VERSION 1.5.2 RUN curl -sfL -o /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl \ && curl -sfL -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 \ && curl -sfL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v${ARGOCD_VERSION}/argocd-linux-amd64 \ && chmod +x /usr/local/bin/kubectl /usr/local/bin/kustomize /usr/local/bin/argocd # =======================GCPのリソースとして専らGKEを使うことが多いので、Kubernetes関連のリソースをコンテナ内にインストールしています
devcontainer.json
VSCodeからコンテナを開く際の設定ファイル
利用するDockerfileやコンテナ上でVSCodeを利用する際の拡張機能、またローカル環境からのVolume等を記述する
他に何ができるかの詳細は公式のリファレンスを参照
最初に全体像を示し、その後各行を解説するdevcontainer.json{ "name": "Google Cloud SDK Remote-Container", "build" : { "dockerfile": "Dockerfile" }, "settings": { "terminal.integrated.shell.linux": "/usr/bin/fish", }, "extensions": [ "alefragnani.bookmarks", "mhutchie.git-graph", "redhat.vscode-yaml", "zainchen.json" ], "mounts": [ "source=${localEnv:HOME}/.ssh/,target=/root/.ssh/,type=bind,consistency=cached", "source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached", "source=${localWorkspaceFolder}/.devcontainer/.local/share/fish/fish_history,target=/root/.local/share/fish/fish_history,type=bind,consistency=cached", "source=${localEnv:HOME}/.config/gcloud/,target=/root/.config/gcloud/,type=bind,consistency=cached", "source=${localEnv:HOME}/.kube/,target=/root/.kube/,type=bind,consistency=cached", ], }
利用するコンテナイメージ
"build" : { "dockerfile": "Dockerfile" },Dockerfileの置いてある場所を指定する
最初にディレクトリ構造で示した通り、同じディレクトリ上にあるのでそのまま"Dockerfile"と書いているコンテナ固有のVSCodeの設定
"settings": { "terminal.integrated.shell.linux": "/usr/bin/fish", },コンテナ上独自で設定したいVSCodeの設定を記載する
例えば、ローカル上では導入しないがコンテナ上では導入するExtension用の設定等
settingsの記述に関してはローカル上で書かれていることは改めてdevcontainer.json上で書かなくてもコンテナ上で引き継がれる
ここではコンテナ上ではターミナルのシェルはfishを利用することだけ記述しているコンテナ環境上のVSCodeで利用する拡張機能の設定
"extensions": [ "alefragnani.bookmarks", "mhutchie.git-graph", "redhat.vscode-yaml", "zainchen.json" ],コンテナ環境上で利用したい拡張機能を記述する
拡張機能に関してはsettingsの設定と違い、ローカル上で導入されていてもdevcontainer.json上で書かれていないものはコンテナ上で導入されないので注意ローカル環境からのマウント
"mounts": [ "source=${localEnv:HOME}/.ssh/,target=/root/.ssh/,type=bind,consistency=cached", "source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached", "source=${localWorkspaceFolder}/.devcontainer/.local/share/fish/fish_history,target=/root/.local/share/fish/fish_history,type=bind,consistency=cached", "source=${localEnv:HOME}/.config/gcloud/,target=/root/.config/gcloud/,type=bind,consistency=cached", "source=${localEnv:HOME}/.kube/,target=/root/.kube/,type=bind,consistency=cached", ],ローカル環境上のファイルを使いたい、または、コンテナを再起動しても消去されて欲しくないファイルをマウントする
"source="でローカルのパス、"target="でコンテナ上のパスを指定している
また、${localEnv:XXXX}と書くことで、ローカル環境上で環境変数「XXXX」を利用できる
ここでは5つのファイル・ディレクトリをマウントしている
- sshの設定 sshの設定は複数の環境から利用されるため、ローカル環境からマウントして利用する
- gitの設定 gitの設定も複数の環境から利用されるため、ローカル環境からマウントして利用する
- fishの操作履歴 ここが結構ポイントで、コンテナ上で作業しているとコンテナを停止すると操作履歴が全て削除されてしまう 自分は作業をするときにカーソル↑等を利用して過去のhistoryのコマンド履歴を利用することが多く消されると不便だったので、消えないようにWorkspaces上でマウントしておく
- gcpの設定 GCPログイン情報等も毎回消えると面倒なのでローカル上からマウントする
- kubectlの設定 同じくGKEのクラスタ登録等も毎回消えると面倒なのでローカル上からマウントする
Java
Java用の環境として、OpenJDK+Wildfly+maven+Gradleが入った環境を使用している
このJava用の環境も上で紹介したGoogleCloudSDKの環境と相違点に絞って紹介する
全体のディレクトリ構成は以下のようになっている. ├ .devcontainer ├ devcontainer.json ├ docker-compose.yaml ├ Dockerfile ├ .m2/ ├ .gradle/ ├ .config/fish/config.fish └ .local/share/fish/fish_historydocker-compose
Javaの環境は別にコンテナで立てるDB環境と接続するためにDockerのNetworkを利用するためにDockerfileではなく、docker-composeを利用する
最初に全体像を示し、その後各行を解説するdocker-compose.yamlversion: "3" services: jdk-wildfly-maven: build: . ports: - "8080:8080" - "9990:9990" command: /bin/sh -c "while sleep 1000; do :; done" volumes: - $HOME/.ssh:/root/.ssh - $HOME/.gitconfig:/root/.gitconfig - .local/share/fish/fish_history:/root/.local/share/fish/fish_history - ..:/workspace - ./jboss_home/configuration/standalone.xml:/opt/wildfly/standalone/configuration/standalone.xml - .m2:/root/.m2 - .gradle:/root/.gradle networks: - remote-container_common-network networks: remote-container_common-network: external: true
ローカル環境からコンテナ環境へのポートフォワード
ports: - "8080:8080" - "9990:9990"Wildflyのデフォルトポートである8080と9990に対して、ローカル環境で対象のポートにアクセスした際にコンテナ上にアクセスするようにする
コンテナのデフォルトコマンドの上書き
command: /bin/sh -c "while sleep 1000; do :; done"コンテナ起動時のデフォルトコマンドが失敗したり終了したりした場合にコンテナが停止しないように、デフォルトコマンドを上書きする
ここで記述しているコマンドはdocker-composeを利用しない場合のRemote Containersのデフォルト設定
docker-composeを利用する場合は明示的に書いてあげる必要があるローカル環境からのマウント
volumes: - $HOME/.ssh:/root/.ssh - $HOME/.gitconfig:/root/.gitconfig - .local/share/fish/fish_history:/root/.local/share/fish/fish_history - ..:/workspace - ./jboss_home/configuration/standalone.xml:/opt/wildfly/standalone/configuration/standalone.xml - .m2:/root/.m2 - .gradle:/root/.gradleローカル環境からのマウントはdevcontainer.jsonではなくdocker-compose.yamlで書く必要がある
Dockerfileの場合と違うところは、"..:/workspace"と書いているようにworkspace自体を明示的に指定してマウントしている
java環境独自の設定として".m2:/root/.m2"や".gradle:/root/.gradle"でGradleやMavenの設定やリポジトリをマウントしている。これはこの環境でしか利用しないものなので、ユーザーホーム($HOME)ではなくWorkSpace上に直接マウントしている
またWildflyの設定ファイルであるstandalone.xmlについては、データソースの設定等が開発中に常に変更される可能性があり、コンテナ再起動のたびに削除されても困るので"./jboss_home/configuration/standalone.xml:/opt/wildfly/standalone/configuration/standalone.xml"といった形でマウントしているdocker networkの利用
networks: - remote-container_common-network networks: remote-container_common-network: external: trueJavaはアプリケーションの実行環境として利用するのでDBと接続をしたい
DBに関してもローカル環境ではコンテナとして起動するので他のコンテナと接続するためにDocker Networkを作成してそれを利用する
そのためこの環境を利用するためには以下のコマンドで事前にネットワークを作成する必要があるdocker network create --driver bridge remote-container_common-network
Dockerfile
docker-compose.yamlで指定しているOpenJDK+Wildfly+maven+Gradle環境を作成するDockerfile
ベースイメージとしてはJBoss公式イメージ"jboss/wildfly"はサイズが大きく使いずらかったりalpineベースのイメージを使いたかったこともあり、Adoptopenjdkを元にして作成しているDockerfileFROM adoptopenjdk/openjdk11:alpine-slim # ===== common area ===== ENV WORKSPACE_DIR "/workspace" RUN apk add --no-cache fish git openssh curl wget tar unzip\ && mkdir -p $WORKSPACE_DIR COPY .config/fish/config.fish /root/.config/fish/config.fish # ======================= # ==== wildfly install ===== ENV JBOSS_HOME "/opt/wildfly" ENV WILDFLY_VERSION "20.0.0.Final" RUN wget -P /opt http://download.jboss.org/wildfly/${WILDFLY_VERSION}/wildfly-${WILDFLY_VERSION}.tar.gz \ && tar -zxvf /opt/wildfly-${WILDFLY_VERSION}.tar.gz -C /opt \ && rm /opt/wildfly-${WILDFLY_VERSION}.tar.gz \ && mv /opt/wildfly-${WILDFLY_VERSION} ${JBOSS_HOME} \ && $JBOSS_HOME/bin/add-user.sh admin admin --silent # ======================= # ==== maven install ===== ENV MAVEN_HOME "/opt/maven" ENV MAVEN_VERSION 3.6.3 ENV PATH "$PATH:$MAVEN_HOME/bin" ENV MAVEN_CONFIG "$HOME/.m2" RUN curl -fsSL -o /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz http://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ && tar -zxvf /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz -C /opt \ && rm /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz \ && mv /opt/apache-maven-${MAVEN_VERSION} /opt/maven # ======================= # ==== gradle install ==== ENV GRADLE_HOME "/opt/gradle" ENV GRADLE_VERSION 6.5 ENV PATH "$PATH:$GRADLE_HOME/bin" RUN curl -fsSL -o /opt/gradle-${GRADLE_VERSION}-bin.zip https://downloads.gradle-dn.com/distributions/gradle-${GRADLE_VERSION}-bin.zip \ && unzip -d /opt /opt/gradle-${GRADLE_VERSION}-bin.zip \ && rm /opt/gradle-${GRADLE_VERSION}-bin.zip \ && mv /opt/gradle-${GRADLE_VERSION} /opt/gradle # =======================devcontainer.json
Dockerfileを利用する場合とdocker-composeを利用する場合で、devcontainer.jsonのデフォルトの設定や利用できる設定が変わっている(例えば、マウントはdevcontainer.jsonには記述しても効かなくなり、docker-composeにて記述しなければならなくなる)
詳細は公式リファレンス参照devcontainer.json{ "name": "JDK&Wildfly&Maven&Gradle Remote-Container", "dockerComposeFile": "docker-compose.yaml", "service" : "jdk-wildfly-maven", "workspaceFolder": "/workspace", "settings": { "terminal.integrated.shell.linux": "/usr/bin/fish", "java.home": "/opt/java/openjdk", "maven.executable.preferMavenWrapper": false, "maven.executable.path": "/opt/maven/bin", "maven.terminal.useJavaHome": true, "java.jdt.ls.vmargs": "-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication -javaagent:\"/root/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar\"", }, "extensions": [ "alefragnani.bookmarks", "mhutchie.git-graph", "vscjava.vscode-java-pack", "shengchen.vscode-checkstyle", "gabrielbb.vscode-lombok", "naco-siren.gradle-langua" ], "shutdownAction": "stopCompose" }
利用するイメージとサービス
"dockerComposeFile": "docker-compose.yaml", "service" : "jdk-wildfly-maven",docker-composeを利用する場合は"dockerComposeFile"を利用してdocker-compose.yamlの場所を指定する
また、docker-composeの場合は複数のコンテナが起動している可能性があるので、serviceでどのコンテナでVSCodeを開くのかも指定するworkspaceフォルダの指定
"workspaceFolder": "/workspace",Dockerfileの場合と違い、docker-composeの場合は明示的にマウントするworkspaceの場所を指定する必要がある
この場合に存在しないディレクトリは指定できないため、Dockerfile上で先に/workspaceといったディレクトリを作っておくjava特有の設定
"settings": { "terminal.integrated.shell.linux": "/usr/bin/fish", "java.home": "/opt/java/openjdk", "maven.executable.preferMavenWrapper": false, "maven.executable.path": "/opt/maven/bin", "maven.terminal.useJavaHome": true, "java.jdt.ls.vmargs": "-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication -javaagent:\"/root/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar\"", }, "extensions": [ "alefragnani.bookmarks", "mhutchie.git-graph", "vscjava.vscode-java-pack", "shengchen.vscode-checkstyle", "gabrielbb.vscode-lombok", "naco-siren.gradle-langua" ],ローカル環境のVSCode上では入れていないが、Java環境では利用したい拡張機能を指定している
また、その拡張機能に対応したコンテナ上でのみ適用したいsettingsの内容を記述しているMySQL
前の章で作成したJavaから利用するDBもコンテナで作成する
この環境はあまりRemote Containersで作成する意味はないが、統一するために一応Remote Containersで作っている
単純にdocker-composeで起動しても特に問題はない
他のコンテナ(Java環境)と接続するためにこの環境を作る前に以下のコマンドでDocker networkを作っておくこと
(すでにある場合は問題なし)docker network create --driver bridge remote-container_common-network
全体のディレクトリ構成や設定ファイルは以下のようになっている
. ├ .devcontainer │ ├ devcontainer.json │ ├ docker-compose.yaml │ └ my.cnf └ dbdocker-compose.yamlversion: "3" services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: pass TZ: "Asia/Tokyo" ports: - "3306:3306" volumes: - ../db/data:/var/lib/mysql - ./my.cnf:/etc/mysql/conf.d/my.cnf networks: - remote-container_common-network phpmyadmin: image: phpmyadmin/phpmyadmin environment: PMA_ARBITRARY: 1 ports: - 3307:80 depends_on: - mysql networks: - remote-container_common-network networks: remote-container_common-network: external: truedevcontainer.json{ "name": "MySQL Remote-Container", "dockerComposeFile": "docker-compose.yaml", "service" : "mysql", "workspaceFolder": "/root", "settings": { "terminal.integrated.shell.linux": "/bin/bash", }, "extensions": [], "shutdownAction": "stopCompose" }補足
今回はあくまで自分用のローカル環境の構築なので、複数のアプリケーションを1つの環境で扱うことを想定してRemote Containersの設定を作っている
つまり以下のようなこと. ├ .devcontainer ├ application1 │ ├ .git │ └ source code ├ application2 │ ├ .git │ └ source code上記のような構成ではなく、1つのアプリケーションに対して1つのRemote Containersの設定を作る方がgit上でそのアプリの開発環境も管理でき開発者全員が同じ環境を使える等のメリットがあるため良いと思われる
つまり以下のようなこと. ├ application1 │ ├ .devcontainer │ ├ .git │ └ source code ├ application2 │ ├ .devcontainer │ ├ .git │ └ source codeただし、このような管理の仕方の場合は今回紹介したようなfishの独自設定をぶち込んだりすると戦争が起りかねないのでチームでよく相談してどうするかを決定した方が良いと思われます
VSCode Remote Containers のメリット・デメリット
最後に使っていて思ったメリット・デメリットをまとめて終わりにする
メリット
- 自分のローカル環境が汚れない
VSCodeとDockerさえあれば余計なものを何も入れなくて良い点がすごく良い
- 開発環境の設定もアプリ開発者の間で共有できる
同じ開発環境を共有していることになるので人によっては動く動かないといった事象の発生をなくせる
また、そもそもDockerfileが必須になるため本番環境もDockerfileで作れば開発と本番での差異を限りなく少なくできる
ただし、あくまで開発環境用のDockerfileと本番環境用のDockerfileは別で作った方が良い
(本記事では紹介していないがRemote Containersのextendの機能を利用して本番環境のDockerfileを元に開発にい必要なパッケージの導入部分のみ上書いて開発環境で利用することもできる)- 開発環境で作ったイメージがCI/CDで流用できる
開発環境上でツールを使ってチェック等をしている時は、CI/CDの時にも同様のチェックをすることは多い
この時に今のCICDツールはJOBのコンテナ上での実行をサポートしていることが多いので、開発環境作成時に作ったコンテナをそのままであったり一部だけ改良して利用できたりするデメリット
- VSCodeでしか使えない
VSCodeの拡張機能なので、それ以外のIDEでは使えない
かなり有用な機能なので自分が知らないだけで他のIDEでも同じようなことができるのかもしれないですが...
- コンテナ上では利用できない拡張機能もある
Remote Containersで起動したコンテナ上のVSCodeでは利用できない拡張機能が一部存在する
- 利用するツールについてある程度理解していないと環境構築できない
Dockerfileを作成することが必須であり、このツールの設定ファイルはどこに展開されるかといったことやマウントした方が良い部分とそうでない部分といったことを理解して意識する必要がある
ただし、設定を自作するのではなく他人が作成した設定ファイルをそのまま利用する場合は今までよりさらに何も知らなくても使えます
- 一つのコンテナ環境にどこまで詰め込んで良いか分かりづらい
今回紹介したものだとJavaとGoogleCloudSDKで分けているが、やろうと思えばこれはさらに細分化できるし、逆に1つにまとめることもできる
アプリケーションの単位でremote-containerの設定を作るなら分かりやすいが、GoogleCloudSDKのように自分用のローカル環境として作る場合は境目が難しく基準となる答えはまだ持っていない参考
- VSCode Remote Containers公式サンプル : https://github.com/Microsoft/vscode-dev-containers
- VSCode Remote Containers公式ドキュメント : https://code.visualstudio.com/docs/remote/remote-overview
- fishプロンプト設定の参考ブログ : https://www.martinklepsch.org/posts/git-prompt-for-fish-shell.html
- 投稿日:2020-07-06T02:27:17+09:00
docker-composeで、nginx、php、mysqlの環境を作成してみた
私は初心者です。間違っていたりもっと良いやり方がありましたら教えていただけるとありがたいです
こちらのリンクにコードを置きました
参考
- docker-composeでPHPとMySQLを連携させてみる - Qiita
- https://hub.docker.com/_/php
- https://hub.docker.com/_/mysql
- FuelPHPでのMySQL接続時にThe server requested authentication method unknown to the client [caching_sha2_password] となった場合に対処してみた - Qiita
- Docker Laravel Mysql: could not find driver - Stack Overflow
docker-compose.ymlversion: "3" services: web: image: nginx ports: - "8080:80" volumes: # ホストのdefault.confを同期 - ./default.conf:/etc/nginx/conf.d/default.conf # ホストの./myappフォルダを同期 - ./myapp:/var/www/html depends_on: - php php: build: . volumes: # ホストの./myappフォルダを同期 - ./myapp:/var/www/html db: image: mysql # PDOでhostを指定するときにこのコンテナ名を使う container_name: mysql # MySQL8.0でのデフォルトの認証方式が「caching_sha2_password」なので変更する # 設定しないと "The server requested authentication method unknown to the client" とエラーになる command: --default-authentication-plugin=mysql_native_password environment: # 設定必須、rootパスワード - MYSQL_ROOT_PASSWORD=root # この設定はオプション、イメージの起動時に作成されるデータベース名 - MYSQL_DATABASE=sampledefault.confserver { listen 80; listen [::]:80; server_name localhost; root /var/www/html; location / { index index.php index.html; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }DockerfileFROM php:7-fpm # 拡張モジュールをインストール RUN docker-php-ext-install pdo pdo_mysqlmyapp/index.php<?php try { echo (new PDO( 'mysql:host=mysql;dbname=sample;charset=utf8mb4', 'root', 'root', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] )) ->query('select concat(\'MySQL Version :\', version()) v') ->fetch()['v']; } catch (PDOException $e) { echo $e->getMessage(); }以上です。m(_ _)m