20200623のdockerに関する記事は16件です。

[Ruby on rails] Docker & Travis CIを使ってHerokuデプロイしたときのエラーまとめ

概要

初めてDockerやTravis CIを使ってデプロイしたので流れとエラーをまとめておきます。
誰かの参考に慣れば・・・
Dockerの勉強はUdemyのこちらの動画で勉強しました。
初心者にもかなりわかりやすく説明されているのでお勧めです。
※この動画ではpostgesqlを使う方法が紹介されていますが、僕は開発環境も含めmysqlを使ってので違いなどもメモしておきます。

環境設定

・Docker
・rails 5.2

 大まかなデプロイ時の流れ

  1. TravisCIに登録し、GitHubと連携
  2. .tarvis.yml ファイルを書く
  3. Travis CIにビルド
  4. Herokuでアプリ作成
  5. Heroku と Travis CI に環境変数を設定する。

 2つのエラー

 mysql2が読み込まれない

Herokuにデプロイした際に、Build failedとなってしまいました。
ブラウザからHerokuのリポシトリーのActivityにあるBuild log を見ると以下のところでエラーになっているようでした。

LoadError: Could not load the 'mysql' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.

これはブラウザのHerokuのリポジトリーのsettingsのConfig Varsを開き、

CLEARDB_DATABASE_URL : mysql://~~

となっているところを

CLEARDB_DATABASE_URL : mysql2://~~

と変更すると直ります。デフォルトではmysqlが書かれてしまうんですかね?

 DBがない!?

Herokuのアプリの画面に移動した際、We're sorry, but something went wrong.というエラー表示がされてしまいました。

これはローカルからHerokuへとアクセスし

$ heroku logs -t

でログを見てみると

ActiveRecord::StatementInvalid (Mysql2::Error: Table 'heroku_067b02b8d8fb0b9.users' doesn't exist: SHOW FULL FIELDS FROM `users`):

となっていて、DBができていないようなので、マイグレーションして解決しました。

$ heroku run rails db:migrate

※ travis.yml ファイルにデプロイの際に、マイグレーションするように書いたはずなんだけどなー。なぜかうまく行っていなかったですね。

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

Docker+Rails6+MySQL+Nginx環境構築メモ

はじめに

弊社では未だにdockerを導入しておらず、このままだとマズいと思ったので勉強も兼ねて環境構築してみました。
ミスや間違った説明をしている箇所があるかもしれませんが、優しくご指摘頂けると助かります。
既に環境構築系の記事は出ていますが、実際試しても上手くいかないことがあったので自分の経験もまとめておきます。

流れ

  • "rails new"でプロジェクト作成
  • "git init"でローカルリポジトリ作成
  • GitHubにてリモートリポジトリ作成
  • リモートリポジトリにプッシュ

-----ここから書きます-----
- EC2インスタンス作成
- gitインストール
- dockerインストール
- docker起動
- リモートリポジトリをプル

  • イメージのビルド(docker-compose build --no-cache)
  • コンテナ作成,起動(docker-compose up -d)
  • マイグレーション(docker-compose exec sample-app_web_1 bundle exec rails db:migrate)

gitのインストール

Gitをインストールします

$ sudo yum install git
$ git clone https://github.com/satou-yuuki/sample-app.git

dockerのインストール

AWS公式に従ってDockerをインストールします
参考:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html

$ sudo yum update -y
$ sudo amazon-linux-extras install docker
$ sudo systemctl start docker.service または sudo service docker start
$ sudo usermod -a -G docker ec2-user
一度ターミナルを抜けるとグループが追加されていると思います

docker-composeのインストール

docker公式に従ってdocker-composeをインストールします
参考:https://docs.docker.com/compose/install/

$ 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-compose build

$ docker-compose build --no-cache

docker-compose up

$ docker-compose up -d

rails db:migrate

$ docker exec sample-app_web_1 bundle exec rails db:migrate

ブラウザから確認

ブラウザで http://host/users を確認するとエラー画面が表示されてしまったのでログを確認します。

Started GET "/users" for 111.239.186.32 at 2020-06-22 00:17:50 +0000
Cannot render console from 111.239.186.32! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by UsersController#index as HTML
  Rendering users/index.html.erb within layouts/application
  User Load (0.4ms)  SELECT `users`.* FROM `users`
  ↳ app/views/users/index.html.erb:16
  Rendered users/index.html.erb within layouts/application (Duration: 3.8ms | Allocations: 1537)
[Webpacker] Compiling...
[Webpacker] Compilation failed:
yarn run v1.22.4
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.


error Command "webpack" not found.

Completed 500 Internal Server Error in 1573ms (ActiveRecord: 0.9ms | Allocations: 23784)



ActionView::Template::Error (Webpacker can't find application in /sample-app/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
}
):
     6:     <%= csp_meta_tag %>
     7: 
     8:     <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
     9:     <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    10:   </head>
    11: 
    12:   <body>

app/views/layouts/application.html.erb:9

ググった結果以下のコマンドを実行で解決しました。
babelやpostceeなど各種設定ファイルの生成とyarn addを実行してくれるようです。
ただ設定ファイルはrails newした時点で存在していたのでyarn addする必要があるみたいですね。

yarn add @rails/webpacker@4.2.2 from "."
yarn add --dev webpack-dev-server from "."

$ docker exec bundle exec rails webpacker:install
    conflict  config/webpacker.yml
Overwrite /sample-app/config/webpacker.yml? (enter "h" for help) [Ynaqdhm] n
        skip  config/webpacker.yml
Copying webpack core config
       exist  config/webpack
   identical  config/webpack/development.js
   identical  config/webpack/environment.js
   identical  config/webpack/production.js
   identical  config/webpack/test.js
Copying postcss.config.js to app root directory
   identical  postcss.config.js
Copying babel.config.js to app root directory
   identical  babel.config.js
Copying .browserslistrc to app root directory
   identical  .browserslistrc
The JavaScript app source directory already exists
       apply  /usr/local/bundle/ruby/2.5.0/gems/webpacker-4.2.2/lib/install/binstubs.rb
  Copying binstubs
       exist    bin
   identical    bin/webpack
   identical    bin/webpack-dev-server
File unchanged! The supplied flag value not found!  .gitignore
Installing all JavaScript dependencies [4.2.2]
         run  yarn add @rails/webpacker@4.2.2 from "."
yarn add v1.22.4
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.13: The platform "linux" is incompatible with this module.
info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@2.1.3: The platform "linux" is incompatible with this module.
info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
[4/4] Building fresh packages...
success Saved 0 new dependencies.
Done in 49.21s.
Installing dev server for live reloading
         run  yarn add --dev webpack-dev-server from "."
yarn add v1.22.4
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@2.1.3: The platform "linux" is incompatible with this module.
info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
info fsevents@1.2.13: The platform "linux" is incompatible with this module.
info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
[4/4] Building fresh packages...
success Saved 1 new dependency.
info Direct dependencies
└─ webpack-dev-server@3.11.0
info All dependencies
└─ webpack-dev-server@3.11.0
Done in 4.67s.
Webpacker successfully installed ? ?

もう一度ブラウザから確認するとユーザー一覧画面が表示されていました!
ログを見るとwebpackでコンパイルされていることが分かります。

Started GET "/users" for 111.239.186.32 at 2020-06-22 00:24:31 +0000
Cannot render console from 111.239.186.32! Allowed networks: 127.0.0.0/127.255.255.255, ::1
   (17.7ms)  SET  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
Processing by UsersController#index as HTML
  Rendering users/index.html.erb within layouts/application
  User Load (8.9ms)  SELECT `users`.* FROM `users`
  ↳ app/views/users/index.html.erb:16
  Rendered users/index.html.erb within layouts/application (Duration: 10.6ms | Allocations: 731)
[Webpacker] Compiling...
[Webpacker] Compiled all packs in /sample-app/public/packs
[Webpacker] Hash: 15d1bb7b54cf6326b9ba
Version: webpack 4.43.0
Time: 2988ms
Built at: 06/22/2020 12:24:36 AM
                                     Asset       Size       Chunks                         Chunk Names
    js/application-9afcbb5693aa87623e69.js    124 KiB  application  [emitted] [immutable]  application
js/application-9afcbb5693aa87623e69.js.map    139 KiB  application  [emitted] [dev]        application
                             manifest.json  364 bytes               [emitted]              
