20201124のdockerに関する記事は15件です。

Docker環境でNodeJSのライブラリsharpを使用するときの darwin-x64 エラー

MacでNode.jsのライブラリsharpを使用するときに darwin-x64 エラーが発生しました。
Docker環境のため、sharpの公式ドキュメントで書いた対処方法ですぐ解決できなかったのではまりました。

/var/www/xxxxx/node_modules/sharp/lib/libvips.js:68
    throw new Error(`‘${vendorPlatformId}’ binaries cannot be used on the ‘${currentPlatformId}’ platform. Please remove the ‘node_modules/sharp/vendor’ directory and run ‘npm install’.`);

Error: ‘darwin-x64’ binaries cannot be used on the ‘linux-x64’ platform. Please remove the ‘node_modules/sharp/vendor’ directory and run ‘npm install’.
    at Object.hasVendoredLibvips (/var/www/xxxxx/node_modules/sharp/lib/libvips.js:68:13)
    at Object.<anonymous> (/var/www/xxxxx/node_modules/sharp/lib/constructor.js:7:22)
    at Module._compile (internal/modules/cjs/loader.js:1200:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
    at Module.load (internal/modules/cjs/loader.js:1049:32)
    at Function.Module._load (internal/modules/cjs/loader.js:937:14)
    at Module.require (internal/modules/cjs/loader.js:1089:19)
    at require (internal/modules/cjs/helpers.js:73:18)
    at Object.<anonymous> (/var/www/xxxxx/node_modules/sharp/lib/index.js:3:15)
    at Module._compile (internal/modules/cjs/loader.js:1200:30)

下記のように解決しました。
OS:macOS Catalina

1. nodeのバージョンを揃えます。

MacのnodeのバージョンとDocker環境のnodeバージョンとメジャーバージョンを揃えます。
例えば、
プロジェクトのnodeのバージョンが v14.xx.xx であれば、DockerfileでFROM node:14を指定。
※nodeのバージョンの制御にプロジェクト単位で設定できるnodenvの利用がおすすめです。

2. Dockerコンテナに入ってsharpを再インストール

$ docker ps
$ docker exec -it xxxxx bash
$ rm -rf node_modules/sharp
$ npm install --arch=x64 --platform=linux sharp

自分の環境では、targetの指定が不要でした。
$ npm install --arch=x64 --platform=linux --target=xx.xx.x sharp

参考:
https://github.com/lovell/sharp/blob/master/docs/install.md
https://sharp.pixelplumbing.com/install#common-problems
https://qiita.com/mame_daifuku/items/1dbdfbd4897b34df0d9f

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

【ConoHa VPS,Vue-cli,Docker】Vue CLIで作成したSPAをConoHaで公開するまで①(ConoHa登録~VPSにログイン)

初投稿です。よろしくお願い致します。
新卒入社して半年、「エンジニアなら自分のプロダクトを公開したい!」という思いから、学生自体にお世話になったバイト先のWEBサイトを公開することにしました。

その際の作業ログを共有いたします。

前提条件

Vue Cliで作成したアプリケーションがあること
もし作成していない場合は、下記URLなどを参考に作成してみましょう。
https://qiita.com/yuucu/items/189945f984e5e53117ea

環境

PC: MacBookPro
VPS: ConoHa
CentOS: 8.2.2004
docker-compose: 1.27.4
Docker: 19.03.13
nginx: 1.19.4
vue-cli: 4.5.8
npm: latest(作業時:15.2.0)

ConoHa登録

https://www.conoha.jp/vps/
_2020-10-25_15.23.07.png

新規登録

signup.png

登録後

私は下から二番目のグレードの「memory:1GB」を選択
OSはCentOS8にしました。
右側の値段は、デフォルトでは、三ヶ月分まとめ払いが選択されていますが、
一ヶ月ごとの支払いに変更することもできます。
しかし、まとめ払いがお得みたいです。
ここで、rootパスワードとネームタグを入力しましょう。
※rootパスワードはVPSに接続するために必要です。必ずメモしましょう!
※また、この時SSH Keyを作成できるはずだったのですが、私は作成し損ねてしまったので、自力で作成していきます。
screencapture-manage-conoha-jp-Wizard-Create-2020-10-25-05_49_24.png

コントロールパネル

コントロールパネルはこんな感じです。
自分が作成したVPSが一覧で確認できます。
スクリーンショット 2020-11-19 22.31.35.png

ネームタグをクリックすると、サーバの詳細が確認できます。
ここで、VPSのIPアドレスを確認しておきましょう。
スクリーンショット 2020-11-19 22.34.31.png

VPSにリモートアクセス

rootでSSH接続していきます。
今回はMacのTerminalでの接続を想定しております。
Windowsの方は、Teratermなどで接続されることをお勧めします。

ssh root@ipアドレス

The authenticity of host '(IPAddress) ((IPAddress))' can't be established.
ECDSA key fingerprint is (...).
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '(IPAddress)' (ECDSA) to the list of known hosts.
root@(IPAddress)'s password: #初めに設定したrootパスワードを入力

※基本的に、パスワード入力をしても、画面上に表示されません。
しかし、文字は見えないだけで入力されています。
注意して入力しましょう。

このように表示されれば、リモートアクセス成功です。

[root@(IPアドレス) ~]# 

次回:セキュリティ対策

サーバに接続して、早速アプリケーションの環境を立ち上げたいところですが、
まずはセキュリティ対策をします。

とはいえ、新卒研修でも行うぐらい作業自体は難しいものではありません。
(法人レベルになると、もっと高度な対策が求められると思われますが…)

地道に進めていきます。

参考・引用

https://qiita.com/mkoku/items/ea107a29fd925081ebcf

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

Vue 3.x (Vue CLI 5.x) 環境構築完全版 Docker + TypeScript + Yarn + Router

Vue 3 環境セットアップ手順

数ある記事から見ていただき有難うございます。
Vue 3 がリリースされてから2ヶ月ほど経過しましたが、
今回は会社でとりあえず採用している Vue 3 の環境構築をご紹介します。

歓迎条件

  • Docker の環境構築ができている。
  • これまでに Vue (2.x) の環境を構築したことがある。
  • とりあえず TypeScript で Vue3 触ってみたい!
  • 完全版と書いていますがあくまで一つの環境に過ぎませんので構築したい環境の条件が合う方は使ってみてください。

プロジェクトの作成

自身のプロジェクトを作成します。
名前はお任せします。(どうしても決められない方は new-vue3-app とかで大丈夫です)

プロジェクト直下に docker-compose.yml ファイルを作成

version: "2.4"

services:
  node:
    image: node:latest
    ports: 
      - 8080:8080
    volumes:
      - .:/srv:cached
    working_dir: /srv
    command: yarn serve

プロジェクトで以下のコマンドを実行

Vue CLI インストール

docker-compose run --rm node yarn add @vue/cli

Vue CLI バージョン確認

vue -V
=> @vue/cli 5.9 (2020/11/24)

アプリケーションの初期化

docker-compose run --rm node ./node_modules/.bin/vue create . 
// 最後の . はカレントディレクトリを指すのでお忘れなく!
?  Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) Y
? Generate project in current directory? (Y/n) Y

プロジェクトの作成方法を選択

? Please pick a preset: (Use arrow keys)
  Default ([Vue 2] babel, eslint)
  Default (Vue 3 Preview) ([Vue 3] babel, eslint)
❯ Manually select features

プロジェクトへ導入するライブラリを選択

? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Choose Vue version
 ◉ Babel
 ◉ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◯ Vuex
❯◉ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

重要 : バージョンの選択 3.x を選択

? Choose a version of Vue.js that you want to start the project with
  2.x
❯ 3.x (Preview)

Class Style or Object Style の選択(基本的に No の Object Style で良い)

? Use class-style component syntax? (y/N) N

自動検出されたポリフィルに Babel と TypeScript を使うか選択

? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) Y

Vue RouterのHistoryモードを利用するかを設定

? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Y

CSS プリプロセッサの選択

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
❯ Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
  Less
  Stylus

ESLintのプリセットを選択

? Pick a linter / formatter config:
  ESLint with error prevention only
  ESLint + Airbnb config
❯ ESLint + Standard config
  ESLint + Prettier
  TSLint (deprecated)

ESLintの実行タイミングを選択

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

ライブラリ(BabelやESLint)の設定ファイルの配置個所を選択

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files
  In package.json

次回以降のcreate projectで利用できるプリセットに登録するか設定

? Save this as a preset for future projects? (y/N) N

Yarn or NPM を選択

? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn
  Use NPM

完了時のログ

success Saved lockfile.
Done in 80.73s.
⚓  Running completion hooks...

?  Generating README.md...

?  Successfully created project srv.
?  Get started with the following commands:

 $ yarn serve

 WARN  Skipped git commit due to missing username and email in git config, or failed to sign commit.
You will need to perform the initial commit yourself.

サーバを立てる

yarn serve
yarn run v1.22.4
warning ../../../package.json: No license field
$ vue-cli-service serve
 INFO  Starting development server...
98% after emitting CopyPlugin

 DONE  Compiled successfully in 2932ms                                                                        21:55:12


  App running at:
  - Local:   http://localhost:8081/
  - Network: http://10.13.52.2:8081/

  Note that the development build is not optimized.
  To create a production build, run yarn build.

No issues found.

構築完了です。
新生 Vue3 をお楽しみください。
お疲れ様でした!

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

Railsプロジェクトをdocker-composeで環境ごとに構築

Railsのプロジェクト(Redmine)をdocker-composeを用いて、
環境ごとに管理していきます
今回はdockerを用いた環境構築を主軸としたため、
webサーバーなどの詳しい説明は省きます

作成:2020年11月24日

環境

Ubuntu18.04
Rails 5
Ruby 2.6.5
Redmine 4.0
nginx 1.15.8
Docker 19.03.13
docker-compose 3
MySQL 5.7

必要なもの

Dockerとdocker-compsoeが動く環境(今回はUbuntu18.04で実行)
Redmineのソース
やる気

ざっくりとした方法

環境ごとにcomposeファイルを作成
環境変数COMPOSE_FILEを環境ごとに指定する