Entrypoint application = js/application-9afcbb5693aa87623e69.js js/application-9afcbb5693aa87623e69.js.map
[./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
[./app/javascript/channels/index.js] 211 bytes {application} [built]
[./app/javascript/packs/application.js] 749 bytes {application} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
    + 3 hidden modules

Completed 200 OK in 5083ms (Views: 5073.4ms | ActiveRecord: 8.9ms | Allocations: 6105)

まとめ

勉強して分かったことを追記していく予定です。一旦ここまで。
誰かの参考になれば幸いです。

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

Dockerをnginxのリバースプロキシで制御する

概要 

一つのレンタルサーバーに複数のWebサイトをURLで制御する必要性があり、Dockerとnginxを用いて組んでみたという話

環境

レンタルサーバー : さくらのVPS(1GBプラン)
os : CentOS7
Docker version 19.03.12, build 48a66213fe
nginx version: nginx/1.16.1

Dockerの環境構築

Dockerを使ったこともない人が付け焼刃でDockerを組んでみたら意外と組めるものであったが...
数点はまったので書いておく

  • systemctlが使えない まず、普通にCentosのDockerをたてたが、systemctlが認識されない..... なんと、起動時に指定しないといけないらしい....(知らなかった....) ということで、Docker runするときに以下のコマンドを追加
--tmpfs /tmp --tmpfs /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro --stop-signal SIGRTMIN+3
  • portがかぶって複数のコンテナがたたない
    docker container runをするときに ipオプションで ホスト:コンテナの順で、指定する

Dockerをnginxのリバースプロキシで制御する

ここからは本題のDockerをnginxのリバースプロキシで制御したという話
今回の最終目標は以下の図のようにすることである
nginx.jpg

図の説明をすると、URLを基にDocker1~Docker4のどれかに接続する
今回はSSLについては記述しない
nginxの設定は/etc/nginx/conf.d以下に記述する
接続したいDocckerのコンテナ名でconfファイルを生成する
そこに以下を記述する

server{
    listen 80;
    server_name         <接続したいURL>;
    location / {
        proxy_pass    <DockerのIP>;
    }
}

この記述ができ次第nginxを再起動する

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

[2020Q2] Docker コンテナでの sshd 起動まとめ w/o init

はじめに

いくつかのディストリビューションにおいて sshd を起動するミニマムと思しき手順をまとめます。
今回想定しているのは init を使わないで直接 sshd を起動するケースです。

・・・っていう出だしなんですが、どちらかと言うと、鍵を誰が作っているのか、鍵が無かったらどうなるのか、イメージ配布するのに鍵を消したいけど自動的に再生成されるのか、みたいなことがポイントになってます。

対象ディストリビューション:

  • CentOS 8
  • Ubuntu 20.04 LTS (Focal Fossa)

CentOS 6 と 7 それから Ubuntu 16.04 LTS (Xenial Xerus) と 18.04 (Bionic Beaver) については、古い投稿にて扱っています。

そろそろみんな systemd けれど少しずつ微妙に違う

CentOS 8 も Focal も sshd は systemd が管理しています。例えば sshd の起動は下記で共通です。

# systemctl start sshd

CentOS はオンデマンドで鍵を生成する

伝統的に CentOS は sshd 起動時に自動的に鍵が生成されます。
もしイメージから鍵ファイルを消しておいたとすると、次回起動時に改めて生成されるということです。イメージ流用の観点からは、この方式は便利です。サンクス。

CentOS 7 と 8 では鍵生成用の systemd unit ファイルが独立して存在し、sshd.service に依存関係が設定されています。ただちょっと 7 と 8 では unit ファイル構成が違っています。

CentOS 7 はシンプル

/lib/systemd/system/sshd-keygen.service
[Unit]
Description=OpenSSH Server Key Generation
ConditionFileNotEmpty=|!/etc/ssh/ssh_host_rsa_key
ConditionFileNotEmpty=|!/etc/ssh/ssh_host_ecdsa_key
ConditionFileNotEmpty=|!/etc/ssh/ssh_host_ed25519_key
PartOf=sshd.service sshd.socket

[Service]
ExecStart=/usr/sbin/sshd-keygen
Type=oneshot
RemainAfterExit=yes

CentOS 8 は target を活用

/lib/systemd/system/sshd-keygen@.service
[Unit]
Description=OpenSSH %i Server Key Generation
ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key

[Service]
Type=oneshot
EnvironmentFile=-/etc/sysconfig/sshd
ExecStart=/usr/libexec/openssh/sshd-keygen %i

[Install]
WantedBy=sshd-keygen.target
/lib/systemd/system/sshd-keygen.target
[Unit]
Wants=sshd-keygen@rsa.service
Wants=sshd-keygen@ecdsa.service
Wants=sshd-keygen@ed25519.service
PartOf=sshd.service

ふーん、て感じですw

Ubuntu は1回だけ鍵を生成する

伝統的に Ubuntu では openssh-server パッケージの postinst スクリプトが鍵を生成しています。

# dpkg-reconfigure openssh-server

もしイメージから鍵ファイルを消しておいたとすると、次回起動時に sshd は正常に動きません。イメージ流用の観点からは、この方式は不便です。ざんねん。

そして、鍵が無いとき、sshd の挙動が Bionic と Focal で異なります。Bionic も Focal も sshd.serviceExecStartPresshd -t しているのですが・・・

Bionic は諦めない

Bionic は鍵が無くても sshd -t が成功扱い($? が 0)で、sshd が起動します。しかし鍵が無いと ssh クライアントから接続できません。
ここで sshd を起動したまま鍵を生成すると、ssh クライアントから接続できるようになります。なんだか強い子っぽい。

Focal は潔い

Focal は鍵が無いと sshd -t が失敗し、sshd は起動しません。
個人的には Focal の挙動が好きです。

ところで

Ubuntu では伝統的に sshd.service は ssh.service へのシンボリックリンクです。

実は

dpkg-reconfigure openssh-server では dsa 鍵が生成されません。なんでだろ。
ちょっとキモいけど今は無視します。

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

SpringBoot(Gradle)+MySQL8.0+CSVで初期DBインポート のアプリを Windows Dockerで動かす

目的

  • SpringBootで作ったJavaサーバ、DBはMySQLの8.0を使用する
  • サーバー起動時に、data.csvとinit.sqlを用意し、init.sqlからlocal infileコマンドを使用してdata.csvで初期DBをインポート
  • 他の人の環境で環境構築が大変なので、Dockerを使用することにした
  • 結構ハマったり苦労したので共有

Dockerでどうやるか

  • Dockerは1コンテナで1サービスが基本。JavaサーバコンテナとMySQLコンテナの2つを作り、docker-composeで連携させます

設定に必要な全体構成図

  • root
    • src/main/java
      • @Entity をもったクラスファイル
    • src/main/resources/application.yml
    • docker-compose
      • mysql
        • config/my.cnf
          • 権限は読み取り専用
        • initdb
          • data.csv
          • init.sql
        • Dockerfile
      • spring
        • Dockerfile
    • docker-compose.yml
    • build.gradle
  • image.png

How

  • @Entity をもったクラスファイル
    • GenerationType.AUTO ではなく、GenerationType.IDENTITY を使用してください
    • CSVを事前インポートした後に、新しくデータを追加すると同じIDが重複するという問題が発生します
@Entity
@Table(name="shohin")
public class MyData {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = true, unique = true)
    private Integer id;

  • application.yml
    • 上がローカルで回すとき、下がdocker-composeで回すときの設定です
    • ローカルのurlが長いのは、何かとエラーがでて対策を入れた結果です
server:
  port: 8081

---
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    password: hogehoge
    url: jdbc:mysql://localhost:3306/hogehoge_db?allowPublicKeyRetrieval=true&useSSL=FALSE&characterEncoding=UTF-8&serverTimezone=JST
    username: hoge
  jpa:
    database: MYSQL
    hibernate:
      ddl-auto: update

---
spring:
  profiles: docker-compose
  datasource:
    url: jdbc:mysql://dbserver/hogehoge_db
    username: hoge
    password: hogehoge
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
  • my.cnf
    • MySQL8.0から「load data local infile」コマンドがデフォルトオフになりました。local_infile=1で有効にします
    • また、Windows Proの環境のDockerならばこのままで問題ありませんが、Home環境だとパーミッション777のファイルはMySQL8.0が読みにいかないので読み取り専用にプロパティから変更しておきます
      • [Warning] World-writable config file '/etc/mysql/conf.d/my.cnf' is ignored
    • 文字コードも調整しておきます
[mysqld]
character-set-server=utf8
local_infile=1

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8
local_infile=1
  • init.sql
    • docker-compose up --build コマンドを叩いたとき、1回目に呼ばれるSQLです
    • IDには「id int AUTO_INCREMENT PRIMARY KEY」を指定してください。 @Entity で指定したカラムにしてください。
use hogehoge_db;
CREATE TABLE shohin(hogehoge);
load data local infile '/docker-entrypoint-initdb.d/data.csv' INTO TABLE sector FIELDS TERMINATED BY ',';
select * from shohin;
  • mysql/Dockerfile
FROM mysql:8.0
RUN touch /var/log/mysql/mysqld.log
  • spring/Dockerfile
    • jarのファイル名は、/build/libsの中のjarを指定してください
    • gradle assembleをすればできあがります
      • image.png
FROM openjdk:jdk-alpine
VOLUME /tmp
RUN mkdir /app
WORKDIR /app
ENV JAR_TARGET "hogehoge-0.0.1-SNAPSHOT.jar"
ENTRYPOINT ["sh","-c","java -jar -Dspring.profiles.active=docker-compose ./build/libs/${JAR_TARGET}"]
  • docker-compose.yml
    • データの永続化をすると、mysqlコンテナにデータが残らなくなり、後々CSVを読み込むとき面倒だったのでコメントアウト
    • mysqlコンテナを docker rm hogehoge 等で削除しない限りは残りますので安心してください
version: "3"
services:
  dbserver:
    container_name: mysql8.0_hogehoge_db
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: hogehoge_db
      MYSQL_USER: hoge
      MYSQL_PASSWORD: hogehoge
      MYSQL_ROOT_PASSWORD: hogehogehoge
    expose:
      - 3307
    ports:
      - 3307:3307
    volumes:
      # 起動スクリプト
      - ./docker-compose/mysql/initdb:/docker-entrypoint-initdb.d
      # MySQLの設定ファイル
      - ./docker-compose/mysql/config:/etc/mysql/conf.d
      # DBの永続化 アプリコンテナ、DBコンテナを消しても残り続ける。今回はCSVを読みたいのでコメントアウト。コンテナ消すとDB消えるから注意しろな!
      #- mysql_db:/var/lib/mysql
      # logの出力
      - ./log/mysql:/var/log/mysql
  app:
    container_name: hogehoge_app
    build: ./docker-compose/spring
    depends_on:
      - dbserver
    ports:
      - "8081:8081"
    volumes:
      - .:/app
    environment:
      # mysqlの接続設定 host:portはコンテナ名指定
      spring.datasource.driverClassName: "com.mysql.cj.jdbc.Driver"
      spring.datasource.url: "jdbc:mysql://dbserver/hogehoge_db"
      spring.datasource.username: "hoge"
      spring.datasource.password: "hogehoge"
# DBの永続化先
volumes:
  mysql_db:
    driver: local

  • build.gradle
    • dependenciesにmysqlを追加。以下サンプル
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
    compile 'org.springframework.boot:spring-boot-devtools'
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    runtime('mysql:mysql-connector-java')
}

gitで配布するとき

  • /build/libsの中のjarがデフォルトgitignoreに入ってると思いますが、gitで管理してください。このjarを元に回るため
  • readmeに、mysql\config のmy.cnfを読み取り専用にするように記載してください

dockerの準備

dockerで動かす

  • エクスプローラのファイルよりpowershellを管理者で起動(管理者権限があるユーザなら普通のpowershellでよい)
  • docker-compose up --build
    • その後右下に警告がでたら share it を2回押下。2回でるきがする
    • Ctrl Cで止められるが、怖いなら docker-compose up --build -d でバックグラウンド実行
      • down叩くまで動き続ける
  • 終わらせるときは同一フォルダで docker-compose down
  • 1回目はアプリ起動時にSQLが実行されておらず、起動に失敗すると思う。2回目に起動成功します

2回目以降のCSVインポート、既存DB削除等

  • mysqlのコンテナを削除して、もう一度docker-compose up --build image.png
  • こうしちゃってもいいかも
    * 全コンテナ停止: docker stop $(docker ps -q)
    * 全コンテナ削除:docker rm $(docker ps -q -a)
    * 全イメージ削除: docker rmi $(docker images -q)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

100日後にエンジニアになるキミ - 95日目 - 開発環境 - Docker について

昨日までのはこちら

100日後にエンジニアになるキミ - 94日目 - 開発環境 - 仮想化について

100日後にエンジニアになるキミ - 91日目 - 運用 - 監視について

100日後にエンジニアになるキミ - 90日目 - 開発 - CIについて

100日後にエンジニアになるキミ - 88日目 - データ - データ転送について

100日後にエンジニアになるキミ - 86日目 - データベース - Hadoopについて

100日後にエンジニアになるキミ - 76日目 - プログラミング - 機械学習について

100日後にエンジニアになるキミ - 70日目 - プログラミング - スクレイピングについて

100日後にエンジニアになるキミ - 66日目 - プログラミング - 自然言語処理について

100日後にエンジニアになるキミ - 63日目 - プログラミング - 確率について1

100日後にエンジニアになるキミ - 59日目 - プログラミング - アルゴリズムについて

100日後にエンジニアになるキミ - 53日目 - Git - Gitについて

100日後にエンジニアになるキミ - 42日目 - クラウド - クラウドサービスについて

100日後にエンジニアになるキミ - 36日目 - データベース - データベースについて

100日後にエンジニアになるキミ - 24日目 - Python - Python言語の基礎1

100日後にエンジニアになるキミ - 18日目 - Javascript - JavaScriptの基礎1

100日後にエンジニアになるキミ - 14日目 - CSS - CSSの基礎1

100日後にエンジニアになるキミ - 6日目 - HTML - HTMLの基礎1

本日はにコンテナとDockerについてです。

コンテナについて

仮想化が何たるかは前回を見ていただければ良いかと思います。

仮想化と言えば一昔前はゲストOSを用いた仮想化がほとんどでした。
最近ではコンテナと呼ばれる技術が出てきています。

image.png

参考:https://pfs.nifcloud.com/navi/tech/container_virtualization.htm

従来の仮想化では1台の物理マシン上にはホストOSが起動し
そのOS上で複数のゲストOSが稼働していました。

しかし仮想化ソフトを使用した仮想化環境にもデメリットがあります。
複数OSを利用することによる性能劣化や
仮想化ソフトウェアの介在による複雑化などがあります。

そこで注目されているのがコンテナです。

コンテナホストOS上にアプリケーションの起動に必要な
アプリケーション・ライブラリ・設定ファイルなどをひとまとめにした
コンテナを作成しコンテナエンジン上で動作させる技術のことです。

通常の仮想化と似ている点もありますが、大きく異なる点として
ゲストOSを用いないということです。

コンテナではゲストOSを起動することなく
アプリケーションの実行環境を構築することが可能になるため
仮想マシンに比べて少ないリソースで済むのが特徴です。

このようなコンテナ技術を牽引するソフトウェアとしては
dockerと言うものがあります。

Dockerについて

image.png

Dockerは2013年頃に発表されたコンテナ仮想化を用いて
アプリケーションを実行するためのソフトウェアです。

Docker

Dockerはコンテナ仮想化を用いたOSレベルの仮想化により
環境自体をアプリケーションと同じようにコード(イメージ)として管理可能にし
アプリケーションの素早い提供を実現します。

Dockerはミドルウェアのインストールや各種環境設定をコード化して管理します。
ソフトウェア開発で実施されてきた構成管理や自動化などを
サーバーの各種設定やミドルウェアのインストールなどにも応用できます。

これらにより、以下のような利点が生まれます。

・ファイルを共有することで、誰でも同じ環境が作れる
・作成した環境イメージを配布しやすい
・スクラップ&ビルドが容易

データ分析の観点から言えば、誰でも同じ環境を作る利点が大きいです。
Python言語を用いた分析環境ではライブラリのバージョン差異が生まれやすく
分析環境が異なることでのトラブルが発生しやすいです。

環境の統一化をすることで軽減することができます。

また開発環境の構築をする時間の短縮化にもつながります。
新規の案件に参画した場合、開発環境の構築に1日かかってしまうこともあります。
それが配布されたイメージ1つで済みます。

当然Dockerの学習コストを支払わなければならないのですが
今後はコンテナを利用した開発が増えていくため、抑えておくメリットは大きいです。

また最近ではコンテナを管理するオーケストレーションツールを使うことで
より運用が楽になって来ています。

最近ではオーケストレーションツールとしてKubernetesが注目を浴びています。

参考:https://kubernetes.io/ja/docs/concepts/overview/what-is-kubernetes/

まとめ

10年以上前は仮想化が流行った時期がありましたが
そこから少し経って今ではコンテナと言う技術が流行ってきています。

コンテナを扱うことのできるdockerの利用も高まってきており
開発者のニーズも高まってきています。

これからの開発のスタンダードになると思いますので
抑えておいても損はないかと思います。

明日はもう少し詳しく紹介していきます。

君がエンジニアになるまであと05日

作者の情報

乙pyのHP:
http://www.otupy.net/

Youtube:
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter:
https://twitter.com/otupython

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

「WordPress」で「docker-compose」の理解を深めた勉強会

概要

現場でdocker-composeを使っており、復習も兼ねて勉強会で取り上げてみました。まず、勉強会にはdockerやコンテナの概念が微妙な方もいらっしゃったため、まずはWordPressを使ってコンテナに接続して、まずは触れてもらいながら学習してもらうことにしました。その学習内容を記事にまとめさせていただきます。

勉強会自体はかなりボリュームになってしまい上記は前半の初心者向けの内容となります。なお後半はdocker-composeNode.js(Express)PostgresSQLを使用した簡単なサービスを作成しました。こちらは初めてチャレンジしたモノで、それはそれで面白かったのでそちらの内容も別の記事にて投稿予定です。

それでは以降からは学習内容のまとめになります。

そもそもdockerって何?コンテナって何?

VirtualBoxとの比較がわかりやすかったりします。以下はさくらナレッジの記事を引用です。

VirtualBoxなどの仮想マシンでは、ホストマシン上でハイパーバイザを利用しゲストOSを動かし、その上でミドルウェアなどを動かします。それに対し、コンテナはホストマシンのカーネルを利用し、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができます。

https://knowledge.sakura.ad.jp/13265/

と説明を受けても若干イメージしづらいのが正直なところです。以下のような現実での例で説明してみました。

  • VirtualBoxなどの仮想マシン:一軒家
  • Dockerなどのコンテナ:マンションの1室

あと、仮想マシンは触ったことがある人が多かったので以下のような説明もしました。

  • 仮想環境をアプリケーションごとに分けたいな~と思います~
  • そのときに共通で使用できそうなOSなどを新しく別に作るのはダルいよね~
  • アプリケーションの部分だけ別の環境として作りたいよね~
  • それを実現したのがdockerやコンテナだと思います~

dockerのコンテナってどうやって作られているの?

まずはdocker-hubにあるOfficialのイメージをみてもらいました。いろんなサービスのコンテナのイメージがあり、自分が使いたいプログラミング言語やデータベースのイメージを使用することですぐに動作できる環境を準備できます。

  • 例:Node.jsを使いたい!
    • Node.jsのイメージを使えばNode.jsを動作できる環境を作れる!