コンテナ構成

  • 開発環境
    app(rails), db(mysql)
  • 本番環境
    app(rails, puma), db(mysql), web(nginx)

フォルダ構成

docker-compose.develop.ymlが開発環境とテスト環境
docker-compose.prod.ymlが本番環境となる
開発環境のDockerファイルはDockerfile
本番環境はDockerfile.prodとなる

redmine(プロジェクトroot)
├── app
├── bin
├── etc....
├── config
│ ├── database.yml(追加)
│ ├── puma.rb(追加)
│ └── etc...
├── container(追加)
│     ├── app
│     │     ├── Dockerfile
│     │     └── Dockerfile.prod
│     ├── db
│     │ └── multibyte.cnf
│     └── web
│         ├── Dockerfile.prod
│         └── nginx.conf
├── docker-compose.develop.yml(追加)
└── docker-compose.prod.yml(追加)

初期設定

環境に応じて、環境変数を設定する

docker-composeの仕様により、
COMPOSE_FILE環境変数を設定すると、設定した環境すべてにおいて、
docker-composeコマンドに適応されるので注意。
direnvの導入をおすすめする

 開発環境
$ export COMPOSE_FILE=docker-compose.develop.yml
 本番環境
$ export COMPOSE_FILE=docker-compose.prod.yml

Gemfile修正

pumaを本番環境に適応させる

Gemfile
group :test, :production do 
  gem 'puma', '~> 3.7' # 追加
end
group :test do
  gem "rails-dom-testing"
  gem 'mocha', '>= 1.4.0'
  gem "simplecov", "~> 0.14.1", :require => false
  # For running system tests
  gem "capybara", '~> 2.13'
  gem "selenium-webdriver"
  # gem 'puma', '~> 3.7' 削除
end

puma.rb作成

config/puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
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", true

database.yml作成(DB設定)

redmine公式ドキュメントに基づきdatabase.yml.exampleをもとに
database.ymlを作成

database.yml
    # Default setup is given for MySQL with ruby1.9.
    # Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end.
    # Line indentation must be 2 spaces (no tabs).

    production:
      adapter: mysql2
      database: redmine
      host: db
      username: hoge
      password: "fugafuga_1"
      encoding: utf8

    development:
      adapter: mysql2
      database: redmine_development
      host: db
      username: root
      password: ""
      encoding: utf8

    # Warning: The database defined as "test" will be erased and
    # re-generated from your development database when you run "rake".
    # Do not set this db to the same as development or production.
    test:
      adapter: mysql2
      database: redmine_test
      host: db
      username: root
      password: ""
      encoding: utf8

    # 省略、、、、、

本番環境以外、パスなしrootで良ければproduction関連以外編集しなくてもよい

各ファイル詳細

開発、本番環境共用

実際の本番環境ではDBサーバーを別途用意するとは思いますが、、

cotainers/db/multibyte.cnf
# 文字コードを設定しないとエラーとなるため
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

開発環境

appコンテナ

containers/app/Dockerfile
FROM ruby:2.6.5
RUN apt-get update -qq && apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs
RUN mkdir /redmine
WORKDIR /redmine
COPY . /redmine
RUN gem install bundler && bundle install

compose

docker-compose.develop.yml
# DBを永続化したい場合、コメントを外す
version: '3'
services:
  app:
    build: 
      context: ./
      dockerfile: containers/app/Dockerfile
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    volumes:
      - .:/redmine
    ports:
      - "3000:3000"
    depends_on:
      - db  

  db:
    image: mysql:5.7
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    ports:
      - 3306:3306
    volumes:
      - ./containers/db/multibyte.cnf:/etc/mysql/conf.d/multibyte.cnf
      #- db-store:/var/lib/mysql


#volumes:
  #db-store:

本番環境

appコンテナ

containers/app/Dockerfile.prod
FROM ruby:2.6.5
RUN apt-get update -qq && apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs
RUN mkdir /redmine
WORKDIR /redmine
COPY . /redmine
RUN gem install bundler && bundle install --without development test

webコンテナ