そもそもdockerのコンテナやイメージってどうやって作られているかという話ですがほとんどがDockerfileになると思います。実はOfficialイメージから各バージョンごとのDockerfileを確認することができます。

もし独自にコンテナあるいはイメージを作成したい場合にはDockerfileを作ればよいわけです。また既存のイメージから拡張したい内容をDockerfileに追加することも可能です。

複数のサービスを連携してこそのコンテナ

1つのサービスを実行するだけだと普通の仮想マシンと変わりません。やはりコンテナ同士で連携するサービスを構築することで真価が出ると思います。口だけでいうと伝わらないと思ったので、お試しにdocker-composeWordPressを実行してもらいました。

docker-composeって何?

1つだけのサービスならDockerfileだけで問題ありませんが、複数のコンテナの連携になるとdocker-composeが良いです。

WordPressって何?

WordPressPHPで作られているCMS(コンテンツ管理システム)でサイトの内容を保存するためにMySQLを使用します。詳細については割愛させていただきますが、「PHPが動作する環境」と「MySQLのデータベース」を準備する必要があります。今回は必要な2つの環境をdocker-composeで構築します。

docker-composeでWordPressを動かす

docker-compose.yml

version: '2'
services:
   db:
     image: mysql:5.7
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     image: wordpress:latest
     depends_on:
       - db
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress

実行内容

docker-compose build
docker-compose up -d

実行内容に関する説明

まずは実行内容のbuildでコンテナを作成します。実のところ今回の場合は特に意味はありません。ただし自分でDockerfileを作成した場合はbuildした方がよいです。直接upした場合でもイメージがなければbuildが実行されます。

ここで気を付けてほしいのが以前にbuildしたコンテナがある場合はそのコンテナを実行します。例えばDockerfileで読み込むプログラムを更新した場合でもupだと以前のコンテナを実行するので、更新したプログラムが取り込まれないまま実行されます。新しい状態を作り直す意味でもbuildをすることを意識しておいて損はありません。

docker-compose -d の -d って何?

-dをつけるとバックグラウンドで動作します。逆につけない場合は実行したコンソールでコンテナが稼働するため、実行したコンソールでは他の作業ができなくなります。もし-dをつけ忘れて停止させたいよ~ってなった場合は、Windowsの方はCtrl+CMacの方はControl+Cで停止させることができます。

docker-compose.ymlに関する説明

注意すべきポイントを抜粋して説明します。

WordPressのポート設定

まずはポートの設定を確認します。

   wordpress:
   ~省略~
     ports:
       - "8000:80"

右がコンテナのポートで左がホストのポートです。ホストというのは今自分が操作しているでありコンテナを動かしている端末です。この設定ではWordPressのコンテナのポート80を、ホストのポート8000に転送しています。これはWordPress自体がデフォルトの設定ではポート80に転送されており、それをホストのポート8000に転送しています。
この設定により自分の端末(ホスト)のブラウザから http://localhost:8000 でアクセスすることができます。

最初の頃は何がどうポート転送されているか把握しづらいのが正直なところです。このシンプルな構成でもWordPressのデフォルトのポートが80であることを知らなければ、なぜ8000:80になっているかわからないまま進むことになるので、1つずつ説明しながら理解を深めてもらいました。

環境変数を確認する

環境変数を確認します。

   db:
     ~省略~
     environment:
       MYSQL_ROOT_PASSWORD: wordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     ~省略~
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress

元のコンテナイメージですでに使用されている環境変数を上書きすることができます。

今回はMySQLというデータベースを使用しており、データベースのパスワードの場合はMYSQL_PASSWORDという環境変数を設定することでパスワードの内容を上書き・変更することができます。使うコンテナのイメージごとに設定されいている環境変数は異なりますので調べる必要はあります。環境変数の調べ方ですがサンプルなどで見つかったりするのと、ちゃんと調べる場合にはコンテナイメージのリポジトリなどを確認するとよいと思います。

今回使うMySQLのコンテナイメージのリポジトリを調べてみるとdocker-entrypoint.shMYSQL_PASSWORDを使っていることが確認できました。

https://github.com/docker-library/mysql/blob/bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061/5.7/docker-entrypoint.sh

MySQLの場合はMYSQL_ROOT_PASSWORDなどの環境変数を設定することで、データベース・ユーザーの作成などを自動的に行ってくれるようです。これらの設定はdockerのコンテナの中に入ったときに改めて確認します。

コンテナの中に入ってみる

コンテナの中に入る

コンテナの中に入ってみます。今回はデータベースのコンテナに入ります。

docker-compose exec db bash

もしWindowsの方で以下のようなメッセージが表示された場合は、winptyを頭につければコンテナに入ることができます。

the input device is not a TTY.  If you are using mintty, try prefixing the command with 'winpty'

winpty docker-compose exec db bash

コンテナ内のデータベース(mysql)に接続する

コンテナの中に入った後は以下のコマンドを実行します。
(root@eb769a915d4d:/# は入力しないでください)

root@eb769a915d4d:/# mysql -U wordpress -D wordpress -p

これはMySQLのデータベースに接続しようとしています。-Uはユーザー名、-Dはデータベース名を示し、-pでパスワードを使用します。ここの設定はdocker-compose.ymlの環境変数で設定したモノになり、ユーザー名などを忘れてしまった場合にはdocker-compose.ymlを確認するとよいと思います。
この実行後パスワードを入力するよう求められるのでwordpressと入力します。

Enter password:

パスワードは入力中の内容が他の人から見られないよう入力したい内容が表示されません。間違ってしまった場合(間違ったような気がした場合)はbackspaceで消しきるか、Ctrl+Cなどで抜けてもう一度MySQLの接続からやり直してみてください。パスワードの入力が正しくできていればデータベースに接続できているはずです。

データベースのテーブルを確認する

テーブルの確認をしてみます。
(mysql> は入力しないでください)

mysql> show tables;

まだWordPressの設定されていないのでテーブルは何も作成されていない状態です。

Empty set (0.00 sec)

データベースから抜ける & コンテナから抜ける

以下のコマンドでデータベースから抜けます。
(mysql> は入力しないでください)

mysql> \q

データベースから抜けるとコンテナの中に入っている状態になりますので以下のコマンドでコンテナから抜けます。
(root@eb769a915d4d:/# は入力しないでください)

root@eb769a915d4d:/# exit

WordPressを設定する

自分のパソコンのブラウザを開いて http://localhost:8000/ に接続します。
接続したら日本語を選択して画面を参考にしながら設定しましょう。
今回はWordPressで何かサイトを作るわけではないので適当に設定します。

WordPressの設定

WordPressの設定

image.png

無事にWordPressのインストールが完了できたら、改めてデータベースに接続してみます。

WordPressインストール後にデータベースに接続する

いちいちコンテナの中に入ってからデータベースに接続するのは面倒だったりします。以下のコマンドで直接データベースに接続することも可能です。
(the input device is not a TTY. のメッセージが表示されたら頭にwinptyをつけてください)

docker-compose exec db mysql -U wordpress -D wordpress -p

実行できた場合はパスワードを求められると思いますのでwordpressと入力します。
データベースに接続できたらテーブルを取得してみましょう。

mysql> show tables;
+-----------------------+
| Tables_in_wordpress   |
+-----------------------+
| wp_commentmeta        |
| wp_comments           |
| wp_links              |
| wp_options            |
| wp_postmeta           |
| wp_posts              |
| wp_term_relationships |
| wp_term_taxonomy      |
| wp_termmeta           |
| wp_terms              |
| wp_usermeta           |
| wp_users              |
+-----------------------+
12 rows in set (0.00 sec)

WordPressのインストールによって必要なテーブルが作成されていることが確認できます。更にユーザーのテーブルを確認してみましょう。

mysql> select * from wp_users \G ;
*************************** 1. row ***************************
                 ID: 1
         user_login: test
          user_pass: $P$BTqvOi17OHGROkW0ukBzJk0W356aVu0
      user_nicename: test
         user_email: test@test.com
           user_url: http://localhost:8000
    user_registered: 2020-06-23 07:25:13
user_activation_key:
        user_status: 0
       display_name: test
1 row in set (0.00 sec)

インストール時に設定したユーザー情報があることが確認できました。
確認できたら\qでデータベースから抜けてください。

コンテナを停止させる

以下のコマンドでコンテナを停止させます。

docker-compose down

これでコンテナを停止させることができました。ただし停止するとデータベースの状態が初期化されWordPressの設定などはなくなります。コンテナのデータの永続性については注意する必要があります。永続化させたい場合はdocker-compose.ymlvolumesの設定を行うなど少し工夫が必要になります。今回は学習内容が多くなってしまうので割愛させていただきます。

学習内容をまとめてみた結果

内容自体は既存のWordPressというサービスを使ってみるだけのカンタンなモノですがdocker-composeを理解しながらとなると学習量は多いと感じました。今回の勉強会ではかなりボリュームがあるとの感想をいただいたので、少し様子を見ながら勉強会の内容を分けていくことも検討しようかなと思います。
といいながらも何か理解しながら作り出すとドンドン進みたく性分なので、そこらへんを上手く付き合いながら取り組んでいきます。

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

AWSのEC2内でDockerコマンドを使えないときの対処法【目的:load遂行】

はじめに

ローカルにあるファイルをEC2へ送りたかったのですが、dockerコマンドが使えませんでした。

[ec2-user@ip-xxx-xx-xx-xx ~]$ docker load < dockerfiles.tar
-bash: docker: command not found

色々試行錯誤しながら、EC2環境にdockerをインストールすることで解決できたので共有したいと思います。

手順

[ec2-user@ip-xxx-xx-xx-xx ~]$ sudo yum install -y docker

EC2環境にDockerをインストール。EC2環境で上記コマンドを叩きます。「完了しました!」が最後に表示されたら成功。

[ec2-user@ip-xxx-xx-xx-xx ~]$ sudo service docker start

dockerを起動させます(EC2インスタンスを再起動させたときはDockerが停止してしまうので、インスタンスを再起動したときは毎回このコマンドを使います)。

さあ、もう使えるだろうと思い、手始めにdockerイメージの一覧でも見るかとコマンドを叩くと

[ec2-user@ip-xxx-xx-xx-xx ~]$ docker images
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%43j432jd34fFdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied

エラーが発生。

dockerグループにec2-userを追加してなかったんですね。では追加します。

[ec2-user@ip-xxx-xx-xx-xx ~]$ sudo usermod -a -G docker ec2-user

そして一度EC2から抜けます。

[ec2-user@ip-xxx-xx-xx-xx ~]$ exit

またEC2内に入ります。

nakajimakoutanoMacBook-ea:Desktop nakajimakouta$ ssh -i xxxxxxx.pem ec2-user@ホスト名

そしてdocker imagesコマンドを叩くと無事に動きました。

[ec2-user@ip-xxx-xx-xx-xx ~]$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

本来の目的であった「ローカルにあるファイルをEC2へ送りたい」をできるかどうか試すと

[ec2-user@ip-xxx-xx-xx-xx ~]$ docker load < Dockerfile.tar
Loaded image ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[ec2-user@ip-xxx-xx-xx-xx ~]$ docker run -it xxxxxxxxxxxxx sh
/ # $ ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    Dockerfile←これ   tmp    usr    var

成功です。無事にDockerfileをEC2内へ送ることができました。

参考記事

AWSのEC2でDockerを試してみる

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

Docker-compose ~volumeの罠~

はじめに

 初投稿です。白菜と申します。プログラミングが趣味のしがない大学生です。先日コードを書いている最中に深めなツボにハマり、色々調べても関連する情報が出てこなかったので投稿させていただきます。

何が起こったのか

 windowsを使っておりまして、wsl2が正式に導入されたと聞き、wsl2上でDocker-desktopを動かしてみようと思い立ちました。環境を整えてかれこれ一か月ほど遊んでいて、己のPCの環境を汚さずに様々な言語に触れられて、激アツやんと思っておりました。dockerで立ち上げたコンテナにvscodeのRemote Developmentを利用して接続し、コンテナ内でコードの編集・デバッグを行っていました。

しかし、問題発生

 それはある日の暮れ、羅生門の下で雨やみを待ちながらコードを書いていた時のことでございます。springbootとかいう何某かがなんかとてもすごいつよいと聞いたので、試しておりました。日本語の公式チュートリアルのいくつかを軽く実装し、springMVCの基礎くらいはカンニングせずに書けるようになりました。調子に乗ってきたので、MySQLと連携させてデータベース処理やってみようと思い、dockerで環境を作りました。具体的には、

  • javaコンテナ
  • MySQLコンテナ
  • phpmyadminコンテナ(データベース管理で楽するため)

の三つをdocker-composeで一つのネットワークとして作りました。ついでに書いたコード保存しときたかったので、volumeでテキトーなディレクトリをjavaコンテナ上にマウントしました。
 しかしいざコードを書いてみると、データベースとの連携がうまくいきません。デバッグの度にデータベース接続エラーを吐き出します。コード自体はチュートリアルのほぼコピペなので、動かないはずがないのです・・・。これはコードじゃなくてdockerに原因があるんじゃないか?

症状

 上記以外にも、他のコンテナでも似たような症状が発生しました。以下はその一覧です。

  • MySQLとの連携がうまくいかない
  • というかおそらく連携用の設定ファイルの編集が反映されていない
  • 手動で反映させたら上手くいった
  • htmlを作成してコントローラと紐づけたのに、Not Foundと言われる
  • React環境を作ったが、yarn startに一分以上かかる
  • yarn start後、ファイルを編集してもブラウザに反映されない

共通しているのはファイルの編集・作成が反映されないということでした。

解決

 色々実験してみたところ、dockerのvloumeに問題があるという結論に達しました。windows上のファイルをvolumeに指定した時に、volume内のファイルの変更がリアルタイムで反映されなくなるようです。なのでvolume指定しなけりゃいいというのも一つの解決ではあるのですが、コードを永続的に保存しておきたい場合、いちいちwindows上にコピーして持ってくるのは手間です。
 
 volumeを使いつつ解決する方法があります。そもそもdocker for windows公式には以下のような記述があります。

Store source code and other data that is bind-mounted into Linux containers (i.e., with docker run -v :) in the Linux filesystem, rather than the Windows filesystem.

「volumeマウントするファイルは、Windows上じゃなくてLinux上に置いといた方がいいよ!」

・・・・・・すみませんでした。
ちらっと見たことはあったんですけど、マウント自体はちゃんと機能してたし、別にWindows上でもよくね?と思っていたんです。まさかこんな変な不具合が出るとは思ってもいなかったんです。

 というわけで、wsl2のLinux上に作ったディレクトリをマウントしてReact環境を作り直したら解決しました。yarn startが20秒になったし、コードを変更したら逐一反映されるようになりました。Reactおもしれえ。

終わりに

 結論、volumeでマウントするディレクトリはLinux上に作っておいた方がいいと思います。開発してる人たちが言ってるんだから多分間違いないです。我流でオラオラしようとしていた私が悪かったです。すみませんでした・・・。
 公式ドキュメントはしっかり読まなきゃダメてことですね。

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

Docker+Rails+Vueの環境を迷わず作成するステップ

最近勉強したDockerを使って、railsとVueの環境構築をしてみました。
いろいろ検索してやってみたものの、多くのエラーと向き合う日々を迎えることに...(それでもだいぶ理解は深まった?)

この記事では

  • とにかく開発環境だけ欲しい
  • 自分の忘備録

を主な対象として、最速でDokcer+Rails+Vueの環境を作成するステップをご紹介します?!
(多分エラーは出ないはず。。。)

STEP1. 4つのファイルを作成しよう

まずは作業するフォルダ(ディレクトリ)に

  • Dockerfile
  • docker-compose.yml
  • Gemfile
  • Gemfile.lock

の4つのファイルを作成します。内容はそれぞれ以下のようにします!

Dockerfile
FROM ruby:2.5.3

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get update && \
    apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev

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

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - 
RUN apt-get install -y nodejs npm && npm install n -g && n 10.17.0

RUN yarn add node-sass

RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

docker-compose.yml
version: '3'
services:
    web:
        build: .
        command: bundle exec rails s -p 3000 -b '0.0.0.0'
        volumes:
            - .:/app
        ports:
            - 3000:3000
        depends_on:
            - db
        tty: true
        stdin_open: true
    db:
        image: mysql:5.7
        volumes:
            - db-volume:/var/lib/mysql
        environment:
            MYSQL_ROOT_PASSWORD: password
volumes:
    db-volume:

Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.3'

作業しているディレクトリで
touch Gemfile.lock
を実行すると、からのGemfile.lockが作成されます。

?バージョンやdbのパスワードなどはよしなにご変更ください〜。

STEP2. rails newをする

今回はdockerコンテナ上でrailsアプリを作成するので、コマンドラインにそのまま
rails new
を打つのは正しくありません。
(僕のPCはローカルにrailsを入れていないため、rails newを打っても「そのコマンド知りませんけど?」って怒られます。)

dockerコンテナ上でコマンドを実行したい場合は
docker-compose run
コマンドをつかえばOKです?。

下記コマンドを実行します。
docker-compose run web rails new . --force --database=mysql --webpack=vue --skip-coffee

このコマンドにより、

  • dbはMySQLを明示的に指名
  • Vueを後入れしなくて済む(後入れでエラーが結構出た記憶)
  • coffee使わないので、coffee関連のファイルを作成しない

という付加価値をつけた状態で、rails new しています。

?あと2ステップ!

STEP3. database.ymlを作成する

STEP2の読み込みが完了したら、config/database.ymlが作成されているはず。
このファイル内にある「default」の内容を少し書き換えます。

config/databese.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password   ←docker-compose.ymlで指定したdbのパスワード
  host: db         ←docker-compose.ymlのservicesで指定したdbの名前

STEP4. docker-compose up --build

ここまでできたら、
docker-compose up --build
を実行します!

少し時間がかかりますが、読み込みが終わったあとにローカルホストにアクセスしてみると、「Yay! You’re on Rails!」の画面が表示されましたか?
もしそうなら成功です!

だがしかしBut。。。?
僕の場合は、「ERROR -- : Unknown database 'app_development' (ActiveRecord::NoDatabaseError)」が表示されました。

僕と同じという方は、
docker-compose exec web rails db:create
をしてあげればOK!

docker-compose down
をした後に、再度
docker-compose up --build
をすれば立ち上がるはずだぞ!お疲れ様でした?

最後に

コロナ禍でWebエンジニア転職を頑張っていますが、railsポートフォリオだけだとお祈りしかされません。
AWSの冗長構成でインフラ構築しててもお祈りです。

そこでRails+VueのRESTfulAPIを使ったアプリ(いわゆるSPA)を追加で作ったところ最終面接までは行けるようになりましたが、それでもやっぱり大変です。

もしWebエンジニア転職が大変だぁという方が読んでくれていたら、これだけは言いたいです。
諦めずに頑張ろうね!!!!

以上、お粗末様でした。

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

"docker push"で"denied: requested access to the resource is denied"のエラーに遭遇したら

ググると、下記のサイトがヒットしますが…

いずれにも「docker loginしたらpushできる」と書いていますが、これで解決できない人が続出していて、いずれのスレッドにも終わりが見えない状況です。

この問題の解決方法ですが、push先のディレクトリ・プロジェクトのpush権限を自分が持っていないことが考えられます。
私の場合は、adminからpush権限を付与してもらうことで、このエラーを解決できました。

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

rJavaをR3.6環境のLinuxにインストールする。

rJavaをR3.6環境のlinux にインストールする
というか、そういうDockerImageを作るDockerfileを書く必要があったが、
結構エラーがでて詰まった。
ネットを探してもドンピシャがなかなか出てこなかったで、メモ。

#rJavaインストールのための準備
RUN apt-get update && apt-get install -y openjdk-8-jdk
RUN R CMD javareconf

# install packages(DB接続用追加)
RUN R -e "install.packages(c(\
'rJava' \
), repos='https://cloud.r-project.org/')"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CUDA on WSL導入時,Docker Desktop for Windowsとケンカしてしまった件

CUDA on WSLの公開と,前回紹介したNeural Source Filter実装がLinux環境でしか動作しないことを受けて,本格的に環境構築を行うことにした.ところが,

docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"process_linux.go:385: running prestart hook 1 caused \\\"error running hook: exit status 1, stdout: , stderr: exec command: [/usr/bin/nvidia-container-cli --load-kmods configure --ldconfig=@/sbin/ldconfig.real --device=all --compute --utility --require=cuda>=9.0 --pid=8276 /var/lib/docker/overlay2/b956d7f169cca157457e107ee8c99a050c33199ded8f4fa4d68e3ace612c6d0c/merged]\\\\nnvidia-container-cli: initialization error: driver error: failed to process request\\\\n\\\"\"": unknown.

と言った感じでWSL側からGPUの認識ができず苦労した.なので,その解決法をメモしておく.

CUDA on WSLとは

Windows Subsystem for Linux(WSL)でCUDAを利用したPGU計算ができる仕組み.今まではWSL上にCUDAをインストールして行っていたそうだが,CUDA on WSLを使えばWindows側にGPUドライバーをインストールすればOK.Gigazineの記事がわかりやすかったので詳しく知りたい方はこちらを参照

環境構築

はじめに

もしCUDA on WSLの導入のみを考えている方は,必ず公式の手順のみに従って欲しい.以下に記すのは,導入につまずいた状況の整理であるため,上記のエラーが発生している人は,以下を見て同じような構築を行ってないかチェックして欲しい.

WSL上にAnaconda導入

まず,WSL上でPythonを動かせるようにして,ついでにPyCharmから実行したいなと思いそちらの構築から開始した.以下が参考にしたサイトである.

また,WSLのUbuntuにはgcc等がインストールされていないため,そちらのインストールも行った.

Docker Desktopの導入

あと,CUDA on WSLでDockerが必要というのを見たことと,Windows10 homeでも利用可能になったので嬉しくなり,Docker Desktop for Windowsをインストール.これが元凶

CUDA on WSLの導入

CUDA on WSL構築にあたって参考にしたサイト

解決方法

公式で,WSL上のUbuntuにdockerをインストールする項目がある.

$ curl https://get.docker.com | sh

このUbuntu上のDockerと,Docker Desktop for Windowsが別に動作していることに気づき,もしかすると2つのDockerが競合しているのでは?と考えた,そこで,Docker Desktop for Windowsが自動的に起動しないように設定,念の為NVIDIA Container Toolkitのアンインストールを行ってから再起動をして,再びDocumentation通りにインストール,CUDAサンプルの実行を行うと

Run "nbody -benchmark [-numbodies=<numBodies>]" to measure performance.
-fullscreen       (run n-body simulation in fullscreen mode)
-fp64             (use double precision floating point values for simulation)
-hostmem          (stores simulation data in host memory)
-benchmark        (run benchmark to measure performance)
-numbodies=<N>    (number of bodies (>= 1) to run in simulation)
-device=<d>       (where d=0,1,2.... for the CUDA device to use)
-numdevices=<i>   (where i=(number of CUDA devices > 0) to use for simulation)
compare          (compares simulation results running once on the default GPU and once on the CPU)
-cpu              (run n-body simulation on the CPU)
-tipsy=<file.bin> (load a tipsy model file for simulation)
NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.
> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
MapSMtoCores for SM 7.5 is undefined.  Default to use 64 Cores/SM
GPU Device 0: "GeForce RTX 2080 Ti" with compute capability 7.5
Compute 7.5 CUDA device: [GeForce RTX 2080 Ti]
69632 bodies, total time for 10 iterations: 119.463 ms
= 405.868 billion interactions per second
= 8117.351 single-precision GFLOP/s at 20 flops per interaction 

動いた!!!
そういえば,待ってました CUDA on WSL2にも

この時、

WSL DETECTED: We recommend using Docker Desktop for Windows.

なんて言われますが、無視。

って書かれてたのを考えると,Docker Desktop for Windowsが動いてるとエラー吐くのは当然だなと納得した.

ちなみに

試しに,CUDAサンプル実行後に,Docker Desktop for Windowsを起動して同じサンプルを実行するとエラーが出る.また,Docker Desktopを終了してもエラーが出てしまい,Windowsを再起動しないとサンプルが動かせなくなった.なので,CUDA on WSLを使用する方は,Docker Desktopのアンインストールをしてしまっても良いのかもしれない(保証はしない)

Pytorchで計算をした感想

そもそもPytorchがCUDA11に非対応なのだが,面白そうなので動かしてみたところ,GPUでの計算は可能だった.しかし,どこが原因か不明であるが,1iterの計算がけっこう重く実用的ではない.試しにWindows環境で同じプログラムを実行したところCUDA10.1のときと同じ速度で計算が行えるため,Python環境で直接実行するにはまだまだ改善の余地があるのでは,と思った.そもそもDockerの仕組みすら曖昧なペーペーであり,自分の知識不足である可能性が高いので,もっと勉強したい所存.

まとめ

  • まだWSLの構築もしていない人は,CUDA on WSLのDocumentation通りに環境構築すべし
  • Docker Desktop for Windowsをインストールしている場合は,自動的に起動しないよう設定またはアンインストール
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker内のJooby(Kotlin × Gradle)をホットリロードさせながらIntelliJでRemoteDebugする

1-やること

タイトルの通り、DockerやIntellijの実行構成を含んだ全部入りリポジトリはこちら
Githubリポジトリ

2-完璧でないところ

・後述のjoobyRunを行った後、RemoteDebugを走らせないとホットリロードが動きません。
 →裏でport5005に対する接続待ちが起きてる??

・ブレークポイントで止まっている間はホットリロードが効きませんでした。

3-ポイント

・Docker内のJDKとIntelliJのJDKは合わせよう!
 →この記事ではamazoncorretto:11でそろえてます。

・docker-compose.yml: environmentに環境変数GRADLE_OPTSを指定

docker-compose.yml
version: '3'

services:
  app:
    shm_size: 4096m
    build: "./build/app"
    ports:
      - '8015:8080'
      - '5005:5005'

    volumes:
      - "./app:/app"

    environment:
      TZ: 'Asia/Tokyo'
      GRADLE_OPTS: '-Dorg.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005'

    working_dir: /app

    cap_add:
      - SYS_ADMIN
    security_opt:
      - seccomp:unconfined
    tty: true

・IntelliJにdocker-compose用の実行構成を作成
image.png

・RemoteDebug用の実行構成を作成
 Command line arguments for remote JVMの内容が先述の「GRADLE_OPTS」とイコールになるはず
image.png

・docker-composeの起動構成を実行→コンテナ内部でjoobyRun実行
image.png

コマンド実行
./gradlew joobyRun

image.png

・RemoteDebugの起動構成を実行→適当に置いたブレークポイントを通るパスにアクセス
image.png

以下にアクセス
http://localhost:8015/

ブレークポイントで止まる
image.png

ソース修正するとホットリロードが行われる
※ブレークポイントで処理停止させている場合は勿論効かないです。(重要なので二度目)
image.png

4-おわり

・dockerでローカルを汚さないかつ、IntelliJの強力なアシスト+joobyRunでのホットリロード+RemoteDebug
 LL言語並みに高速でリコンパイルされるわけでないですが、これで開発がとても楽になります。

・後述のjoobyRunを行った後、RemoteDebugを走らせないとホットリロードが動きません。
 →裏でport5005に対する接続待ちが起きてる??

回避策としてはRemoteDebugが不要な時はdocker-compose.ymlのGRADLE_OPTSをコメントアウトすれば良いです。

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

Docker初心者に立ちはだかるエラー

下記サイトからDockerを学んでいるときに出会ったエラー
https://tech-lab.sios.jp/archives/19191

Dockerイメージを作ろうと
docker buildをした際に起こりました。
Sending build context to Docker daemon
がひたすら続くというエラー。。
下のようなエラーも出たりで、、

ERRO[0529] Can't add file /Users/shingo/Library/Application Support/Code/1.45.1-main.sock to tar: archive/tar: sockets not supported 
ERRO[0529] Can't add file /Users/shingo/Library/Application Support/Code/1.45.1-shared.sock to tar: archive/tar: sockets not supported

一向にイメージを作れる気配もなく、中断しました。

色々と調べた結果
https://ytooyama.hatenadiary.jp/entry/2018/04/06/003019
この記事を発見!

Dockerファイルをホームディレクトリに作成し、docker buildを実行していたので
DockerクライアントからDocker daemonに対して、ホームディレクトリ配下のファイルを全て転送していたようです。
~/working/dockerディレクトリを作成し、そこにDockerfile「だけ」を作成しました。
その後
buildが成功しました。

なんとも簡単な、、

PC
余計な仕事させてごめんよ!!

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

リモートデバッグ可能なNginx, Spring Boot, MySQLの開発環境をDockerで作った

前置き

最近、WebサイトをSpring Bootで開発しています。以前に投稿した記事のような開発環境が欲しくなってきましたので調査しました。前回とほぼ同じ形式で執筆します。

動作環境

   
OS macOS Catalina 10.15.5
Docker docker desktop community 2.3.0.3 (45519)
Spring Tool Suite Version: 4.5.1.RELEASE

Spring Bootプロジェクト

InteliJ + Kotlin + gradleとしたいところですが、現在携わっている環境に近い構成でやっていこうと思います。
モダンJavaだとこの組み合わせ減ってると思います:sob::sob:

  • Spring Boot 2.2
  • Java OpenJDK 11
  • STS 4
  • Maven 3.6.3

構築イメージ

まずは構築する環境を説明します。
構成の図解.png

以下のコンテナを作成します。

  • MySQL
    • ホストOSのMySQL Workbenchでアクセスできる(localhost:3306)
  • Spring Boot
    • ホストOSのブラウザでアクセスできる(localhost:8080)
    • STS(Eclipse)からリモートデバッグできる(localhost:5005)
  • Nginx
    • HTTPSでアクセスできる(https://devnokiyo.example.com)
    • ただし、GitHubにソースコードを公開する関係で自己署名SSL証明書)

もちろん、コンテナ間も通信を行います。

構成

GitHubに公開しています。併せてご覧ください。
前述の記事同様にDocker周りだけを管理したいディレクトリと永続化だけを管理したいディレクトリに分けました。
以降、粛々とファイルとその説明が続きます。「とにかくGitHubのコードを動かしたい」方はこちらまで飛んでください:airplane_departure::airplane_departure::airplane_departure:

$ tree
├── README.md
├── docker                          # DockerやDocker Compose
│   ├── containers                   # 各コンテナ(イメージ)
│   │   ├── mysql                     # MySQL 5.7
│   │   │   ├── Dockerfile             # MySQL 5.7のDockerファイル
│   │   │   ├── initialize_data.sql    # 初期セットアップでユーザとサンプルデータを作成するスプリプト
│   │   │   └── my.cnf                 # 初期セットアップで反映するmy.cnf
│   │   ├── nginx                     # Nginx 1.19.0
│   │   │   ├── Dockerfile             # NginxのDockerファイル
│   │   │   └── nginx.conf             # 初期セットアップで反映するnginx.conf
│   │   └── spring                    # OpenJDK 11 (Spring Boot構築用)
│   │       └── Dockerfile             # Spring Boot構築用のDockerファイル
│   ├── docker-compose.yml          # Docker Composeファイル
│   └── environments                # 環境変数定義 
│       ├── common.env               # 各コンテナ共通
│       └── db.env                   # DB接続用MySQL関連
└── volumes                         # 永続化するリソース
    ├── app                          # Spring Bootのプロジェクト (以下、特筆点するディレクトリ/ファイルのみコメント)
    │   ├── .m2                       # Mavenのローカルリポジトリ
    │   ├── mvnw                      # Maven Wrapper 今回はこれを使ってSpring Bootを起動する
    │   └── src                        # ソースコード
    │       └── main
    │           └── resources            # この配下にstaticディレクトリを作成しない (静的ファイルはNginxで返す)
    ├── db                           # MySQLのデータ このディレクトリは最初は無し
    └── web                          # Nginxのファイル
        ├── ssl                       # SSL証明書
        │   ├── privkey.pem            # 秘密鍵
        │   └── server.crt             # サーバー証明証
        └── static                    # 静的ファイル置き場

Composeファイル

docker/docker-compose.yml
version: '3'
services:                                          # 各コンテナ(サービス)
  db:                                               # MySQLのコンテナ 「db」と命名
    build: containers/mysql                          # Dockerファイルのパス
    env_file:                                        # 環境変数
      - ./environments/common.env                     # 各コンテナ共通
      - ./environments/db.env                         # DB接続用MySQL関連
    volumes:                                         # 永続化
      - ../volumes/db/data:/var/lib/mysql             # MySQLのデータ
    ports:                                           # 開放ポート
      - 3306:3306                                     # ホストOSのWorkBenchでDBを参照する目的
  app:                                              # Spring Bootのコンテナ 「app」と命名
    build: containers/spring                         # Dockerファイルのパス
    env_file:                                        # 環境変数
      - ./environments/common.env                     # 各コンテナ共通
      - ./environments/db.env                         # DB接続用MySQL関連
    # 実行するコマンド(後述)
    command: ./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005"
    volumes:                                         # 永続化
      - ../volumes/app:/app                           # Spring Bootのプロジェクト
      - ../volumes/app/.m2:/root/.m2                  # Mavenのローカルリポジトリ
    ports:                                           # 開放ポート
      - 8080:8080                                     # ホストOSからNginxを通さずTomcatを直接参照する目的
      - 5005:5005                                     # IDEでリモートデバッグする目的
    depends_on:                                      # 起動する順番
      - db                                            # 「db」の後で起動
  web:                                              # Nginxのコンテナ 「web」と命名
    build: containers/nginx                          # Dockerファイルのパス
    env_file:                                       # 環境変数
      - ./environments/common.env                    # 各コンテナ共通
    volumes:                                        # 永続化
      - ../volumes/web/static:/usr/share/nginx/www/  # 静的ファイル (Spring Bootプロジェクトのresouce/staticには配置しない)
      - ../volumes/web/ssl:/etc/nginx/cert/          # SSL証明書
      - ../volumes/web/log:/var/log/nginx/           # Nginxのログ
    ports:                                          # 開放ポート
      - 443:443                                      # HTTPS この開発環境はHTTPSのみ想定
    depends_on:                                     # 起動する順番
      - app                                          # 「app」の後で起動

db(MySQL)コンテナ

Dockerファイル

docker/containers/mysql/Dockerfile
# MySQL 5.7
FROM mysql:5.7

# 初期セットアップで利用するmy.cnfをイメージへコピー
# アーカイブを展開する必要などが無ければADDで無くてCOPYで良い。
COPY my.cnf /etc/mysql/conf.d

# 初期セットアップで実行したいスクリプトをイメージへコピー
COPY initialize_data.sql /docker-entrypoint-initdb.d

コピーするファイルの概要

ホスト イメージ 概要
docker/containers/mysql/my.cnf /etc/mysql/conf.d/ 文字コード
docker/containers/mysql/initialize_data.sql /docker-entrypoint-initdb.d/ Spring Bootアプリ向けDBアカウント/サンプルデータ

Docker Comopseから設定される環境変数

docker/environments/common.env
TZ=Asia/Tokyo
docker/environments/db.env
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=spring
MYSQL_PASSWORD=spring

Docker Comopseから設定される永続化

ホスト コンテナ 概要
volumes/db/data /var/lib/mysql MySQLのデータ

app(Spring Boot)コンテナ

Dockerファイル

docker/containers/spring/Dockerfile
FROM openjdk:11

# 永続化でマウントされるパスをワーキングディレクトリに指定
WORKDIR /app

Docker Comopseから設定される環境変数

docker/environments/common.env
TZ=Asia/Tokyo
docker/environments/db.env
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=spring
MYSQL_PASSWORD=spring

Docker Comopseから設定される永続化

ホスト コンテナ 概要
volumes/app/ /app Spring Bootのプロジェクト
GitHubに公開しているものは予めサンプルアプリが入っています)
volumes/app/.m2 /root/.m2 Mavenのローカルリポジトリ
./mvnw cleanを実行するとプラグイン/ライブラリなどを毎回ダウンロードしてしまうことを防ぎます。

Docker Comopseのcommand

こちらのコマンドについて少し補足します。

./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005"
コマンド 概要
./mvnw Java -jarによる起動は開発中のコードが更新されたときの自動リロードが無効になってしまうので、Mavenで起動することにしました。Maven WrapperがあればMavenをインストールする必要がないので、mvnwを採用しました。
address=*:5005 JDWPのポートを指定しますが、 ホストOSからコンテナへアクセスするには*:5005とする必要があります。ポート番号しか書いていないネット情報が多いのでご注意ください:skull_crossbones::skull_crossbones:

web(Nginx)コンテナ

Dockerファイル

docker/containers/nginx/Dockerfile
FROM nginx:1.19.0

# 初期セットアップで反映するファイルをコピー
COPY nginx.conf /etc/nginx/conf.d/app.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

コピーするファイルの概要

ホスト イメージ 概要
docker/containers/nginx/nginx.conf /etc/nginx/conf.d/app.conf 後述

WEBサーバーの設定

トリッキーな設定は無いと思いますが簡単に補足します。
GitHubに公開しているものはSSL証明書については「*.example.com」の自己署名SSL証明書(所謂「オレオレ証明書」)を利用しています。筆者の環境ではLet's EncryptのSSL証明書を利用しています。

docker/containers/nginx/nginx.conf
server {
  listen 443 ssl;
  server_name devnokiyo.example.com;

  ssl_certificate     /etc/nginx/cert/server.crt;
  ssl_certificate_key /etc/nginx/cert/privkey.pem;
  ssl_prefer_server_ciphers on;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /app/public;
  try_files $uri /;
  client_max_body_size 10m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;

  location / {
    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_set_header X-CSRF-Token $http_x_csrf_token;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://app:8080;
  }

  # Spring Bootの静的ファイルはNginxで返す。
  location ~* .*\.(jpg|gif|png|css|js|ico|svg) {
      root /usr/share/nginx/www;
      access_log off;
  }
}

Docker Comopseから設定される環境変数

docker/environments/common.env
TZ=Asia/Tokyo

Docker Comopseから設定される永続化

ホスト コンテナ 概要
volumes/web/static/ /usr/share/nginx/www/ 静的ファイル
volumes/web/ssl/ /etc/nginx/cert/ SSL証明書
volumes/web/log/ /var/log/nginx/ ログ

実行してみましょう!

Docker Composeで起動

だいぶ簡単でしたが各ファイルの説明が終わりましたので実行して確認します。

  1. GitHubから一式ダウンロードします。
  2. dockerディレクトリへ移動します。

    $ cd docker
    
  3. ビルドします。(初回なので起動でも構いません)

    $ docker-compose build --no-cache
    Building db
    Step 1/3 : FROM mysql:5.7
    ---> 9cfcce23593a
    Step 2/3 : COPY my.cnf /etc/mysql/conf.d
    ---> 4af29808e20c
        :
        :
    Successfully built b074e2d8831d
    Successfully tagged docker_web:latest
    
  4. 起動します。

    $ docker-compose up
    Creating network "docker_default" with the default driver
    Creating docker_db_1 ... done
    Creating docker_app_1 ... done
    Creating docker_web_1 ... done
    Attaching to docker_db_1, docker_app_1, docker_web_1
    db_1   | 2020-06-22 23:04:49+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.30-1debian10 started.
        :
        :
    db_1   | Version: '5.7.30'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
        :
        :
    app_1  | [INFO] Scanning for projects...
    app_1  | Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.2.8.RELEASE/spring-boot-starter-parent-2.2.8.RELEASE.pom
    app_1  | Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-dependencies/2.2.8.RELEASE/spring-boot-dependencies-2.2.8.RELEASE.pom
        :
        :
    app_1  | [INFO] Attaching agents: []
    app_1  | Listening for transport dt_socket at address: 5005
    app_1  | 
    app_1  |   .   ____          _            __ _ _
    app_1  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    app_1  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    app_1  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
    app_1  |   '  |____| .__|_| |_|_| |_\__, | / / / /
    app_1  |  =========|_|==============|___/=/_/_/_/
    app_1  |  :: Spring Boot ::        (v2.2.8.RELEASE)
    app_1  | 
    app_1  | 2020-06-22 23:07:31.526  INFO 74 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on e5dd9a4954d8 with PID 74 (/app/target/classes started by root in /app)
        :
        :
    app_1  | 2020-06-22 23:07:37.683  INFO 74 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    app_1  | 2020-06-22 23:07:37.686  INFO 74 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 6.781 seconds (JVM running for 8.41)
    

ブラウザからアクセス

hostsファイルにdevnokiyo.example.comをループバックIPで設定してhttps://devnokiyo.example.com にアクセスします。不正な証明書ということでエラーが出ると思いますが便宜上例外を許可してください。以下はChromeの例ですが表示自体はされています。

ブラウザの警告.png
nginxへアクセス.png
Nginxを経由でWebサイトにアクセスできています:thumbsup:
なお、ポポデザイン様のテンプレートを利用させて頂きました。感謝申し上げます。

前述のとおり筆者専用環境ではLet's EncryptのSSL証明書を利用しています。ご参考までに正常な証明書扱いの画像も載せておきます。独自ドメインを所有しておりhoge.devnokiyo.comで取得した例になります。
スクリーンショット 2020-06-23 1.32.32.png

Tomcatへアクセス

Nginxの設定の誤りで動作不良になることもあると思いますので、Tomcatへの直接アクセスも許可しています。念のためアクセスできるか確認します。
http://localhost:8080 にアクセスします。レイアウトが崩れています:thermometer_face::thermometer_face::thermometer_face:
しかし、静的ファイルはNginxから返されるように設定しているので問題ありません:bangbang:
Tomcatにアクセス.png

ホストOSからMySQLへ接続を確認

ホストOSのMySQL Workbenchから以下にアクセスします。

ホスト名 127.0.0.1
ポート 3306
ユーザー spring
パスワード spring

無事できていますね:thumbsup:
DB_確認_1.png

TomcatからMySQLへ接続を確認

Docker Composeで定義したコンテナ間でMySQLへ接続できるか確認します。
https://devnokiyo.example.com/formへアクセスしてお問い合わせしてみます。
お問い合わせ.png
送信ボタンを押下します。
お問い合わせ完了.png
再度MySQL Workbenchでテーブルを参照するとレコードが1行増えていますね:thumbsup:
DB_確認_4.png

リモートデバッグする

Spring BootをDockerでコンテナ化しましたが、ブレークポイントを利用できないと不便です。STS(Eclipse)からTomcatのコンテナをアタッチしてデバッグできるようにします。

準備

STS(Eclipse)のメニューからRun -> Debug Configurations...を選択します。Remote Java ApplicaiondemoプロジェクトをDebugします。
リモートデバッグの準備.png

ブレークポイントを設定

RootControllerの29行目にブレークポイントを設定しました。
ブレークポイントを設定
http://devnokiyo.example.com/formへアクセスするとブレークポイントで処理が止まります。
ブレークポイントで停止中.png

自動リロード

ソースコードを修正したときに毎回ビルドするのは面倒なので、Spring Boot Devtoolsの自動リロードを利用します。前述のとおりJava -jarによる起動は開発中のコードが更新されたときの自動リロードが無効になってしまいますが、Maven WrapperでSpring Bootを起動しているので自動リロードできます。

ソースコード修正

以下のアクションメソッドを追加してみます。コントローラークラスのファイルを保存するとリロードされます。

RootController.java
@GetMapping("/hoge")
public String hoge() {
    return "root/index";
}

ソースコード修正

自動リロード中

コンソールをみるとリロードの状況がわかります。1行目が初回起動時の日時で2行目以降が自動リロードの挙動になります。

app_1  | 2020-06-23 00:09:00.911  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 6.459 seconds (JVM running for 8.092)
app_1  | 2020-06-23 00:21:51.379  INFO 40 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
app_1  | 2020-06-23 00:21:51.379  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
app_1  | 2020-06-23 00:21:51.389  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 9 ms
app_1  | 2020-06-23 00:36:13.585  INFO 40 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
app_1  | 2020-06-23 00:36:13.588  INFO 40 --- [       Thread-5] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
app_1  | 2020-06-23 00:36:13.651  INFO 40 --- [       Thread-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
app_1  | 2020-06-23 00:36:13.755  INFO 40 --- [       Thread-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
app_1  | 
app_1  |   .   ____          _            __ _ _
app_1  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
app_1  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
app_1  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
app_1  |   '  |____| .__|_| |_|_| |_\__, | / / / /
app_1  |  =========|_|==============|___/=/_/_/_/
app_1  |  :: Spring Boot ::        (v2.2.8.RELEASE)
app_1  | 
app_1  | 2020-06-23 00:36:14.036  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on e5dd9a4954d8 with PID 40 (/app/target/classes started by root in /app)
app_1  | 2020-06-23 00:36:14.037  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
app_1  | 2020-06-23 00:36:14.500  INFO 40 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
        :
        :
app_1  | 2020-06-23 00:36:15.884  INFO 40 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
app_1  | 2020-06-23 00:36:15.907  INFO 40 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
app_1  | 2020-06-23 00:36:15.908  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 1.965 seconds (JVM running for 1644.96)
app_1  | 2020-06-23 00:36:15.911  INFO 40 --- [  restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
app_1  | 2020-06-23 00:36:30.177  INFO 40 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
app_1  | 2020-06-23 00:36:30.178  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
app_1  | 2020-06-23 00:36:30.183  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

修正後の確認

https://devnokiyo.example.com/hogeにアクセスしてトップページと同じページが表示されることを確認します。
自動リロード済み

終わりに

前回同様に基礎的なコマンドの説明よりは「筆者はこうやった」的なことをメインに記事を書いてみました。JVM系はRubyやGoと比較するとDocker周りの情報が少ない印象です。(点々とした情報はあるのですが、線になっている情報は少ない雰囲気です。)
ひととおりの手順を習得できたので、どのくらい開発環境として使っていけるか運用してみようと思います。

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