Dockerfile.prod
FROM nginx:1.15.8
# インクルード用のディレクトリ内を削除
RUN rm -f /etc/nginx/conf.d/*

# Nginxの設定ファイルをコンテナにコピー
ADD nginx.conf /etc/nginx/myapp.conf

# ビルド完了後にNginxを起動
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/myapp.conf
containers/db/nginx.conf
user  root;
worker_processes  1;

events{
    worker_connections  512;
}

# ソケット接続
http {
  upstream redmine{
    server unix:///redmine/tmp/sockets/puma.sock;
  }
  server { # simple load balancing
    listen 80;
    server_name localhost;

    #ログを記録しようとするとエラーが生じます
    #root /redmine/public;
    #access_log logs/access.log;
    #error_log logs/error.log;

    location / {
      proxy_pass http://redmine;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
    }
  }
}

compose

docker-compose.prod.yml
# DBコンテナはdatabase.ymlをもとに設定
# DBを永続化したい場合、コメントを外す
version: '3'
services:
  app:
    build:
      context: ./
      dockerfile: containers/app/Dockerfile.prod
    command: bash -c "rm -f /redmine/tmp/pids/server.pid && bundle exec puma -e production -C config/puma.rb"
    volumes:
      - .:/redmine
      - public-data:/redmine/public
      - tmp-data:/redmine/tmp
    depends_on:
      - db

  web:
    build: 
      context: containers/web/
      dockerfile: Dockerfile.prod
    ports:
      - 80:80
    volumes:
      - public-data:/redmine/public
      - tmp-data:/redmine/tmp
    depends_on:
      - app

  db:
    image: mysql:5.7
    environment:
      MYSQL_USER: hoge
      MYSQL_PASSWORD: fugafuga_1
      MYSQL_ROOT_PASSWORD: rootdayo
      MYSQL_DATABASE: redmine
    ports:
      - 3306
    volumes:
      - ./containers/db/multibyte.cnf:/etc/mysql/conf.d/multibyte.cnf
      #- db-store:/var/lib/mysql

volumes:
  #db-store:
  public-data:
  tmp-data:

実行手順

開発環境

$ docker-compose build
# DBを永続化した場合は最初だけ----------
# db作成(appはコンテナ名)
$ docker-compose run app rake db:create
# テーブル設定
$ docker-compose run app rake db:migrate
# ---------------------------------------
# 起動
$ docker-compose up -d
# http://localhost:3000

本番環境

$ docker-compose build

# Redmine公式ドキュメントに基づき、シークレットトークン作成
# 実行は最初の一回だけでよい
$ docker-compose run -e RAILS_ENV=production app bundle exec rake generate_secret_token
# DBを永続化した場合は最初だけけ---------
# テーブル設定
$ docker-compose run -e RAILS_ENV=production app bundle exec rake db:migrate
# ---------------------------------------
# $ 起動
$ docker-compose up -d

参考

Redmine GitHub
https://github.com/redmine/redmine
Redmineインストール

http://guide.redmine.jp/RedmineInstall/
docker-compose.ymlが環境別に複数ある場合はCOMPOSE_FILEを定義しておくと幸せになれる

https://suin.io/535

GitHub

ソースをgithubにあげているので良かったら参考にしてください
https://github.com/kinako555/redmine_managed_docker.git

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

Rails on Dockerのgemの永続化について

背景

Dockerを利用したアプリ開発を行っていて、ログイン機能を搭載したくbcryptをGemfileに追加したが以下のエラーが出続け解決不能に。

22: from /usr/local/bundle/gems/spring-2.1.1/bin/spring:49:in `<main>'
        21: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/client.rb:30:in `run'
        20: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/client/command.rb:7:in `call'
        19: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/client/server.rb:9:in `call'
        18: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        17: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        16: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/server.rb:9:in `<top (required)>'
        15: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        14: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        13: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/commands.rb:4:in `<top (required)>'
        12: from /usr/local/bundle/gems/spring-2.1.1/lib/spring/commands.rb:33:in `<module:Spring>'
        11: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        10: from /usr/local/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
         9: from /usr/local/lib/ruby/2.6.0/bundler/setup.rb:20:in `<top (required)>'
         8: from /usr/local/lib/ruby/2.6.0/bundler.rb:107:in `setup'
         7: from /usr/local/lib/ruby/2.6.0/bundler/runtime.rb:20:in `setup'
         6: from /usr/local/lib/ruby/2.6.0/bundler/runtime.rb:108:in `block in definition_method'
         5: from /usr/local/lib/ruby/2.6.0/bundler/definition.rb:226:in `requested_specs'
         4: from /usr/local/lib/ruby/2.6.0/bundler/definition.rb:237:in `specs_for'
         3: from /usr/local/lib/ruby/2.6.0/bundler/definition.rb:170:in `specs'
         2: from /usr/local/lib/ruby/2.6.0/bundler/spec_set.rb:85:in `materialize'
         1: from /usr/local/lib/ruby/2.6.0/bundler/spec_set.rb:85:in `map!'
/usr/local/lib/ruby/2.6.0/bundler/spec_set.rb:91:in `block in materialize': Could not find bcrypt-3.1.16 in any of the sources (Bundler::GemNotFound)


解決方法


こちらのサイトの方法を試したが、一向に解決せず。。。
https://qiita.com/totto357/items/1741da83bf642dab99df


問題は実はDockerのgem一覧が永続化されていなかったからということが発覚。
https://nishinatoshiharu.com/datavolume-for-gem/

gemの永続化を行なっていないとコンテナ上でbundle installを実行してもDockerイメージにはgemが保存されないためエラーが発生していたようです。

gemを永続化していないと新しいgemを入れるたびに、ビルドを実行しコンテナを起動しなければならないというわけです。

しかし、永続化を行えばコンテナ上でgemをインストールした際にイメージの再ビルドを行わなくて済むということのようです。

永続化の方法については上記のサイトがわかりやすいため参照ください。

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

コンテナ間通信ができない場合の原因について

docker-composeを使っていて、GoのコンテナからMySQLのコンテナに接続できずにハマった。 dial tcp 172.20.0.2:3306: connect: connection …
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSL2 上の Docker で wp-env が起動できない問題

Docker を Windows で動かしている場合は問題ありませんが、WSL2 上の Ubuntu で動かしているといろいろと壁にぶつかります。

今回の問題は、wp-env で WordPress のコンテナから MySQL のコンテナにアクセスできない問題です。エラー内容は以下の通り。

yarn wp-env start
...
mysqlcheck: Got error: 1130: Host '192.168.0.5' is not allowed to connect to this MariaDB server when trying to connect
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

192.168.0.5 には MySQL にアクセスする権限がないとエラー。

コンテナ自体は立ち上がっているので、mysql のコンテナに入って権限の設定を行います。コンテナ名は docker ps | grep mariadb で調べて置き換えてください。

docker exec -it 3c9213646ddda6dbba714e3a7744fdfb_mysql_1 bash

mysql のコンテナに入ったら、デフォルトのrootユーザー(パスワードなし)で mysql に接続します。

root@f122f108eb2e:/# mysql -u root

ユーザーの一覧を確認

MariaDB [(none)]> SELECT host, user FROM mysql.user;
+--------------+-------------+                      
| Host         | User        |                      
+--------------+-------------+                      
| 127.0.0.1    | root        |                      
| ::1          | root        |                      
| a1842b624a31 | root        |                      
| localhost    | mariadb.sys |                      
| localhost    | root        |                      
+--------------+-------------+                      
5 rows in set (0.001 sec)

たしかに 192.168.0.5 ではアクセスできないようです。開発環境なのでどこからでも接続できるように Host % を追加します。

MariaDB [(none)]> CREATE USER 'root'@'%';

権限の付与も忘れずに行います。

MariaDB [(none)]> GRANT ALL ON *.* TO 'root'@'%';

追加できているか確認します。

MariaDB [(none)]> SELECT host, user FROM mysql.user;
+--------------+-------------+
| Host         | User        |
+--------------+-------------+
| %            | root        |
| 127.0.0.1    | root        |
| ::1          | root        |
| a1842b624a31 | root        |
| localhost    | mariadb.sys |
| localhost    | root        |
+--------------+-------------+
6 rows in set (0.004 sec)

無事に追加されています。

exit を2回入力してコンテナから出ます。

MariaDB [(none)]> exit    
Bye                       
root@85afdca4b77e:/# exit 
exit                      

それでは、再度 wp-env をスタートしてみましょう。

yarn wp-env start

yarn run v1.22.5                   
$ wp-env start                                                  
⚠ Warning: could not find a .wp-env.json configuration file and 
 could not determine if 'プロジェクトディレクトリ名' is a WordPress 
installation, a plugin, or a theme.                             
✔ WordPress started. (in 22s 915ms)                             
Done in 23.38s.                                                 

無事に起動できたようです。
http://localhost:8888/ で動作が確認できます。

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

サーバーサイドエンジニアに知っておいてほしい文脈ごとのdockerコマンドとトラブルシューティング

これはなに

  • docker自体は知っているし,「なんとなく起動と停止は使えるけどそれ以上はあまりやったことない」という人向け
  • これらを抑えておけば普段の開発作業はもちろん,サーバー作業もおおよそ大丈夫でしょう!というのを想定作業ごとにまとめた

前提

  • シェルスクリプトの構文がある程度頭に入っている
  • dockerの環境整備が済んでいる
  • dockerの基礎的な単語を抑えている
    • dockerにおけるイメージ,コンテナの区別がついている
    • buildをやったことはある

想定している作業

  • dockerイメージの構築
    • Dockerfileの作成および最適化
    • CIでのdocker build
  • 複数コンテナを利用したローカルでの環境の構築
    • docker-compose.ymlの作成
  • サーバー作業
    • dockerコンテナのリソース利用率の確認
    • コンテナに入って諸々の調査

それでは個別にみていきましょう.

作業ごとの解説

dockerイメージの構築作業

Dockerfileの作成および最適化

ここで想定しているのは,Dockerfileを編集しつつ,docker builddocker runを繰り返すような作業
使うコマンドとしては主に以下になる

# build
docker build .
docker build -f /path/to/Dockerfile .
docker build --build-arg HOGE=hoge
docker build --no-cache

# debugで使う
docker run $IMAGE_ID
docker run -it $IMAGE_ID sh
docker exec -it $CONTAINER_ID sh

# モリモリストレージ容量が食われるので適当なタイミングで片付ける
docker images
docker images -a
docker images -aq
docker rmi -f $(docker images -aq)
docker system prune

Dockerfileの作成

  • docker buildで抑えておくべきなのは,コンテキストという概念である
  • docker build自体が失敗するとき
    • docker buildではRUNコマンドひとつ一つに対してimageが作成されている.
    • エラー直前に出力されたimage idに対して,docker runして,失敗したコマンドを実行&ログ確認して解決していく.
  • docker buildは成功するが,docker runが失敗するとき
    • image idに対して,docker run -it $IMAGE_ID shで起動してからコマンドを実行してエラーを確認する.
    • ENTRYPOINTを指定しているときは,docker run -it --entrypoint='' $IMAGE_ID shとしてentrypointを上書きすれば入れる.

Dockerfileの最適化

  • --build-arg VAR=varというオプションはDockerfileのARG構文と同時に理解すべき.
    • 基本的に引数をDockerfileに渡せる,というだけ.それだけではdocker imageの中には記録されないので,注意.
    • 記録したい場合はENV構文を利用する.
    • ARGで気を付けるべきは,FROMとの位置関係.FROMよりあとに書かないと,うまく動かなくてハマる.
    • 参考: Docker ARG vs ENV
  • イメージサイズの削減にはmulti stage buildが効く
    • わかっている人向けに端的にいえば,FROM句が二度でてきて,それぞれbuild時のイメージと実行時イメージに対応しており,buildが完了したら,実行時に必要なものだけ,実行時イメージにCOPYする手法.
    • サービスやデプロイの規模によるが,イメージが1GBを超えないくらいなら優先度はまったく高くない.
  • もしやるときにはdiveというコマンドが便利.
    • brew install dive

CIでのdocker build

ここでのコマンドはこれ

docker pull $PREV_IMAGE_ID
docker build --cache-from $PREV_IMAGE_ID .
  • CIでのポイントはとてもシンプル.buildキャッシュを効かせるだけ!
    • ローカル環境でのbuildとは違って,CI環境ではなにもしないとキャッシュが基本効かない.
    • ただし,通信コストが発生するので依存を一からダウンロードするコストとの比較にはなる.

複数コンテナを利用したローカルでの環境の構築

docker-compose.ymlの作成

ここでよく使うコマンドは以下の通り

docker-compose up
docker-compose up --build
docker-compose down
docker-compose restart
docker-compose exec [service] sh
  • ymlの細かい解説はしない.公式docを読むべし.
    • ローカル環境構築のポイントは下記.これらの項目を理解すればだいたいやりたいことはやれるはず.
      • ポート転送設定(posts:)
      • コンテナとの共有ストレージの設定(volumes:)
      • コンテナ間ネットワークの設定(links:depends_on:
  • コンテナ間の通信ができないとき
    • コンテナ間はサービス名(services:配下のkey)をホスト名として指定すれば通信できる
    • もちろん,ポートをEXPOSEなどしていることなどは確認が必要
  • 環境変数を渡したい
    • environments:での定義はもちろん,コミットしたくないような秘匿情報も,.env形式のファイルを渡すことで解決できる!便利!
  • 変更が反映されない
    • ymlファイル自体を更新したときは,docker-compose downもしくはdocker-compose restartをおこなったほうがよい.
    • dockerにはイメージやコンテナとは別にネットワークの設定があり,一度落とさないと反映されない.

サーバー作業

基本はこちら

# 稼働コンテナ一覧表示
docker container ls
docker ps
docker ps -a

# 稼働中コンテナへ入る
docker exec -it $CONTAINER_ID sh

# 稼働コンテナの強制停止
docker kill $CONTAINER_ID
docker rm -f $(docker ps -aq)

dockerコンテナのリソース利用率の確認

docker stats

dockerコンテナでの作業後のファイル取得

地味に便利.

docker cp $CONTAINER_ID:/path/from/root/ ./
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでLaravelを構築してみた

Laradockとは

Docker環境でLaravel環境を簡単に構築できるDockerイメージです。
Laradockのプロジェクトは大きくなり、SymfonyやWordpress環境までも構築出来るようになりました。

機能としては、Nginx, Apacheなどのwebサーバー、PHPの各バージョン、Mysql, PostgreSQL等の各データベースを自由に選択できます。

今回はNginx、PHP-FPMが動く環境を作り、Laravelを立ち上げるまでを記載します。

前提

・dockerインストールしていること
・docker-composeコマンドが実行できるようになっていることが必要。

環境

Windows10 Pro

手順

[1] CMD開く。作業ディレクトリを作成してそこまで移動する

cd C:\Users\user

[2] フォルダ内でLaradockをgithubからcloneします。

git clone https://github.com/laradock/laradock.git

[3] Laravel環境を構築するまでの下準備

nginx(webサーバー。Apacheでも良いが、今回はLaradockの公式マニュアルに沿いました)
php-fpm(PHPを実行する環境。いわゆるfastCGI)

.envの作成

copy env-example .env

dockerコンテナの立ち上げ

docker-compose up -d nginx

image.png

コンテナが立ち上がっているかを確認する

docker-compose ps

image.png

workspaceにログインし、Laravelをセットアップする

docker-compose exec workspace bash

workspaceにログインすると、最初の状態では/var/wwwにいる。この場所は、Windows側のprojectsフォルダ直下と同様の場所を表している。(laradockディレクトリ直下ではない)

/var/wwwの位置でLaravelをセットアップする

composer create-project laravel/laravel app01

現時点でディレクトリ構成は以下のようになっているかと思います。
親:projects
子1:laradock … Dockerコンテナ
子2:app1 … Laravel本体

image.png

Dockerダッシュボード状態

image.png

ブラウザで動作確認する

image.png

ginx(webサーバー)の設定をします。設定ファイルを編集するため、一度、dockerコンテナを停止します。Windows側のlaradockディレクトリ直下で以下のコマンドを叩く

image.png

dockerコンテナが全てストップします。

image.png

image.png

コンテナを再度立ち上げる

docker-compose up -d nginx

コンテナが立ち上がったら、ブラウザでhttp://localhost へアクセス

image.png

参考

  1. http://laradock.io
  2. http://laradock.io/introduction/
  3. 環境作成時に次のエラーが出た場合

UnexpectedValueException
The stream or file "/var/www/storage/logs/laravel.log" could not be opened:
failed to open stream: Permission denied

laravel.logに書き込もうとして権限がなかった時に発生します。

sudo chmod 777 -R storage/

参考になったURL
https://teratail.com/questions/236475

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

DockerでNode.js環境構築

概要

DockerfileDocker-composeを使って簡単にnode.jsの環境を作る。

ディレクトリ構造

node_app
├─ Dockerfile
└─ docker-compose.yml

Dockerfile の記載

Dockerfile
#イメージを指定
FROM node:12.4.0-alpine

# 環境変数を定義
ENV NODE_ENV=development

# 雛形パッケージのインストール
RUN npm install -g express-generator

# 初期カレントディレクトリ
WORKDIR /app

# 開放ポート
EXPOSE 3000

docker-compose.yml の記載

docker-compose.yml
version: '3.7'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: node
    volumes:
      - ./app:/app
    ports:
      - "8080:3000"

context ディレクトリの指定 「 . 」 で同じディレクトリ

container_name コンテナネームの指定

volumes データーのマウント共有の指定 左がホスト 右がコンテナ

ports コンテナとホストのポートをつなげる指定

Dockerfile からイメージのビルド

$ docker-compose build

コンテナを生成、起動

-d (デタッチ オプション)でバックグラウンドで起動

$ docker-compose up -d

コンテナに接続

-i(--interactive)標準入力を設定させ、コマンドを対話的にする
-t(--tty)疑似ターミナルの割り当て

$ docker exec -it [CONTAINER_ID] bash

express-generator で雛形の作成

今回はテンプレートエンジンはejsを使用

# express --view=ejs /app

パッケージのインストール

# npm install

サーバーを起動

# npm start

local hostに接続して Welcome to Express! と表示されれば完成です。

参考本

Docker ドキュメント
Docker/Kubernetes 実践コンテナ開発入門

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

【AWSアカウント不要】ローカル環境でAWS CDKのデプロイ&動作確認をするチュートリアル

1. はじめに

1-1. この記事で行うこと

  • LocalStackコンテナをセットアップし、動作確認
  • Node.js環境コンテナ内にAWS CDKプロジェクトを作成
  • AWS CDKプロジェクトをLocalStackへデプロイし、動作確認

1-2. この記事の対象者

  • AWS CDKを本物のAWSを使わずに動かしたい方
  • AWS CDKをすぐに捨てられる環境で色々と試してみたい方
  • AWS CDKをブラウザのみで気軽に始めてみたい方

1-3. 動作環境

このチュートリアルはブラウザだけでDockerを使用可能なPlay with Dockerを使用しております。詳細な説明は以下の記事をご参考ください。
Docker 入門にはインストールなしで使える「Play with Docker」がいいと思う

また、Play with DockerではなくてもDockerが動く環境ならおそらく同じようにチュートリアル可能だと思います (が、この記事では手順等ございませんのでご了承ください)。

  • 共通して必要なもの
    • Docker Hubアカウント
  • Play with Dockerで試す場合、必要なもの
    • Play with Dockerを操作可能なブラウザ
  • Play with Docker以外で試す場合、必要なもの
    • Dockerをセットアップ済のPC等

1-4. 各種のバージョン

2020年11月24日時点で動作確認済のバージョンは以下の通りです。

  • docker
    • Docker version 19.03.11, build 42e35e61f3
  • localstack
    • 0.12.2
  • aws-cli
    • aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2
  • aws-cdk
    • 1.74.0
  • aws-cdk-local
    • 1.65.0

2. チュートリアル

このチュートリアルではLocalStackというローカルでAWSを擬似的に使用できるツールを用います。詳しい説明は以下の記事をご参考ください。
LocalStack を使って無料で AWS を学ぶ

このLocalStackのDockerコンテナ内に擬似的なAWS環境を立て、そこへAWS CDKをデプロイし、動作確認を行っていきます。

2-1. 最終的なファイル構成

いきなりですが、このチュートリアルが完了した状態のファイル構成です。
以下の「▶︎ 詳細」をクリックしてご確認ください。


$ tree -L 5 -I node_modules
.
├── localstack
│   ├── CHANGELOG.md
│   ├── Dockerfile
│   ├── LICENSE.txt
│   ├── MANIFEST.in
│   ├── Makefile
│   ├── README.md
│   ├── bin
│   │   └── 略
│   ├── doc
│   │   └── 略
│   ├── docker-compose.yml
│   ├── localstack
│   │   └── 略
│   ├── requirements.txt
│   ├── setup.py
│   └── tests
│       └── 略
├── node_workdir
│   ├── Dockerfile
│   ├── app
│   │   └── sample
│   │       ├── README.md
│   │       ├── bin
│   │       │   ├── sample.d.ts
│   │       │   ├── sample.js
│   │       │   └── sample.ts
│   │       ├── cdk.json
│   │       ├── cdk.out
│   │       │   ├── SampleStack.template.json
│   │       │   ├── cdk.out
│   │       │   ├── manifest.json
│   │       │   └── tree.json
│   │       ├── jest.config.js
│   │       ├── lib
│   │       │   ├── sample-stack.d.ts
│   │       │   ├── sample-stack.js
│   │       │   └── sample-stack.ts
│   │       ├── package-lock.json
│   │       ├── package.json
│   │       ├── test
│   │       │   ├── sample.test.d.ts
│   │       │   ├── sample.test.js
│   │       │   └── sample.test.ts
│   │       └── tsconfig.json
│   └── docker-compose.yml
└── s3.txt

2-2. LocalStackのセットアップ

2-2-1. LocalStackをダウンロードする

[node1] (local) root@192.168.0.18 ~
$ git clone https://github.com/localstack/localstack
Cloning into 'localstack'...
remote: Enumerating objects: 44, done.
remote: Counting objects: 100% (44/44), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 14028 (delta 15), reused 13 (delta 5), pack-reused 13984
Receiving objects: 100% (14028/14028), 5.75 MiB | 9.78 MiB/s, done.
Resolving deltas: 100% (9762/9762), done.

2-2-2. LocalStackコンテナを起動する

[node1] (local) root@192.168.0.18 ~
$ cd localstack

[node1] (local) root@192.168.0.18 ~/localstack
$ docker-compose up -d
WARNING: The TMPDIR variable is not set. Defaulting to a blank string.
Pulling localstack (localstack/localstack:)...
latest: Pulling from localstack/localstack
1cff8f8f4790: Pull complete
Digest: sha256:0e85ea6d44e3bf69a415298e72be46d06500ac038faebd98ea7bd9bcbcaab614
Status: Downloaded newer image for localstack/localstack:latest
Creating localstack_main ... done

[node1] (local) root@192.168.0.18 ~/localstack
$ cd ..

2-2-3. LOCALHOST_IP_ADDRESS変数を設定する

[node1] (local) root@192.168.0.18 ~
$ LOCALHOST_IP_ADDRESS=192.168.0.18 # 各自の環境によって異なります!

後ほど、様々なコンテナ内からホストのIPアドレスを使用することになるので、先に変数としてLOCALHOST_IP_ADDRESSを設定しておきます。
Play with Dockerの場合、root@192.168.0.18@以降の192.168.0.18を設定します (Play with Dockerでも毎回IPアドレスが固定ではないのでお気をつけください)。
それ以外の環境で試されている方は、各自で調べていただけると幸いです。

2-2-4. LocalStackのステータスを確認する

[node1] (local) root@192.168.0.18 ~
$ curl "http://${LOCALHOST_IP_ADDRESS}:4566"
{"status": "running"}

https://github.com/localstack/localstack
2020-09-15: A major (breaking) change has been merged in PR #2905 - starting with releases after v0.11.5, all services are now exposed via the edge service (port 4566) only! Please update your client configurations to use this new endpoint.
(DeepLによる翻訳)
PR #2905 に主要な (壊すような) 変更がマージされました - v0.11.5 以降のリリースから、すべてのサービスがエッジサービス (ポート 4566) のみを介して公開されるようになりました! この新しいエンドポイントを使用するために、クライアントの設定を更新してください。

公式githubにport 4566のみで動いてると書いてあるので、curlのポートに:4566を指定しています。
上手く動いていると{"status": "running"}が返ってきます。

2-2-5. Docker版aws-cliをaliasに登録する

[node1] (local) root@192.168.0.18 ~
$ alias awsd='docker run --rm -ti -v ~/.aws:/root/.aws -v $(pwd):/aws amazon/aws-cli'

LocalStackは基本的にはGUIで操作できないのでaws-cliを使用する必要があります。
以下の記事を参考に設定しました。
AWS公式さんがDocker Hubで aws-cli のイメージを公開してくれた!
ちなみにawsd (AWS Dockerの意味) は各自好きなように変更していただいても大丈夫です。

2-2-6. Docker版aws-cliを起動し、バージョンを確認する

[node1] (local) root@192.168.0.18 ~
$ awsd --version
Unable to find image 'amazon/aws-cli:latest' locally
latest: Pulling from amazon/aws-cli
37373184fe69: Pull complete 
fc9d36ec628d: Pull complete 
2ddf91b98617: Pull complete 
9504c29fa015: Pull complete 
21fd79a0d708: Pull complete 
Digest: sha256:8f8283ee998f26145569d411f986f1bdf0c56b1f4005077a22d94c7ed4561fb3
Status: Downloaded newer image for amazon/aws-cli:latest
aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2

初回のDocker版aws-cli実行時にはDockerイメージのプルがまず実行されます。
そして、aws-cliのバージョンが表示されます。
ちなみに、2回目以降は以下のようにDockerイメージのプルが実行されずにDocker版aws-cliを使用できるようになります。

[node1] (local) root@192.168.0.18 ~
$ awsd --version
aws-cli/2.1.3 Python/3.7.3 Linux/4.4.0-189-generic docker/x86_64.amzn.2

2-2-7. LocalStack用のaws-cliのconfigureを設定する

[node1] (local) root@192.168.0.18 ~
$ awsd configure --profile=localstack
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json

上記のように入力してください。
LocalStack用なのでAWS Access Key IDAWS Secret Access Keyは適当な値 (dummy等) で大丈夫です。

2-2-8. LocalStack用の情報入力を省略するaliasを設定する

[node1] (local) root@192.168.0.18 ~
$ alias awsdl="awsd --endpoint-url=http://${LOCALHOST_IP_ADDRESS}:4566 --profile=localstack"

毎回awsd --endpoint-url=http://${LOCALHOST_IP_ADDRESS}:4566 --profile=localstackを入力しなくてもすむように、aliasを設定します。
ちなみにawsdl (AWS Docker Localstackの意味) は各自好きなように変更していただいても大丈夫です。
なお、この記事ではこれ以降のawsコマンドはawsdlとなっています。

2-3. LocalStackの動作確認

Amazon Simple Storage Service (以降、S3) へバケットを登録し、テキストファイルをアップロードできるかを確認します。

2-3-1. S3にバケットを登録する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 mb s3://test-s3
make_bucket: test-s3

2-3-2. S3のバケット一覧を取得する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 ls
2020-11-23 07:04:37 test-s3

2-3-3. S3へファイルをコピーする

[node1] (local) root@192.168.0.18 ~
$ echo "test text" > s3.txt

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 cp ./s3.txt s3://test-s3
upload: ./s3.txt to s3://test-s3/s3.txt 

2-3-4. 指定したS3のバケットのファイル一覧を取得する

[node1] (local) root@192.168.0.18 ~
$ awsdl s3 ls test-s3
2020-11-23 07:05:43         10 s3.txt

2-4. Node.js環境のセットアップ

今回はAWS CDKをTypeScriptを使用して作成するので、Node.js環境が必要となります。
特別な理由はないですが、Node.js環境もDockerで準備していきます。

2-4-1. Node.js環境作業ディレクトリを作成する

[node1] (local) root@192.168.0.18 ~
$ mkdir node_workdir && cd node_workdir

[node1] (local) root@192.168.0.18 ~/node_workdir
$ mkdir app

2-4-2. Dockerfileを作成する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ vi Dockerfile

以下のファイルの中身をコピペしてください。

Dockerfile
FROM node:14-alpine
WORKDIR /app
CMD ["sh"]

2-4-3. docker-compose.ymlを作成する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ vi docker-compose.yml

以下のファイルの中身をコピペしてください。

docker-compose.yml
version: '3'
services:
  app:
    build: .
    image: my-node-image
    volumes:
      - ./app:/app
    environment:
      - LOCALSTACK_HOSTNAME=${LOCALHOST_IP_ADDRESS}
    tty: true

environmentのLOCALSTACK_HOSTNAMEは後ほど出てくるaws-cdk-localライブラリ内で必要となります。

aws-cdk-local/bin/cdklocalから一部抜粋
const getLocalEndpoint = () => {
  const port = process.env.EDGE_PORT || DEFAULT_EDGE_PORT;
  const host = process.env.LOCALSTACK_HOSTNAME || DEFAULT_HOSTNAME;
  return `http://${host}:${port}`;
};

2-4-4. Node.js環境作業ディレクトリの中身を確認する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ ls
Dockerfile          app                 docker-compose.yml

3つの項目が表示されていたら、次の工程へ移りましょう。

2-4-5. Node.js環境コンテナを起動する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ LOCALHOST_IP_ADDRESS=$LOCALHOST_IP_ADDRESS docker-compose up -d
Creating network "node_workdir_default" with the default driver
Building app
Step 1/3 : FROM node:14-alpine
14-alpine: Pulling from library/node
cbdbe7a5bc2a: Pull complete
f2ffd52523c3: Pull complete
48a445fb9d78: Pull complete
7a27e63388b2: Pull complete
Digest: sha256:d41417bb7fd04744cd159a40632f918c13bc1af3486a848782e1f68af2c3e6cb
Status: Downloaded newer image for node:14-alpine
 ---> 7f1893c3ede0
Step 2/3 : WORKDIR /app
 ---> Running in 47b57683cdda
Removing intermediate container 47b57683cdda
 ---> 71423a0bee1b
Step 3/3 : CMD ["sh"]
 ---> Running in e23e65a6f1f7
Removing intermediate container e23e65a6f1f7
 ---> c695ce33957e
Successfully built c695ce33957e
Successfully tagged my-node-image:latest
WARNING: Image for service app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating node_workdir_app_1 ... done

docker-compose up -dコマンドの前にLOCALHOST_IP_ADDRESS=$LOCALHOST_IP_ADDRESSの指定を忘れないようにお気をつけください。
コンテナの起動に成功するとCreating node_workdir_app_1 ... doneのように生成されたコンテナの名前が出力されます。

2-4-6. Node.js環境コンテナの中に入る

[node1] (local) root@192.168.0.18 ~/node_workdir
$ docker exec -it node_workdir_app_1 sh
/app # 

先ほど生成されたコンテナの名前を指定してdocker execコマンドを実行します。
オプションに-itを、コマンドにshを指定しているので、コンテナの中に入ることができます。
Dockerコンテナに入る方法については以下の記事をご参考ください。
docker exec -itって実際は何をしてるの?【90日目】

なお、「2-5. AWS CDKプロジェクトの作成〜デプロイ」は、このコンテナの中に入っている状態で進めていきます。

2-5. AWS CDKプロジェクトの作成〜デプロイ

aws-cdkでプロジェクトを作成し、aws-cdk-localでLocalStackへデプロイしていきます。

2-5-1. aws-cdkとaws-cdk-localをグローバルインストールする

/app # npm install -g aws-cdk
/usr/local/bin/cdk -> /usr/local/lib/node_modules/aws-cdk/bin/cdk
+ aws-cdk@1.74.0
added 188 packages from 186 contributors in 12.617s

/app# npm install -g aws-cdk-local
/usr/local/bin/cdklocal -> /usr/local/lib/node_modules/aws-cdk-local/bin/cdklocal
+ aws-cdk-local@1.65.0
added 189 packages from 187 contributors in 7.703s

2-5-2. サンプルcdkプロジェクト用ディレクトリを作成し、移動する

/app # mkdir sample && cd sample

2-5-3. サンプルcdkプロジェクトを作成する

/app/sample # cdk init sample-app --language=typescript
Applying project template sample-app for typescript
# Welcome to your CDK TypeScript project!

You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`SampleStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template

Initializing a new git repository...
/bin/sh: git: not found
Unable to initialize git repository for your project.
Executing npm install...
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.2 (node_modules/jest-haste-map/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.2.1: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN sample@0.1.0 No repository field.
npm WARN sample@0.1.0 No license field.

✅ All done!

cdk initコマンドで--language=typescriptを指定してTypeScriptでファイルが生成されるようにしています。
また、sample-appと指定すると、簡単なサンプルを含んだプロジェクトが生成されます。出力の中に簡単なサンプルについての説明があります。

You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`SampleStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.

(DeepLによる翻訳)
このプロジェクトの内容を探ってみてください。スタック (SampleStack) のインスタンスを持つ CDK アプリのデモを行います。
これは、Amazon SNSのトピックにサブスクライブされているAmazon SQSキューを含んでいます。

生成された簡単なサンプルのソースコードを、ちょっとだけ見てみましょう。

/app/sample # vi ./lib/sample-stack.ts
./lib/sample-stack.ts
import * as sns from '@aws-cdk/aws-sns';
import * as subs from '@aws-cdk/aws-sns-subscriptions';
import * as sqs from '@aws-cdk/aws-sqs';
import * as cdk from '@aws-cdk/core';

export class SampleStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const queue = new sqs.Queue(this, 'SampleQueue', {
      visibilityTimeout: cdk.Duration.seconds(300)
    });

    const topic = new sns.Topic(this, 'SampleTopic');

    topic.addSubscription(new subs.SqsSubscription(queue));
  }
}

Amazon Simple Queue Service (以降、SQS) のキューとAmazon Simple Notification Service (以降、SNS)のトピックとサブスクリプションが定義されています。SNSトピックからメッセージを発行すると、サブスクリプションとして登録されているキューに登録されるようになっています。

2-5-4. TypeScriptファイルをJavaScriptファイルにトランスパイルする

/app/sample # npm run build

> sample@0.1.0 build /app/sample
> tsc

ブラウザやNode.js環境はJavaScriptしか実行できないため、TypeScriptファイルをJavaScriptファイルへ必ず変換しましょう。

2-5-5. 初めてデプロイする場合、デプロイ用のS3バケットを作成する

/app/sample # cdklocal bootstrap
 ⏳  Bootstrapping environment aws://000000000000/us-east-1...
CDKToolkit: creating CloudFormation changeset...
[··························································] (0/3)

 ✅  Environment aws://000000000000/us-east-1 bootstrapped.

2-5-6. LocalStackへデプロイする

/app/sample # cdklocal deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬─────────────────────────┬────────┬─────────────────┬─────────────────────────┬───────────────────────────┐
│   │ Resource                │ Effect │ Action          │ Principal               │ Condition                 │
├───┼─────────────────────────┼────────┼─────────────────┼─────────────────────────┼───────────────────────────┤
│ + │ ${SampleQueue.Arn}      │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.c │ "ArnEquals": {│   │                         │        │                 │ om                      │   "aws:SourceArn": "${Sam │
│   │                         │        │                 │                         │ pleTopic}"                │
│   │                         │        │                 │                         │ }                         │
└───┴─────────────────────────┴────────┴─────────────────┴─────────────────────────┴───────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
SampleStack: deploying...
SampleStack: creating CloudFormation changeset...
[··························································] (0/6)


 ✅  SampleStack

Stack ARN:
arn:aws:cloudformation:us-east-1:000000000000:stack/SampleStack/3b39e2b2-bb7d-42d0-9b36-d53e069c1451

途中でDo you wish to deploy these changes (y/n)?と入力を求められるので、問題がなければyを入力しましょう。

2-5-7. Node.js環境コンテナから抜け出す

/app/sample # exit
[node1] (local) root@192.168.0.18 ~/node_workdir
$ 

2-6. AWS CDKからLocalStackへデプロイされたリソースの動作確認

「リソースが生成されているか」と「SNSトピックからメッセージを発行し、サブスクリプションとして登録されているキューに登録されるか」を確認していきます。

2-6-1. SQSキューの一覧を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs list-queues
{
    "QueueUrls": [
        "http://localhost:4566/000000000000/queue-7f6ead47"
    ]
}

SQSキューがちゃんと生成されていますね。
ちなみに、QueueUrlsに表示されている値は各自の環境で異ります。

2-6-2. 指定したSQSキューの詳細を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs get-queue-attributes --queue-url http://localhost:4566/000000000000/queue-7f6ead47
{
    "Attributes": {
        "ApproximateNumberOfMessages": "0",
        "ApproximateNumberOfMessagesDelayed": "0",
        "ApproximateNumberOfMessagesNotVisible": "0",
        "CreatedTimestamp": "1606116190.41501",
        "DelaySeconds": "0",
        "LastModifiedTimestamp": "1606116190.41501",
        "MaximumMessageSize": "262144",
        "MessageRetentionPeriod": "345600",
        "QueueArn": "arn:aws:sqs:us-east-1:000000000000:queue-7f6ead47",
        "ReceiveMessageWaitTimeSeconds": "0",
        "VisibilityTimeout": "300"
    }
}

--queue-urlに指定する値は「2-6-1. SQSキューの一覧を取得する」で取得した各自の値を指定してください。
今回はとりあえず出力結果のうち、次の一項目だけ確認します。ApproximateNumberOfMessages (キューから取得可能なメッセージのおおよその数) が"0"になっていることが確認できましたでしょうか。

2-6-3. SNSトピックの一覧を取得する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sns list-topics
{
    "Topics": [
        {
            "TopicArn": "arn:aws:sns:us-east-1:000000000000:topic-cac07a20"
        }
    ]
}

SNSトピックもちゃんと生成されていますね。
TopicArnも同様に表示されている値は各自の環境で異ります。

2-6-4. 指定したSNSトピックへメッセージを発行する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sns publish --message "test message" --topic-arn "arn:aws:sns:us-east-1:000000000000:topic-cac07a20"
{
    "MessageId": "d06d6c48-fba9-4b8b-ab09-5f96e0784aef"
}

--topic-arnに指定する値は「2-6-3. SNSトピックの一覧を取得する」で取得した各自の値を指定してください。
発行に成功するとMessageIdが入ったJSONが返ってきます。

2-6-5. 指定したSQSキューの詳細を取得し、ApproximateNumberOfMessagesを確認する

[node1] (local) root@192.168.0.18 ~/node_workdir
$ awsdl sqs get-queue-attributes --queue-url http://localhost:4566/000000000000/queue-7f6ead47
{
    "Attributes": {
        "ApproximateNumberOfMessages": "1",
        "ApproximateNumberOfMessagesDelayed": "0",
        "ApproximateNumberOfMessagesNotVisible": "0",
        "CreatedTimestamp": "1606116190.41501",
        "DelaySeconds": "0",
        "LastModifiedTimestamp": "1606116190.41501",
        "MaximumMessageSize": "262144",
        "MessageRetentionPeriod": "345600",
        "QueueArn": "arn:aws:sqs:us-east-1:000000000000:queue-7f6ead47",
        "ReceiveMessageWaitTimeSeconds": "0",
        "VisibilityTimeout": "300"
    }
}

「2-6-2. 指定したSQSキューの詳細を取得する」と同じコマンドを実行しましょう。
ApproximateNumberOfMessages (キューから取得可能なメッセージのおおよその数) が"1"になっていたら、SNSトピックから発行されたメッセージがSQSキューに登録される処理がうまくいった証拠です!

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

gem install: SSL verification error at depth 1: unable to get local issuer certificate

状況

GitHub Actionsを利用したDocker buildx中のgem installで以下のエラーが発生

#24 [linux/arm/v7  7/10] RUN gem install iconv
#24 2.493 ERROR:  SSL verification error at depth 1: unable to get local issuer certificate (20)
#24 2.495 ERROR:  You must add /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA to your local trusted store

ベースコンテナはDocker Hubのhttpd:2.4.46httpd:2.4.43(2020年11月時点のlatest)のlinux/arm/v7です。
linux/arm64linux/amd64では発生していません。

詳しくはレポジトリを参照してください。
後述の通りその後対処が不要になったのでDockerfile等は当時の版を参照。

原因

原因は書いてある通り証明書エラーです。
GlobalSign Root CAの証明書が入っていません。

対処

証明書を追加すれば解決します。
Bundlerのページにあるトラブルシュートに従い、pemファイルへの直接リンクからダウンロードします。
署名の追加方法はLife with ITさんの記事@msiさんの記事に従いました。

ただし、証明書が不足している/古い場合はcurlが動作しないことがあります、Dockerfile内ではなく外部でcurlから取得し、COPYした方が良いでしょう。

.github/workflows/docker.yml
      - name: Download GlobalSignRootCA.pem
        run: curl https://raw.githubusercontent.com/rubygems/rubygems/master/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem -o GemCert.pem
Dockerfile
COPY GemCert.pem /tmp/GemCert.pem
RUN mkdir /usr/share/ca-certificates/Gem && \
    cp /tmp/GemCert.pem /usr/share/ca-certificates/Gem && \
    echo "Gem/GemCert.pem" >> /etc/ca-certificates.conf && \
    update-ca-certificates && \
    rm /tmp/GemCert.pem

なお、apt-get install ca-certificatesでは解決しませんでした。
他には、

$ curl -Lks 'https://git.io/rg-ssl' | ruby # SSLのチェック
$ gem install bundler # Bundlerの更新
$ gem update --system # RubyGemsの更新

が推奨されていました。私の場合更新は必要ありませんでしたが、チェックスクリプトは便利です。

懸念点

SSLの証明書をGitHubからダウンロードするというのはセキュリティ上心配です。
GitHubでなくとも将来ずっとURLが維持されるか、証明書自体が今後も信用できるのかなど不安が残ります。
特に定期実行もするGitHub Actionsで現時点で動作するだけのワークアラウンドも避けた方が良いでしょう。

私の場合は、この後ソースコードを修正しgem install自体が不要になり、この対処を削除しました。

参考記事

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

Docker buildでのSSL証明書エラー対処 【GitHub Actions】

状況

GitHub Actionsを利用したDocker buildx中のgem installで以下のエラーが発生

#24 [linux/arm/v7  7/10] RUN gem install iconv
#24 2.493 ERROR:  SSL verification error at depth 1: unable to get local issuer certificate (20)
#24 2.495 ERROR:  You must add /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA to your local trusted store

ベース・イメージはDocker Hubのhttpd:2.4.46httpd:2.4.43(2020年11月時点のlatest)のlinux/arm/v7です。
linux/arm64linux/amd64では発生していません。

詳しくはレポジトリを参照してください。
後述の通りその後対処が不要になったのでDockerfile等は当時の版を参照。

原因

原因は書いてある通り証明書エラーです。
GlobalSign Root CAの証明書が入っていません。

対処

証明書を追加すれば解決します。
Bundlerのページにあるトラブルシュートに従い、pemファイルへの直接リンクからダウンロードします。
署名の追加方法はLife with ITさんの記事@msiさんの記事に従いました。

ただし、証明書が不足している/古い場合はcurlが動作しないことがあります、Dockerfile内ではなく外部でcurlから取得し、COPYした方が良いでしょう。

.github/workflows/docker.yml
      - name: Download GlobalSignRootCA.pem
        run: curl https://raw.githubusercontent.com/rubygems/rubygems/master/lib/rubygems/ssl_certs/index.rubygems.org/GlobalSignRootCA.pem -o GemCert.pem
Dockerfile
COPY GemCert.pem /tmp/GemCert.pem
RUN mkdir /usr/share/ca-certificates/Gem && \
    cp /tmp/GemCert.pem /usr/share/ca-certificates/Gem && \
    echo "Gem/GemCert.pem" >> /etc/ca-certificates.conf && \
    update-ca-certificates && \
    rm /tmp/GemCert.pem

なお、apt-get install ca-certificatesでは解決しませんでした。
他には、

$ curl -Lks 'https://git.io/rg-ssl' | ruby # SSLのチェック
$ gem install bundler # Bundlerの更新
$ gem update --system # RubyGemsの更新

が推奨されていました。私の場合更新は必要ありませんでしたが、チェックスクリプトは便利です。

なお、今回は証明書をインストールしましたが、SSLなしに設定するという選択肢もあります。お勧めしません。

懸念点

SSLの証明書をGitHubからダウンロードするというのはセキュリティ上心配です。
GitHubでなくとも将来ずっとURLが維持されるか、証明書自体が今後も信用できるのかなど不安が残ります。
特に定期実行もするGitHub Actionsで現時点で動作するだけのワークアラウンドも避けた方が良いでしょう。

ここではやりませんでしたが、追加し処理が終わった後証明書を削除するのも一つのやり方でしょう。

私の場合は、この後ソースコードを修正しgem install自体が不要になり、この対処を削除しました。

参考記事

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

【ほぼ無料】FreenomとLet's Encryptを使って0円でドメインとSSL証明書を手に入れて、AWS EC2にdockerを入れてnginxコンテナを起動してドメインで繋がるHTTPS WEBサービスを立ち上げる方法

経緯

何か業務で使う技術や新しい技術を試したいときにAWS上にWebサーバーを立ててAPIとかテストページとか用意して、ローカルのChromeやAndroid端末からhttpで繋いでごにょごにょやるってのを結構やる。
RestAPIの疎通確認ぐらいならそれでいいんだけど、WebRTCやWebSocketの検証で使いたい場合、SSL化されたサイトでないとエラーになって接続できないため動作確認が出来ない問題があった。
どうにかこうにか安価でオレオレ証明書じゃないWebサーバーを立てられないかなーと調べたところ、FreenomとLet's Encryptを使えばほぼ無料で独自ドメインのhttpsサーバーを立てられそうだと判明。

Freenomでのドメイン取得方法やLet's EncryptでのSSL証明書取得方法、それらをAWSで設定するやり方等は探せば断片的にはあるけど、全部まとまった記事は無かったので、備忘録もかねてここに残しておく。

やること

  1. 【無料】Freenomで無料ドメインを取得する
  2. 【条件付無料】AWS EC2インスタンスを作成してdockerをインストールする
  3. 【条件付無料】AWS Elastic IPで静的IPアドレスを発行してEC2インスタンスに関連付ける
  4. 【ほぼ無料】AWS Route53でDNS設定を行いドメイン名でEC2インスタンスに繋がるようにする
  5. 【無料】dockerでEC2インスタンスにnginxコンテナを立ち上げる
  6. 【無料】Let's Encryptで無料SSL証明書を取得してhttpsで繋がるようにする

無料の条件とほぼ無料の詳細

  • AWS EC2インスタンスは無料利用枠を使用する
    • 無料利用枠と記載のあるAmazonマシンイメージ(AMI)は月に750時間無料で使える。今回はそれを使うことで無料とする
  • ElasticIPで割り当てたEC2インスタンスは起動したままにしておく
    • ElasticIPで発行したIPアドレスがEC2インスタンスに関連付けされていない場合は課金が発生する。いくら課金されるかは調べていないがわずかであるらしい。こういう仕組みになっているのは無駄にIPアドレスを確保されるのを防ぐためだろう。
  • AWS Route53では月に0.5$課金される
    • 下記は公式(2020年11月現在)から抜粋してきたもの。まあこのくらいなら缶コーヒー半分くらいだし、いいよね。 image.png

1. 【無料】Freenomで無料ドメインを取得する

早速やっていきます。ドメインはFreenomというサービスを使って取得します。Freenomとは、ドメインを無料で取得出来る海外のサービスです。ドメイン名は、XXXX.tkやXXXX.ml、XXXX.ga等が無料で取得できます。
https://www.freenom.com/ja/index.html

ドメインが使えることを確認し、チェックアウトする

好きなドメインを取得することが出来ますので、取得したいドメインを入力しましょう。利用可能か調べてくれて利用可能であれば以下のような画面になりますので「今すぐ入手!」を押下した後、「チェックアウト」を押下します。

image.png


image.png

使用期間を選択する

12ヵ月まで無料で使えるようですので、最大限使用させていただきましょう。Periodで「12 Months @ FREE」を選択して「Continue」を押下します。

image.png

ユーザー登録 or ログイン

金額が$0.00USD(無料)なのを確認します。問題なければ購入のためログインします。
私の場合は既に登録済みなので、普通にGoogleでログインします。
初回登録してないと、いろいろ登録しないといけないかもしれません。
image.png

規約に同意して購入

再度、金額が$0.00USD(無料)なのを確認してから、規約に同意のチェックを入れ、「Complete Order」を押下します。

image.png


image.png


image.png

これにてドメインの取得は完了しました。

2. 【条件付無料】AWS EC2インスタンスを作成してdockerをインストールする

こちらは私が書いた別の記事がそのまま使用できますので、こちら↓を参照ください。

AWS EC2インスタンスにdockerとdocker-composeをインストールして簡単なWEBサービスを立ち上げる方法

3. AWS Elastic IPで静的IPアドレスを発行してEC2インスタンスに関連付ける

静的IPアドレス(固定IPアドレス)を取得し、上記で起動したEC2インスタンスにそのIPアドレスを割り当てます。こうすることで、EC2を再起動したりしてもIPアドレスが変わることは無くなります。

静的IPアドレスを取得する

まずは画面操作して静的IPアドレスを取得します。
「Elastic IP」を押下し、
image.png
次の画面で「Elastic IP アドレスの割り当て」を押下します。
image.png
次の画面で「割り当て」を押下します。
image.png
静的IPアドレスが取得できました。
image.png

EC2インスタンスに静的IPアドレスを関連付ける

割り当てられたIPアドレスを選択状態にして「アクション」内の「Elastic IPアドレスの関連付け」を押下します。
image.png
インスタンスには、先ほど作成したEC2のインスタンスIDを入力します。
入力したら「関連付ける」を押下します。
image.png

EC2インスタンスと静的IPアドレスの関連付けが完了しました。
image.png

4. 【ほぼ無料】AWS Route53でDNS設定を行いドメイン名でEC2インスタンスに繋がるようにする

ドメイン名で繋がるようにDNS設定を行います。
ホストゾーン作成→Aレコード登録→FreenomでNameserver設定という手順になります。

ホストゾーンの作成

Route53の画面に行き、
image.png
「ホストゾーン」を押下します。
image.png
「ホストゾーンの作成」を押下します。
image.png
Freenomで取得したドメインを入力して「ホストゾーンの作成」を押下します。
image.png
ホストゾーンの作成が完了しました。
image.png

Aレコードの作成

「レコードの作成」を押下します。
image.png
シンプルルーティングがデフォルト選択されているのを確認して「次へ」を押下します。
image.png
「シンプルなレコードを定義」を押下します。
image.png
値/トラフィックのルーティング先で「レコードタイプに応じたIPアドレスまたは別の値」を選択した後、先ほど取得した静的IPアドレスを入力して、「シンプルなレコードを定義」を押下します。
image.png
レコードの作成を押下します。
image.png
レコードの作成が完了しました。
image.png

Nameserverの設定

今度はFreenomでNameserverの設定を行います。

「My Domains」を押下し、次の画面で「Manage Domain」を押下します。

image.png


image.png
「Management Tools」の「Nameservers」を押下します。
image.png
「Use custom nameservers(enter below)」を選択、Nameserver欄にはRoute53 ホストゾーンのNSレコードの値をコピペします。
入力したら「Change Nameservers」を押下します。
image.png

この時点で数分経過すると、DNSが浸透して行って「http://ドメイン名」でサイトが表示されるようになっているかと思います。
image.png

5. 【無料】dockerでEC2インスタンスにnginxコンテナを立ち上げる

6. 【無料】Let's Encryptで無料SSL証明書を取得してhttpsで繋がるようにする

5と6は一気にやっちゃいます。
いろいろやり方はあるかと思いますが、以下構成でdockerを使用してやってみます。

  • reverse-proxyコンテナをインターネットに公開し、https通信を受け付けます。
  • reverse-proxyコンテナからwebコンテナへ通信を転送、webコンテナではreverse-proxyからhttp通信を受け付けます。

Untitled Diagram.png

全てのdockerを停止しておく

誤動作防止のため、作業前に一度全てのdockerコンテナを止めて、dockerオブジェクトも全部削除しておくといいでしょう。

docker stop $(docker ps -q)
docker system prune -a

webコンテナの作成と起動

homeディレクトリ配下にwebディレクトリを作成し、必要な構成ファイルを作成します。

cd
mkdir web

ディレクトリ配下とファイルの内容は以下のような構成にしました。

ディレクトリ構成
web
  - html
      - index.html # hogeとでも書いておく
  - docker-compose.yml
docker-compose.yml
version: '3'

services:
  web:
    image: nginx:latest
    container_name: web
    volumes:
      - ./html:/usr/share/nginx/html

作成が終わったらdockerコンテナを起動します。

docker-compose up -d --build

起動したことを確認します。

docker-compose ps
Name              Command               State   Ports
------------------------------------------------------
web    /docker-entrypoint.sh ngin ...   Up      80/tcp

reverse-proxyコンテナの作成と起動

homeディレクトリ配下にreverse-proxyディレクトリを作成し、必要な構成ファイルを作成します。

cd
mkdir reverse-proxy

ディレクトリ配下とファイルの内容は、悪戦苦闘の結果、以下のような構成にしました。

ディレクトリ構成
reverse-proxy
  - reverse-proxy
    - default.conf
    - Dockerfile
    - entrypoint.sh
  - docker-compose.yml
default.conf
server{

    server_name y-do.tk;

    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
      proxy_pass     http://web/;
    }

}
Dockerfile
FROM nginx

COPY default.conf /etc/nginx/conf.d/default.conf

RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

RUN apt-get update && apt-get install -y \
  wget cron && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/*

ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh

ADD https://dl.eff.org/certbot-auto /usr/local/bin/certbot-auto
RUN chmod a+x /usr/local/bin/certbot-auto
RUN certbot-auto --os-packages-only -n

COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]
entrypoint.sh
#!/bin/bash

# hogehoge@example.comはメールアドレス
certbot-auto --nginx -d y-do.tk -m hogehoge@example.com --agree-tos -n
certbot-auto renew

# cron job settings
# Let's Encrypt automatic Renew
echo '0 8 * * * certbot-auto renew --post-hook "nginx -s reload"' >> /cron-tmpfile
crontab /cron-tmpfile
rm /cron-tmpfile

# cron start
/etc/init.d/cron start

/bin/bash
docker-compose.yml
version: '3'

services:
  reverse-proxy:
    build: ./reverse-proxy
    tty: true
    container_name: reverse-proxy
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - '/srv/letsencrypt:/etc/letsencrypt'
    command: ["wait-for-it.sh", "web:80"]
    networks:
      - default
      - web_default

networks:
  web_default:
    external: true

作成が終わったらdockerコンテナを起動します。

docker-compose up -d --build

起動したことを確認します。

docker-compose ps
    Name                   Command               State                    Ports
-------------------------------------------------------------------------------------------------
reverse-proxy   entrypoint.sh wait-for-it. ...   Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

インターネットからhttpsで繋がるようにAWSでセキュリティグループを更新する

FWで弾かれているため、まだインターネットからhttps通信を受け付けることが出来ません。
AWSのセキュリティグループのインバウンドルールを修正します。

ルールを追加して、タイプ「HTTPS」、ソースは「0.0.0.0/0」を入力します。
入力したら「ルールを保存」を押下します。

image.png

動作確認

ここまでやってやっとhttpsで通信が出来るようになっているはずです。アクセスしてみます。

image.png


image.png

アクセス出来た!!!

結果

月額0.5USDで独自ドメインのSSLサイトが運用できる。
ただし、ドメインは12ヵ月、SSL証明書は3か月で有効期限が切れる(無料だから文句は言えない)ので、今後は自動更新の仕組みを導入したい

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

WSL2 + Ubuntu18.04 + Docker環境構築

はじめに

アドベントカレンダー11日目の記事です。
今回は、WindowsでWSL2環境のセットアップ方法を紹介します。

巷に記事はたくさんありますが、情報が古くエラーが発生して上手く動作しなかったり。。。
記事とターミナルを行ったり来たりで時間がかかったりと、セットアップに煩わしさを感じることが多いのではないでしょうか

本記事では、そんな大変な設定をシェルスクリプトで大部分を構築する方法を紹介します。

環境

  • Ubuntu18.04LTS(64bit)を想定しています。
    ※ Ubuntu 20.04の場合は、適宜置き換えてください。
  • Windows OSビルド 19041以上

Ubuntu 18.04のインストール

Microsoft StoreからUbuntu 18.04LTSをインストールします
image.png

WSL1の設定

インストールしたUbuntu 18.04をスタートメニューから開いてユーザ名やパスワードを設定します

Ubuntu18.04ターミナル
# 初回起動時は初期設定が必要
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: # <= ログインユーザ名を設定
Enter new UNIX password: # <= ログインパスワードを設定(sudo コマンド実行時等に必要なため忘れないようにする)
Retype new UNIX password: # <= ログインパスワードをもう一度入力

# 初期設定を行うと WSLにUbuntu 18.04 ディストロが追加される
# ここで一旦終了する
$ exit

WSL2有効化

PowerShellを管理者権限で開いて下記コマンドを入力します。

# WSL2 を使うために、Windows仮想化機能(Hyper-V)を有効化
> Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
この操作を完了するために、今すぐコンピューターを再起動しますか?
[Y] Yes  [N] No  [?] ヘルプ (既定値は "Y"): # そのままENTERして再起動

# 再起動が完了したらWSLのバージョン確認
## 現状の Ubuntu 18.04はVersion 1 になっているはずです
> wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-18.04    Stopped         1

# 先にインストールしていたUbuntu 18.04をWSL2環境に変換する
> wsl --set-version Ubuntu-18.04 2

# 「WSL 2 を実行するには、カーネル コンポーネントの更新が必要です。」というエラーが出た場合
## => https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi をインストールして再実行する

# 変換が完了したらバージョン確認
## Ubuntu 18.04がVersion 2になっていればOK
> wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-18.04    Stopped         2

WSL2の有効化が完了しました。
次は、WSL2を開いて基本設定を行います。

基本設定

Ubuntu環境を一括で設定するためのシェルスクリプトを用意しました。
記事を見ながらコピペすることなく基本的なものは一括でインストールすることができます。

やること

  • ミドルウェアのインストール
    • 動作に必要な基本ミドルウェアのインストール
    • PythonやNode.jsをビルドするために必要なミドルウェアをインストール
  • カラーテーマの設定

    • ColorToolを利用してOneHalfDarkテーマを適用します
    • 無題.png
  • Linuxbrewのインストール

    • MacでおなじみのHomebrewのLinux版です
  • Dockerのインストール

    • Windows版DockerクライアントをインストールすることなくWSL内で完結するDocker環境を構築します
    • メリットとしては、Dockerクライアントを常時起動しなくても良いのでリソースの節約に繋がります

シェルスクリプトで実行

~/init.shを作成し、下記の全文をコピー
スクリプト中の[USER_NAME]を自身のWindowsのユーザ名に変更します

~/init.sh
#!/bin/bash


install_colortool()
{
  echo 'カラーテーマの適用'
  # ColorToolのダウンロード先
  ## [USER_NAME]はWindowsのユーザ名に適宜変更
  DOWNLOAD_PATH="/mnt/c/Users/[USER_NAME]/Downloads"
  # 適用したいカラーテーマ(今回はOneHalfDarkを選択)
  # 変えたい場合は、ColorTool.exe -s で選択可能なテーマを確認して置き換える
  COLOR_THEME="OneHalfDark.itermcolors"

  echo 'ColorTool.zipのダウンロード'
  wget -P "${DOWNLOAD_PATH}" https://github.com/microsoft/terminal/releases/download/1904.29002/ColorTool.zip

  echo 'zipファイルの解凍'
  unzip "${DOWNLOAD_PATH}/ColorTool.zip" -d "${DOWNLOAD_PATH}/ColorTool"

  echo 'zipファイルの削除'
  rm "${DOWNLOAD_PATH}/ColorTool.zip"

  echo 'カラーテーマの種類'
  `echo ${DOWNLOAD_PATH}/ColorTool/ColorTool.exe -s`

  echo 'OneHalfDarkテーマの選択'
  # その他のテーマを変更したい場合は-dオプションの後を置き換える
  `echo ${DOWNLOAD_PATH}/ColorTool/ColorTool.exe -d ${COLOR_THEME}`

  echo '解凍したフォルダの削除'
  rm -r "${DOWNLOAD_PATH}/ColorTool"
}


install_linuxbrew()
{
  echo 'Linuxbrew (Linux版の Homebrew パッケージマネージャ) 導入'
  ## Linuxbrew を使うことで最新の開発ツール等を導入しやすくなる
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
  echo 'PATHを通す'
  echo 'export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"' >> ~/.bashrc
  source ~/.bashrc

  echo 'Linuxbrew で各種開発ツールを導入'
  ## curl や git などは、最新版を使う方が良いため、改めて Linuxbrew で導入しなおす
  brew install curl git wget gcc zlib libzip bzip2 readline openssl pkg-config autoconf
}


install_anyenv()
{
  echo 'Linuxbrewでanyenv導入'
  brew install anyenv
  anyenv install --init

  echo 'anyenv初期化スクリプトを.bashrc に記述'
  echo 'eval "$(anyenv init -)"' >> ~/.bashrc
  source ~/.bashrc

  echo 'anyenv update plugin の導入'
  mkdir -p $(anyenv root)/plugins
  git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update
  anyenv update

  echo 'バージョン確認'
  anyenv -v
}


install_docker()
{
  echo 'Docker (Community Edition) インストール'
  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
  sudo apt update && sudo apt install -y docker-ce

  echo 'WSL2再起動時dockerデーモンをスタートアップに登録するための設定'
  echo 'service docker start を /sbin/mount.rc に追記'
  echo 'service docker start' | sudo tee -a /sbin/mount.rc

  # WSL2にはcgroup用ディレクトリがデフォルトで作られていないため、以下もスタートアップスクリプトに登録しておく
  ## これをしておかないと Docker でプロセスのグループ化が必要になったときにエラーが起きる
  echo 'mkdir -p /sys/fs/cgroup/systemd && mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd' | sudo tee -a /sbin/mount.rc

  echo 'docker-compose 導入'
  sudo curl -L https://github.com/docker/compose/releases/download/1.26.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
  sudo chmod +x /usr/local/bin/docker-compose

  echo 'Dockerをsudoなしで実行可能に'
  echo '※ カレントユーザーをdockerグループに所属させた上で docker.sock へのグループ書き込み権限を付与すればよい'
  sudo gpasswd -a $USER docker
  sudo chgrp docker /var/run/docker.sock
  sudo service docker restart

  echo '設定を反映するためにターミナル再起動'
  exec $SHELL -l
}


echo 'Linuxシステムアップデート'
sudo apt update && sudo apt upgrade -y
echo 'Linuxbewの動作に必要なパッケージのインストール'
sudo apt install -y vim curl git ruby
echo 'openjdkは個人開発で必要なため一応インストール'
sudo apt install -y openjdk-11-jdk
echo 'Pythonビルドに必要なミドルウェアのインストール'
sudo apt install -y zlib1g-dev libssl-dev libbz2-dev libsqlite3-dev libffi-dev \
    build-essential libreadline-dev tk-dev liblzma-dev libgdbm-dev libdb-dev
echo 'https通信を可能にするためのミドルウェアをインストール'
sudo apt install -y software-properties-common apt-transport-https ca-certificates


echo '==========color toolのインストール========='
install_colortool
echo '==========color toolのインストール完了========='
echo '==========linux brewのインストール========='
install_linuxbrew
echo '==========linux brewのインストール完了========='
echo '==========anyenvのインストール========='
install_anyenv
echo '==========anyenvのインストール完了========='
echo '==========Dockerのインストール========='
install_docker
echo '==========Dockerのインストール完了========='

実行属性を与えて実行する。

# 実行属性の付与
$ chmod +x init.sh

# シェルの実行
$ ./init.sh

PythonやNode.jsのインストール

基本設定でインストールしたanyenvを使ってPythonとNode.jsをインストールします。
これらをシェルスクリプトに含めなかった理由としては、exec $SHELL -lを実行するときプログラムが終了してしまうためです。
ステップは多くないので、必要であればインストールしましょう。

Pythonのインストール

pyenvを使ってPython 3.9をインストールします

# anyenv を使って pyenv 導入
$ anyenv install pyenv
$ exec $SHELL -l

# pyenvでPython 3.9をインストール
$ pyenv install 3.9.0

# pyenvによるPythonのバージョン指定
$ pyenv global 3.9.0

# 現在選択されているバージョンを確認
$ pyenv versions

# Pythonのバージョン確認
$ python --version

# pipパッケージマネージャを更新しておく
$ pip3 install --upgrade pip setuptools

# pipのバージョン確認
$ pip3 --version

Node.jsのインストール

nodenvを使ってNode.js 15.2.0をインストールします。

# anyenvを使ってnodenv導入
$ anyenv install nodenv
$ exec $SHELL -l

# nodenv-yarn-install プラグイン導入: nodenv install 時にyarnもインストールする
$ mkdir -p "$(nodenv root)/plugins"
$ git clone https://github.com/pine/nodenv-yarn-install.git "$(nodenv root)/plugins/nodenv-yarn-install"
$ export PATH="$HOME/.yarn/bin:$PATH" >> ~/.bashrc

# Node.js 15.2.0インストール
$ touch $(nodenv root)/default-packages
$ nodenv install 15.2.0

# Node.js 15.2.0 に切り替え
$ nodenv global 15.2.0

# 現在選択されているバージョンを確認
$ nodenv versions

# シェルの再起動
$ exec $SHELL -l

# Node.jsバージョン確認
$ node -v

# yarnバージョン確認
$ yarn -v

おわりに

今回は、WSL2のセットアップを紹介しました。
Docker環境がWSL内で完結するので、本当にLinuxに近い形で利用できそうです。
明日は、@tadahayaさんによる記事です。お楽しみに?

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