20201129のdockerに関する記事は20件です。

Dockerを使ってCakePHP2のブログチュートリアルの開発環境を構築しました。

1 はじめに

CakePHP2のアサインされたので、CakePHP2のブログチュートリアルをやりたいと思い、せっかくなのでDockerを使って環境構築することにしました。
OSはUbuntuで、Dockerのインストールが完了しているものとします。

2 Dockerの考え方

この前Dockerの記事を書きましたのでそれも参考にしてください。
Dockerについて理解した後、実際に導入してみました。 - Qiita

Dockerでは、Dockerイメージというものを使ってコンテナを作成します。
このDockerイメージというものの手に入れ方は2つあります。

  1. 自分でDockerFileを作成して作る。
  2. 誰かがDockerFileを作成して作られたイメージをDockerHubから持ってくる。
  3. 既にあるコンテナをイメージ化する。(非推奨)

3のやり方は、どういうコンテナかわかりづらいのであまりよくないようです。

Docker Hubで公開されているDockerイメージも、それぞれDockerfileが公開されていて、それを元に作成されたイメージです。2.のやり方は、暫定的にDockerイメージにしておきたい場合などに行うくらいが良いと思います。
引用元:Docker入門(第三回)~各種dockerコマンドとDockerイメージ作成について~

基本的には使用するDockerイメージのDockerFileは見れる状態にしておくのが良いみたいですね。
実際に、DockerHubに公開されているイメージのページにいくと、DockerFileが書かれていることが多いです。

そして、DockerHubには様々なイメージが置いてあるので、もはや自分でDockerFileを書くのは面倒くさいです。
できればDockerHubからイメージを持ってきて楽したいですね。



そう思っていた時期が僕にもありました。

・結局細かな設定は自分で行う。
・DockerHubで共有しようがDockerfileの内容を共有しようがあんまり手間が変わらない。

等の理由で、結局自分でDockerfileを書くことのほうが多いという印象を、調べていく中で、うけました。


ちなみに、複数のコンテナを使うときはDockerComposeを使う必要があります。

Docker Composeは、複数のコンテナで構成されるアプリケーションについて、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツールです。
引用元:Docker入門(第六回)〜Docker Compose〜 | さくらのナレッジ

ブログチュートリアルでは、WebサーバとMySQLサーバの2つを使うので、DockerComposeを使う必要があります。

3 環境構築

それでは、環境構築をしていきます。
今回は、以下のサイトを参考に環境構築を進めていきます。
DockerでCakePHP2の開発環境を作ってみた(Mac版) – GeekGirl Cafe

3.1 CakePHP2リポジトリのクローン

まず任意のディレクトリに作業ディレクトリを作成し、CakePHP2をクローンします。

$ mkdir blog-turorial
$ git clone -b 2.x git://github.com/cakephp/cakephp.git blog-tutorial

さて、クローンしたばかりのCakePHPリポジトリですが、これは全世界の人が使うバニラな状態です。
例えば我々は日本人なのでタイムゾーンを東京にしたり、アプリの名前とかを設定したりというのは、個別でしなければなりません。後程使用するMySQLコンテナとの接続設定なども必要です。まずは、以下のサイトを参考にそういう設定をしていきます。

[CakePHP2]インストールの覚え書きです。 - Qiita

3.2 app/tmpのパーミッション修正

app/tmpのパーミッションを変える必要があります。
Apacheからのアクセスを可能にするためみたいです。
これについてはブログチュートリアル内でも説明があると思います。

blog-tutorial$ sudo chmod -R 777 app/tmp

3.3 タイムゾーン設定

タイムゾーンを設定する必要があります。東京にします。

blog-tutorial$ vi lib/Cake/Cache/CacheEngine.php
CacheEngine.php
        if (!is_numeric($this->settings['duration'])) {
            date_default_timezone_set('Asia/Tokyo'); //追加
            $this->settings['duration'] = strtotime($this->settings['duration']) - time();
        }

3.4 データベース設定

データベースの設定を行います。
普通はdatabase.phpはdatabase.php.defaultをコピーしてそれを参考に書きますが今回は新規作成でOKです。

blog-tutorial$ vi app/Config/database.php
database.php
class DATABASE_CONFIG {

    public $default = array(
        'datasource' => 'Database/Mysql',
        'persistent' => false,
        'host' => 'db',
        'login' => 'root',
        'password' => 'root_password',
        'database' => 'blog_tutorial',
        'prefix' => '',
        'encoding' => 'utf8',
    );

}

3.5 Security.saltの設定

Security.saltの設定をします。
これもブログチュートリアル内で説明がありますね。

blog-tutorial$ vi app/Config/core.php
core.php
/**
 * A random string used in security hashing methods.
 */
    Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!'); //ランダムで長い文字列に変更

/**
 * A random numeric string (digits only) used to encrypt/decrypt strings.
 */
    Configure::write('Security.cipherSeed', '7485712659625147843639846751'); //ランダムで長い数字列に変更

3.6 DebugKitをインストール

DebugKitをインストールし、bootstrap.phpに読み込ませます。

blog-tutorial$ mkdir app/Config/Plugin/DebugKit
blog-tutorial$ git clone https://github.com/cakephp/debug_kit -b 2.2 app/Config/Plugin/DebugKit
blog-tutorial$ vi app/Config/bootstrap.php
bootstrap.php
//コメントアウトを解除
CakePlugin::load('DebugKit');

AppController.phpにも追加で記述します。

blog-tutorial$ vi app/Controller/AppController.php
AppController.php
class AppController extends Controller {
    public $components = array('DebugKit.Toolbar'); //追加
}

3.7 Dockerfileの作成

Dockerfileを作成します。

3.7.1 Dockerfile-apacheの作成

まずはApacheコンテナ用のDockerfileを作成します。

blog-tutorial$ mkdir docker
blog-tutorial$ vi docker/Dockerfile-apache
Dockerfile-apache
FROM php:5.6-apache

RUN apt-get update -yqq \
  && apt-get install -yqq --no-install-recommends \
  git \
  zip \
  unzip \
  && rm -rf /var/lib/apt/lists

# Enable PHP extensions
RUN docker-php-ext-install pdo_mysql mysqli

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer

# Add cake and composer command to system path
ENV PATH="${PATH}:/var/www/html/lib/Cake/Console"
ENV PATH="${PATH}:/var/www/html/app/Vendor/bin"

# COPY apache site.conf file
COPY ./docker/apache/site.conf /etc/apache2/sites-available/000-default.conf

# Copy the source code into /var/www/html/ inside the image
COPY . .

# Set default working directory
WORKDIR ./app

# Create tmp directory and make it writable by the web server
RUN mkdir -p \
  tmp/cache/models \
  tmp/cache/persistent \
  && chown -R :www-data \
  tmp \
  && chmod -R 770 \
  tmp

# Enable Apache modules and restart
RUN a2enmod rewrite \
  && service apache2 restart

EXPOSE 80

3.7.2 Dockerfile-MySQLの作成

参考サイトではMySQLイメージは既存のものを使用していますが、それで作成したMySQLコンテナでは日本語が使えなかったので、こちらもDockerfileから作成していきます。

参考:DockerのMySQLコンテナを日本語対応させる - Qiita

blog-tutorial$ vi docker/Dockerfile-MySQL
Dockerfile-MySQL
FROM mysql:5.7

RUN apt-get update
RUN apt-get -y install locales-all

ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8

COPY ./docker/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf

3.8 Apache site.confの作成

dockerディレクトリにapahceディレクトリを作成し、site.confを作成します。

blog-tutorial$ mkdir docker/apache
blog-tutorial$ vi docker/apache/site.conf
site.conf
<VirtualHost *:80>
    DocumentRoot /var/www/html/app/webroot/

    <Directory /var/www/html/app/webroot/>
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

3.9 mysqld_charset.cnfの作成

dockerディレクトリにmysqld_charset.cnfを作成します。

blog-tutorial$ vi docker/mysqld_charset.cnf
mysqld_charset.cnf
[mysqld]
character_set_server=utf8
character_set_filesystem=utf8
collation-server=utf8_general_ci
init-connect='SET NAMES utf8'
init_connect='SET collation_connection = utf8_general_ci'
skip-character-set-client-handshake

3.10 docker.compose.ymlの作成

docker.compose.ymlを作成します。
参考サイトではメールサーバーが立っていますが、ブログチュートリアルではいらないので、消します。

blog-tutorial$ vi docker-compose.yml
docker-compose.yml
version: "3"

services:
  app:
    build:
      context: .
      dockerfile: docker/Dockerfile-apache
    volumes:
      - .:/var/www/html
    ports:
      - 8000:80
    environment:
      TZ: "Asia/Tokyo"
    depends_on:
      - db

  db:
    build:
      context: .
      dockerfile: docker/Dockerfile-MySQL
    volumes:
      - db-data:/var/lib/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: blog_tutorial
      MYSQL_ROOT_PASSWORD: root_password
      TZ: "Asia/Tokyo"

volumes:
  db-data:
    external: false

3.11 ビルド&実行

設定が完了したので、Docker Composeのビルドと実行を行います。

blog-tutorial/docker$ docker-compose build

以下のような警告がいくつか出ますが無視でOKです。

Step 11/12 : RUN a2enmod rewrite   && service apache2 restart
 ---> Running in 38bfaf787e92
Enabling module rewrite.
To activate the new configuration, you need to run:
  service apache2 restart
Restarting Apache httpd web server: apache2AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
.
Removing intermediate container 38bfaf787e92
 ---> 342196dde2c3

気になるならビルド前に以下のサイトを参考にDockerfileを修正してください。

[Docker]AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using .... Set the 'ServerName' directive globally to suppress this message - Qiita

ビルドが終わったら実行しましょう。

blog-tutorial/docker$ docker-compose up

localhost:8000にアクセスします。

cakephp ok.PNG

上のほうにエラーが表示されていなく、文を囲む四角形が全部緑色だったらOKです!

4 終わりに

まだなんとなくしか理解できていませんが、それでもDockerは便利だなあと思ったので、今後Dockerを使わずに環境構築をすることはないのかなと思いました。

Twitterのフォローもお願いします!

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

Rust,Wasmの環境をDockerで作る MacOS

この記事の目的

rustとwasmの環境をdockerを使用して作ります。

元々はMacOSのローカルで環境を作ろうとした際に、

cargo install cargo-generate

がエラーになってしまったので、それならdockerでやろうと思い立ち調べてみたところ上手く出来なかったため、後続の方に役に立っていただければと思い記録しました。

dockerのインストール方法については省略いたします。

dockerイメージをプルする

こちらで紹介されているdockerイメージをpullします。

docker pull secondstate/ssvm-nodejs-starter:v2

作業フォルダを作成し、移動します。

mkdir rust_wasm
cd rust_wasm

dockerを起動します。

docker run -e USER=$USER -p 3000:3000 --rm -it -v $(pwd):/app secondstate/ssvm-nodejs-starter:v2

コンテナの中に入りました。
nodeとcargo(rust)が入っていることが確認できます。

npm -v
#npmのバージョンが表示される
cargo -version
#cargoのバージョンが表示される

wasm-packとcargo-generateをインストールする

#wasm-packをインストールする
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
#cargo-generateをインストールする
#cargo install cargo-generateだとエラーになります
cargo install cargo-generate --features vendored-openssl

以上です。

テンプレートを取ってきて動作を確認してみてください。

cargo generate --git https://github.com/rustwasm/wasm-pack-template

所感

自分でdockerファイルを書くことができれば、wasm-packとcargogenerateのインストール部分はコンテナ起動の際に完了してしまうのだと思っています。
もし、ご自身でそういったイメージを作られた方、ないしはイメージを見つけた方がおりましたらコメントで教えていただけると大変嬉しいです。

参考にした記事

Getting started with Rust functions in Node.js
https://www.secondstate.io/articles/getting-started-with-rust-function/

ゼロからRust+WasmをFirebaseでデプロイするまでを簡単に
https://qiita.com/namn1125/items/8ffa0f87fa03f59f3acc

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

Transformation Advisor Localをインストールした時の手順メモ

1. はじめに

TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズする 」という投稿で、利用する Transformation Advisor Localのインストールをこの投稿で記述します。

このツールの使用例については、上記ページも参照ください。

2. Transformation Advisor Localとは

ta-local.png

まず、Transformation Advisorはオンプレミス環境で動作しているJavaのミドルウェア・アプリケーションを分析し、生成されたマイグレーションバンドルを使って、 OpenShift の Libertyコンテナ上にJavaアプリをデプロイすることができるJavaアプリケーションのモダナイズするための移行支援ツールです。 (IBMの製品です。)

そして、Transformation AdvisorはOpenShift上にインストールしますが、
今回インストールするTransformation Advisor Localは、Windows・Linux・MacOSと、ローカルPCでもインストールして、Transformation Advisorを利用することができるツールです。

詳細はこちら:IBM Cloud Transformation Advisor

仕組みとしては、ローカルPCに、DockerとDocker Composeをインストールして、Transformation Advisorのコンテナイメージを起動して、Transformation Advisorを利用します。

ローカルPCにインストールすることができるで気軽に試すことができますが、ローカルPCの性能によっては、Dockerを動かす時点で、もっさりと遅いという事が起こるかもしれません。

3. Transformation Advisor Localのインストール

今回は、Transformation Advisor Localの90日評価版をLinux ( CentOS7 )の環境にインストールする手順を確認しました。

3.1 前提

  • 導入環境:
    • VMWare ESXi 6.7 の仮想マシン( スペックは適当に設定CPU4コア, メモリ8GB, HDD 32GB)
    • OS: CentOS Linux release 7.8.2003 (Core)の Minimam Install
  • インストール手順書: Installing IBM Cloud Transformation Advisor locally

3.2 手順

DockerとDocker Composeのインストール

  • 作業環境: CentOS7.8

Dockerの導入手順 https://docs.docker.com/get-docker 
に沿って下記の手順でDockerをインストールします。

$ sudo yum install  yum-utils

# docker のyum リポジトリ追加
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

# Dockerのインストール
$sudo yum install docker-ce docker-ce-cli containerd.io

#Dockerの起動
$sudo systemctl start docker

# Dockerの動作確認
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:e7c70bb24b462baa86c102610182e3efcb12a04854e8c582838d92970a09f323
Status: Downloaded newer image for hello-world:latest

Docker Composeのインストール

  • 作業環境: CentOS7.8

Docker Composeの導入手順 https://docs.docker.com/compose/install/
に沿って下記の手順でDockerをインストールします。

#docker-composeコマンドのダウンロード&設置
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

#docker-composeコマンドに実行権限追加
$ sudo chmod +x /usr/local/bin/docker-compose
$ ls -l /usr/local/bin/docker-compose
-rwxr-xr-x. 1 root root 12218968 Nov 29 04:34 /usr/local/bin/docker-compose

Transformation Advisor Localのダウンロード

  • 作業環境: ローカルPC

以下のURLよりTransformation Advisor Localの90日評価版をダウンロードします。(IBMアカウントが必要になります。)
https://www.ibm.com/account/reg/signup?formid=urx-38642

image.png

ダウンロードページにて、「Transformation Advisor Localのインストールスクリプト」をダウンロードします。
image.png

Transformation Advisor Local の CentOS7.8へのインストール

  • 作業環境: CentOS7.8

事前にローカルPCから CentOS7.8の環境に、先ほどダウンロードしたTransformation Advisor Localのバイナリ「 transformationAdvisor.zip」をアップロードしてください。

そして、以下の手順でインストールします。

#必要なツールのインストール(unzipとnetstatを導入)
$ yum install -y unzip net-tools

# Transformation Advisor Localの解凍
$ unzip transformationAdvisor.zip 
$ ls
launchTransformationAdvisor.sh  LICENSE  LICENSES  scripts  transformationAdvisor.zip

インストールのために「 ./launchTransformationAdvisor.sh 」を実行します。

$ sudo ./launchTransformationAdvisor.sh
[sudo] password for dai:

Docker Compose not installed. Please install docker-compose and re-run the script.
https://docs.docker.com/compose/install/

しかし、docker-composeがインストールされていないとメッセージが表示されます。これは、sudoのsecure_pathに docker-composeのインストールされているパスが登録されていないために、発生する事象です。

下記の様にvisudoを実行して、secure_pathに「 /usr/local/bin 」を追加してください。

$ sudo visudo

(変更前)88 Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
(変更後)88 Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

再度、「launchTransformationAdvisor.sh」を実行して、インストールプログラムを起動します。 ライセンス情報が表示され、最後に、同意するか同意しないかの選択を 同意する 1 の選択をします。

sudo ./launchTransformationAdvisor.sh
LICENSE INFORMATION

The Programs listed below are licensed under the following License Information terms and conditions in addition to the Program license
terms previously agreed to by Client and IBM. If Client does not have previously agreed to license terms in effect for the Program, the
 International License Agreement for Evaluation of Programs (Z125-5543-05) applies.

Program Name (Program Number):
IBM Cloud Transformation Advisor local 2.3.0 (Evaluation)

The following standard terms apply to Licensee's use of the Program.

' ----- 省略 ----- '

1) I have read and agreed to the license agreements
2) Don't accept the license agreements

その後、下記のようなオペレーションメニューが表示されるので、「1) Install Transformation Advisor」の 1 を入力してEnterを押してインストールを開始します。

Select the operation.......

1) Install Transformation Advisor
2) Uninstall Transformation Advisor (keep database data)
3) Uninstall Transformation Advisor (remove database data)
4) Stop Transformation Advisor
5) Start Transformation Advisor
6) Check for latest Transformation Advisor
7) Working in an Air Gapped Environment
8) Quit

その後、正常にインストールが環境すると、下記の様にTransformation AdvisorのURLが表示されます。

Installing Transformation Advisor..............
Pulling db     ... done
Pulling server ... done
Pulling ui     ... done
Creating network "scripts_default" with the default driver
Creating scripts_db_1 ... done
Creating scripts_server_1 ... done
Creating scripts_ui_1     ... done
Configuring Transformation Advisor...............................................
Status
------------------------------------------------------------------------------------------------------
Transformation Advisor 2.3.0 is available for us at the following URL> http://192.168.26.253:3000

Transformation Advisor への接続

  • 作業環境: ローカルPC

ローカルPCのブラウザにて、前手順のインストール完了時に出力されるURLに接続し、Transformation Advisorの画面が表示されることを確認します。

image.png

4. 最後に

これで Transformation Advisor を利用することができるようになりました。
今回は、 Linux環境の手順を説明しましたが、Windows・MacOSの環境でも Docker・Docker Composeが導入済みの環境ならばインストールすることができます。

Transformation Advisor の具体的な使用例は、「TomcatのJavaアプリ(VM環境)をTransformation Advisorを使ってモダナイズする 」の投稿をぜひ、ご覧ください。

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

【開発環境にDocker】Capistrano導入方法

今回はcapistranoでの自動デプロイの導入方法を備忘録のためまとめていきたいと思います。前回の記事からの続きとなります。

前提

手動でのデプロイができていることが前提の記事となります。また、細かい設定やインストールしているパッケージなどは下記事に手動でのデプロイ方法としてまとめてあるので、そちらからご確認いただけます。
https://qiita.com/shun0211/items/21871c82d385648b4bae

環境

  • Amazon Linux2 (無料枠)
  • RDS (MySQL8.0)
  • capistrano 3.14.1
  • Ruby 2.7.1
  • Rails 6.0.3.4
  • Unicorn 5.7.0
  • Nginx 1.12.2

Gemのインストール

gemfile
group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
end
terminal
$ bundle install
$ bundle exec cap install

これにて、自動デプロイのための設定ファイルが作成されます

live_share
├  Capfile
├─  config
│ ├─  deploy
│ │ ├─production.rb #自動デプロイ時の本番環境での設定
│ │ └─staging.rb
│ └─deploy.rb #自動デプロイ時の共通設定
└─  lib
    └─capistrano
        └─tasks

Capistranoで自動デプロイをすると、サーバー上のディレクトリ構造は以下のようになります。(今回の設定の場合)

/var/www/rails(サーバー環境)
live_share
├─ current # 最新のデプロイしたフォルダやファイルが置かれる
├─ shared # 共通のファイルが置かれる
│   ├─ bundle
│   ├─ config
│   ├─ log
│   ├─ public
│   ├─ temp
│   └─ vendor
└─ release # 過去にデプロイしたフォルダやファイルが置かれる

見て分かるように、階層構造が一段深くなっているので、NginxやUnicornの設定ファイルも修正する必要があります。

各ファイルの編集

まずは、Capfile, config/deploy.rb, config/deploy/production.rbのファイルを編集します。

capfile
require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require 'capistrano3/unicorn'

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
config/deploy.rb
# caipstranoのバージョンを記載します。バージョンはGemfile.lockに書いてあります。
lock "~> 3.14.1"
set :application, "conefan"
# pullしてくるgitのURLを書きます。
set :repo_url, "git@github.com:shun0211/live_share.git"

# デフォルトのブランチはmasterになっているので、mainに変更します。
set :branch, "main"

# デプロイするディレクトリを指定します。
set :deploy_to, "/var/www/rails/live_share"

# capistranoではデプロイ後にバグが起きた場合、デプロイ前の状態に戻れるようにデプロイ前のファイルをrelesaseフォルダに入れます。その際、いくつ前のバージョンまで残しておくのかをここで設定します。
set :keep_releases, 2

# ssh接続をする際に必要な設定を書きます。
set :ssh_options, {
  # capistranoコマンド実行者の秘密鍵
  port: 22,
  keys: %w(~/.ssh/live_share_key_rsa),
  forward_agent: true,
  auth_methods: %w(publickey)
}

# Railsがproduction.keyを参照するためのシンボリックリンクを貼る記述をします。production.keyについては後述
append :linked_files, 'config/credentials/production.key'
# 同じくシンボリックリンクを貼るフォルダを指定します。記載したフォルダがshared下に作られます。
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')
set :rbenv_type, :user
set :rbenv_ruby, '2.7.1'
set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" }
set :unicorn_config_path, -> { "#{current_path}/config/unicorn.conf.rb" }

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end
end
config/deploy/production.rb
server "18.178.91.188", user: "ec2-user", roles: %w{web app db}

また、前述したようにディレクトリ構造の変更により、NginxやUnicornの設定ファイルを変更する必要があるので、編集します。前回の記事ではUnicornの設定ファイルはサーバー上にしか書いていないので、サーバーにログインしてファイルの中身をローカルに持ってきて編集します。(たくさん試行錯誤をしていたので、前回の記事と書き方が異なっています)

Unicorn設定ファイル

config/unicorn.conf.rb(ローカル)
#サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく
app_path = File.expand_path('../../../', __FILE__)
worker_processes 2
working_directory "#{app_path}/current" #currentにします
stderr_path "#{app_path}/shared/log/unicorn.stderr.log" #sharedにします
stdout_path "#{app_path}/shared/log/unicorn.stdout.log" #sharedにします
timeout 30
listen "#{app_path}/shared/tmp/sockets/.unicorn.sock" #sharedにします .unicorn.sockの.(ドット)を忘れずに
pid "#{app_path}/shared/tmp/pids/unicorn.pid" #sharedにします

preload_app true

GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true
check_client_connection false
run_once = true

before_exec do |server|
  ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile" #currentにします
end

before_fork do |server, worker|
  defined?(ActiveRecord::Base) &&
    ActiveRecord::Base.connection.disconnect!

  if run_once
    run_once = false
  end
  # 古いプロセスがあった場合はkillする処理
  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exist?(old_pid) && server.pid != old_pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH => e
      logger.error e
    end
  end
end

after_fork do |_server, _worker|
  defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end

Nginx設定ファイル

/etc/nginx/conf.d/live_share.conf(サーバー環境)
error_log  /var/www/rails/live_share/shared/log/nginx.error.log; #sharedにします
access_log /var/www/rails/live_share/shared/log/nginx.access.log; #sharedにします

upstream unicorn_server {
    server unix:/var/www/rails/live_share/shared/tmp/sockets/.unicorn.sock fail_timeout=0; #sharedにします
}

server {
    listen 80;
    client_max_body_size 4G;
    server_name conefan.com; #サーバー名

    keepalive_timeout 5;

    root /var/www/rails/live_share/current/public; #currentにします

    location ~ ^/assets/ {
        root /var/www/rails/live_share/current/public; #currentにします
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://unicorn_server;
            break;
        }
    }
    error_page 500 502 503 504 /500.html;
}

設定ファイルを再読み込みし再起動します。

/(サーバー環境)
$ sudo service nginx reload
$ sudo service nginx restart

秘密鍵をDockerコンテナ上に配置

筆者は開発環境にDockerを使っていたので、Dockerコンテナ内の~/.sshディレクトリ内にEC2にログインするための秘密鍵を置かなければいけません。

live_share(ローカル)
$ docker container cp ~/.ssh/<秘密鍵名> <コンテナ名>:/root/.ssh

これでコンテナ内に秘密鍵が設置できたので、実際に入ってコンテナ内からEC2へログインできるか確認します。

live_share(ローカル)
$ docker exec -it <コンテナ名> bash

# コンテナ内で以下コマンド
$ ssh -i ~/.ssh/<秘密鍵> ec2-user@18.178.91.188 

今後、ビルドし直す度に秘密鍵をコピーするのがめんどくさいため、volume化して~/.sshディレクトリを共有します。(.ssh内に他の秘密鍵がある場合はディレクトリを一段深くしてそこをvolume化したほうがいいかもしれません。)

docker-compose.yml
  web:
    # 省略
    volumes:
      - ~/.ssh:/root/.ssh
    # 省略

環境変数の設定

また、database.yml内で環境変数を使っているので、サーバー内でも設定しないといけません。前回の記事ではdotenvのGemを使っていたのですが、自動デプロイのときにはうまくいかなかったので、サーバー内の環境変数を設定します。(gotenvは本番環境では非推奨らしいです。)

/etc/environmemt
DB_NAME=データベース名_production #RDSで作成したDB名
DB_USERNAME=root #RDSのユーザー名
DB_PASSWORD=********* #RDSのパスワード
DB_HOSTNAME=***.ap-northeast-1.rds.amazonaws.com # RDSのエンドポイント

環境変数が設定されているか確認

terminal
$ source .env
$ echo $DB_NAME
$ echo $DB_USERNAME
$ echo $DB_PASSWORD
$ echo $DB_HOSTNAME

環境変数の設定はcredentials.yml.encを使ってやる方法もあるみたいです。

production環境用にCredentialsの設定

手動デプロイとは異なり、production環境用のcredentialsの設定が必要になります。

live_share(ローカル)
$ docker-compose run -e EDITOR=vim web rails credentials:edit --environment production

このコマンドを打つことによりconfig/credentialsディレクトリが作られ、その中にproduction.keyとproduction.yml.encが作られます。デフォルトではsecret_key_baseは生成されないので自分で設定を行います。下記コマンドでヘルプが見れます。

live_share
$ bin/rails credentials:edit --help

その後、生成されたproduction.keyをデプロイ先のサーバにコピーします。コピー先はshared/config/credentialsディレクトリに行います。

live_share(ローカル)
$ scp -i ~/.ssh/live_share_key_rsa production.key ec2-user@18.178.91.188:/var/www/rails/live_share/shared/config/credentials

ここまで来たらmainブランチにローカルで編集した設定の変更をマージしてデプロイを走らせます。

live_share
docker-compose run --rm web bundle exec cap production deploy

最後までデプロイが走れば成功です。お疲れさまでした!
何度もエラーが出ると思いますが、一個ずつ解決していけば必ずできるのでとにかく諦めないことが重要だと感じました。
ここからは筆者がハマったエラーについてまとめます。

エラーについて

ssh接続エラー

コンテナ内に鍵を設置してssh接続できており、設定もまちがってないのに下のようなエラーが出る場合は一旦コンテナをビルドし直したほうがいいかもしれません。筆者はビルドし直すことでエラーがでなくなりました。

エラーログ
Net::SSH::AuthenticationFailed: Authentication failed for ~~~

Gem::LoadError

下エラーが出る場合はエラーログにもありますが、ed25519とbcrypt_pbkdfのGemをインストールすることで解決しました。

エラーログ
Gem::LoadError : "ed25519 is not part of the bundle. Add it to your Gemfile."

Node.jsバージョンエラー

node.jsのバージョンが古い場合にエラーとなります。しかし、筆者の場合サーバー上で確認してもnodeのバージョンは10.21.0でした。なぜ6.17.1が使われているのかはなぞでしたが、新しいバージョンを再度インストールすることで解決しました。

エラーログ
The engine "node" is incompatible with this module. Expected version ">=8.16.0". Got "6.17.1"
/(サーバー上)
# npmでnをインストール
$ sudo npm install n -g
# 安定版の最新node.jsをインストール
$ sudo n stable
バージョン確認
$ node -v

参考

https://qiita.com/gyu_outputs/items/c960c903e7bc6f684a44
https://qiita.com/tatama/items/aaa1300f55da5da2933a
https://loumo.jp/archives/24419

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

docker-composeで都合の良いPython3実行環境を作成する

概要

  • Python3の都合の良い実行環境が欲しくなったのでdockerで作成しました。
    • いつも使ってるOSがCentOS7だ(ubuntuではない。。)
    • ENVを切るのがめんどくさい。
    • 検証のたびにサーバを準備したくない。
    • 検証が終わったら消したい。

事前準備

  • 下記をインストールし実行できること。
    • docker
    • docker-compose

ディレクトリ構成

./---docker-compose.yml
  |--Dockerfile
  |--requirements.txt   # pipインストール用 利用しなければ不要
  |--.env               # 環境変数用 利用しなければ不要
  |--src                # pyファイルを配置するディレクトリ
      |-- sample.py

各種ファイルの配置

docker-compose.yml

docker-compose.yml
version: '3'
services:
  python3:
    restart: always
    build: .
    container_name: 'python3'
    working_dir: '/root/src'
    tty: true
    volumes:
      - ./src:/root/src
    env_file:
      - .env

Dockerfile

FROM python:3
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
ADD requirements.txt /root/
RUN pip install -r /root/requirements.txt

requirements.txt

  • pipインストールする必要があれば記載する
requirements.txt
requests

.env

  • 環境変数を設定する必要があれば記載する
SAMPLE_USER ='root'

sample.py

sample.py
print("hello world")

実行

コンテナを起動

$ docker-compose up -d

スクリプトの実行

  • dockerホストになっているサーバからexecでpythonスクリプトを実行できる。
$  docker-compose exec python3 python3 sample.py
hello world

requirements.txtや.envを修正したとき

  • 一度停止して再ビルド
$ docker-compose down
$ docker-compose build
$ docker-compose up -d
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

30代未経験からRails, AWS, Docker, CircleCIでポートフォリオを作成するまで

プログラミング未経験の31歳男がRuby on Rails, jQuery, AWS, Docker, CircleCIといった技術を使ってWebアプリを作りました。

この記事では、最初にアプリの紹介をした後に、

  • どれくらいの時間かけて作ったのか
  • なぜこれらの技術を使うことにしたのか
  • 特に大変だったところ
  • どのように学習したのか

といったことについて、お伝えできればと思います。

どんなアプリを作ったのか

減量アプリです。(筋トレしてる人が健康的に体脂肪を減らすためのアプリ)

「これなら自分でも続けられる」をコンセプトに「PFC MASTER」というアプリを開発しました。

アプリのURLはこちらです。
https://pfcmaster.work/
(レスポンシブ対応しておりスマホからも見られますが、グラフが崩れます)

Githubはこちらです。
https://github.com/naota7118/pfc-master

なんでこのアプリを作ったのか

僕自身が「減量がなかなか続かなくて、まだ腹筋を割れたことがない」という悩みを抱えていました。
自分自身の悩みを解決するようなアプリを作りたいと思い、減量アプリを作ることにしました。

「どうしたら減量を途中で挫折せずに続けられるようになるかな?」

今まで減量に挫折した原因を考えたところ、下記の2つが思い当たりました。

〈これまで減量が続かなかった原因〉

  • 1日どれくらい食べれば体脂肪落とせるのかわからなくて、適当に食べてしまっていた。
  • 減量が進んでいるのかどうか、進捗がわからなくてモチベーションが保てなかった。

このような原因に対してどうしたら減量を続けやすくなるか考えた結果、下記の2つを思いつきました。

  • 「1日何キロカロリーまで食べていいのか」を自分の体重から自動で計算してくれて、食べるごとに確認できたらカロリーコントロールしやすくなるのではないか。
  • 体重やカロリーの推移をグラフで見られるようにすれば、成果が出てるのがわかってモチベーションが保てるのではないか。

このように原因やそれを解決する策を考えて、グラフ機能をメインとした減量アプリを作ることにしました。

アプリの写真と説明

トップページ

使い方を細かく説明しなくても、パッと見て一目で使い方わかる外観を意識して作りました。
スクリーンショット 2020-11-23 午後8.39.00.png

グラフ

体重とカロリーの推移がグラフという形で見られるようにしました。
自分の頑張りが目に見えることで「よし、いい感じだ。もっと頑張ろう」と思えるのではないかと考えたのです。
82912645752047340005a4a76361350b.gif

カレンダーと画像一覧

食べたものや筋トレをカレンダーや写真で記録して確認できるようにしました。
写真でカラダの変化を可視化することでそれもモチベーションにつながると考えました。
また、他の減量に成功した方がどんなものを食べて減量できたのか知って真似できるため、という目的もあります。
9fd6b65dde2703f27bec05eac512d889.gif

カロリーの自動計算

「1日○キロカロリー食べれば体脂肪を落とせる」という減量の目安となる"1日の摂取カロリー目をユーザーが体重と体脂肪率を入力したら自動で計算されるようにしました。

※ちなみに、摂取カロリーの計算式はバズーカ岡田先生の著書『除脂肪メソッド』を参考にしました。
e30c9e2a5ca5a1523686697876e9b603.gif

自動計算機能によって、「今日あと何キロカロリーまで食べて大丈夫か」がわかるようにしました。
これで減量の成功率を高められると考えました。
スクリーンショット 2020-11-29 午後5.55.14.png

使用技術

  • フロントエンド
    HTML(Haml), CSS(Sass), jQuery, boostrap4

  • サーバーサイド
    Ruby 2.5.1, Rails 5.2.4.3

  • インフラ
    CircleCI, Nginx, MySQL, Docker/Docker-compose, AWS(VPC, EC2, RDS, IAM, Route53, S3)

サーバーサイドはRuby on Rails、フロントエンドはSassとjQueryで実装しました。
開発環境にはDocker-composeを使用しました。

CI/CDパイプラインに関しては、CircleCIによりmasterブランチにmergeしたら自動でRSpecのテストとRubocopのリファクタリングが実行されるように設定しました。

ER図

PFCMASTERのER図.png

インフラ構成図

AWSインフラ構成図.png

アプリを作るのにかかった期間

トータル6ヶ月です。
当初の予定では8月にはAWSにデプロイした時点で転職活動を始める予定でしたが、「DockerやCirlcleCIを導入するところまでやり切りたい」と思い、結局6ヶ月かかりました。

半年間どのように進めてきたかは下記の通りです。

期間 やったこと
2020年4月 テーマを決めた。データベース設計。
2020年5〜7月 (スクールのチーム開発と並行する形で)
RailsのCRUD機能、いいね機能(非同期通信)、コメント機能(非同期通信)、フォロー機能。
Chart.jsを使ったグラフ機能、jQueryを使った自動計算機能。
2020年8月 Unicorn, Nginxを使ってAWSにデプロイ。
Capistranoを使って自動デプロイ。
2020年9月 Haml, Sassで各ページのマークアップ。
Boostrapを使ってレスポンシブ対応させる。
Dockerを使って開発環境を構築。
2020年10月 CircleCIでRSpecの自動テスト、Rubocopの自動リファクタリングを通す。
Gitのエラー解決で誤ってGitリポジトリのファイルを消してしまい、その修復のためAWSへのデプロイをやり直す。
2020年11月 TwitterAPIを使って投稿するとTwitterに自動投稿されるように設定(ローカル環境のみ)
転職活動開始。現在PHPで2つ目のアプリを開発中。

なぜ6ヶ月もかかってしまったのか

誰にも相談せず1人でエラーを解決することにこだわり過ぎて、エラー解決に時間をかけ過ぎたことがいちばんの原因です。

エンジニアになるためには、「エラーに直面した時に"すぐ質問せず自分で問題解決する力"が求められる」との考えから、できるだけ自分でエラーを解決することにこだわっていました。

今振り返ると、リミットを設けてある程度自分で考えたら、リミットがきた時点で質問すべきだったと思います。
実際の仕事では1人のエラー解決をずっと待ってもらえないからです。

現在、「2020年中に完成させる」というリミットを決めて2つめのアプリを開発しています。

なぜRails, jQuery, Docker, CircleCIを使うことにしたのか?

RailsとjQueryを選んだ理由

最速で開発する方法として、これらの技術を選びました。なるべく早くアプリを完成させ、転職活動を開始し、1日も早くエンジニアとして働きたいと思ったためです。
(結果的に半年もかかったので説得力ありませんが...)

なぜRubyとjQueryを使えば最速で開発できると思ったかというと、スクールで簡単なCRUD機能を持ったアプリを開発した経験があり、他の言語に比べて理解していた部分が大きく開発する「こうやって作っていくんだ」というイメージがしやすかったためです。

AWS, Docker, CircleCIを使うことにした理由

これらの技術を使用した理由は、wantedlyで求人情報を見たところ、多くの企業でこれらの技術を使用していたためです。
「多くの企業で使われている技術はどんな技術なのだろう」と興味を持ったのと、実務で使うことを見越して「早いうちから自分で使って慣れておきたい」と考えたためです。

特に大変だったところ

特に挙げるとすると、下記の6点です。
詰まったエラーの解決法をQiita記事にアウトプットしていました。

どのように学習したのか

技術 学習方法
HTML/CSS/Ruby/Rails/jQuery スクールのカリキュラム
Boostrap4 Boostrap日本語リファレンス
AWS AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
(デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
Docker 米国AI開発者がゼロから教えるDocker講座
CircleCI 米国AI開発者がゼロから教えるDocker講座
Chart.js Chart.js日本語ドキュメント

今後の課題

  • 2日連続投稿した時に「すごい!!」と表示されるようにする。
  • プロフィール画像を登録できるようにする。(現状は女性ユーザーも外国人男性がプロフィール画像になってしまう。)
  • 運動した日と運動しなかった日をカレンダーでわかるようにする。

企業の方へ

ここまでお読みいただきありがとうございました。
現在、webエンジニアになるため転職活動を行っております。
少しでも興味を持って頂けましたら、Twitterの@naota7118までDM頂ければ幸いです。
何卒よろしくお願いいたします。

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

30代未経験からRails, AWS, Docker, CircleCIを使って減量アプリを作りました

プログラミング未経験の31歳男がRuby on Rails, jQuery, AWS, Docker, CircleCIといった技術を使ってWebアプリを作りました。

この記事では、最初にアプリの紹介をした後に、

  • どれくらいの時間かけて作ったのか
  • なぜこれらの技術を使うことにしたのか
  • 特に大変だったところ
  • どのように学習したのか

といったことについて、お伝えできればと思います。

どんなアプリを作ったのか

減量アプリです。(筋トレしてる人が健康的に体脂肪を減らすためのアプリ)

「これなら自分でも続けられる」をコンセプトに「PFC MASTER」というアプリを開発しました。

アプリのURLはこちらです。
https://pfcmaster.work/
(レスポンシブ対応しておりスマホからも見られますが、グラフが崩れます)

Githubはこちらです。
https://github.com/naota7118/pfc-master

なんでこのアプリを作ったのか

僕自身が「減量がなかなか続かなくて、まだ腹筋を割れたことがない」という悩みを抱えていました。
自分自身の悩みを解決するようなアプリを作りたいと思い、減量アプリを作ることにしました。

「どうしたら減量を途中で挫折せずに続けられるようになるかな?」

今まで減量に挫折した原因を考えたところ、下記の2つが思い当たりました。

〈これまで減量が続かなかった原因〉

  • 1日どれくらい食べれば体脂肪落とせるのかわからなくて、適当に食べてしまっていた。
  • 減量が進んでいるのかどうか、進捗がわからなくてモチベーションが保てなかった。

このような原因に対してどうしたら減量を続けやすくなるか考えた結果、下記の2つを思いつきました。

  • 「1日何キロカロリーまで食べていいのか」を自分の体重から自動で計算してくれて、食べるごとに確認できたらカロリーコントロールしやすくなるのではないか。
  • 体重やカロリーの推移をグラフで見られるようにすれば、成果が出てるのがわかってモチベーションが保てるのではないか。

このように原因やそれを解決する策を考えて、グラフ機能をメインとした減量アプリを作ることにしました。

アプリの写真と説明

トップページ

使い方を細かく説明しなくても、パッと見て一目で使い方わかる外観を意識して作りました。
スクリーンショット 2020-11-23 午後8.39.00.png

グラフ

体重とカロリーの推移がグラフという形で見られるようにしました。
自分の頑張りが目に見えることで「よし、いい感じだ。もっと頑張ろう」と思えるのではないかと考えたのです。
82912645752047340005a4a76361350b.gif

カレンダーと画像一覧

食べたものや筋トレをカレンダーや写真で記録して確認できるようにしました。
写真でカラダの変化を可視化することでそれもモチベーションにつながると考えました。
また、他の減量に成功した方がどんなものを食べて減量できたのか知って真似できるため、という目的もあります。
9fd6b65dde2703f27bec05eac512d889.gif

カロリーの自動計算

「1日○キロカロリー食べれば体脂肪を落とせる」という減量の目安となる"1日の摂取カロリー目をユーザーが体重と体脂肪率を入力したら自動で計算されるようにしました。

※ちなみに、摂取カロリーの計算式はバズーカ岡田先生の著書『除脂肪メソッド』を参考にしました。
e30c9e2a5ca5a1523686697876e9b603.gif

自動計算機能によって、「今日あと何キロカロリーまで食べて大丈夫か」がわかるようにしました。
これで減量の成功率を高められると考えました。
スクリーンショット 2020-11-29 午後5.55.14.png

使用技術

  • フロントエンド
    HTML(Haml), CSS(Sass), jQuery, boostrap4

  • サーバーサイド
    Ruby 2.5.1, Rails 5.2.4.3

  • インフラ
    CircleCI, Nginx, MySQL, Docker/Docker-compose, AWS(VPC, EC2, RDS, IAM, Route53, S3)

サーバーサイドはRuby on Rails、フロントエンドはSassとjQueryで実装しました。
開発環境にはDocker-composeを使用しました。

CI/CDパイプラインに関しては、CircleCIによりmasterブランチにmergeしたら自動でRSpecのテストとRubocopのリファクタリングが実行されるように設定しました。

ER図

PFCMASTERのER図.png

インフラ構成図

AWSインフラ構成図.png

アプリを作るのにかかった期間

トータル6ヶ月です。
当初の予定では8月にはAWSにデプロイした時点で転職活動を始める予定でしたが、「DockerやCirlcleCIを導入するところまでやり切りたい」と思い、結局6ヶ月かかりました。

半年間どのように進めてきたかは下記の通りです。

期間 やったこと
2020年4月 テーマを決めた。データベース設計。
2020年5〜7月 (スクールのチーム開発と並行する形で)
RailsのCRUD機能、いいね機能(非同期通信)、コメント機能(非同期通信)、フォロー機能。
Chart.jsを使ったグラフ機能、jQueryを使った自動計算機能。
2020年8月 Unicorn, Nginxを使ってAWSにデプロイ。
Capistranoを使って自動デプロイ。
2020年9月 Haml, Sassで各ページのマークアップ。
Boostrapを使ってレスポンシブ対応させる。
Dockerを使って開発環境を構築。
2020年10月 CircleCIでRSpecの自動テスト、Rubocopの自動リファクタリングを通す。
Gitのエラー解決で誤ってGitリポジトリのファイルを消してしまい、その修復のためAWSへのデプロイをやり直す。
2020年11月 TwitterAPIを使って投稿するとTwitterに自動投稿されるように設定(ローカル環境のみ)
転職活動開始。現在PHPで2つ目のアプリを開発中。

なぜ6ヶ月もかかってしまったのか

誰にも相談せず1人でエラーを解決することにこだわり過ぎて、エラー解決に時間をかけ過ぎたことがいちばんの原因です。

エンジニアになるためには、「エラーに直面した時に"すぐ質問せず自分で問題解決する力"が求められる」との考えから、できるだけ自分でエラーを解決することにこだわっていました。

今振り返ると、リミットを設けてある程度自分で考えたら、リミットがきた時点で質問すべきだったと思います。
実際の仕事では1人のエラー解決をずっと待ってもらえないからです。

現在、「2020年中に完成させる」というリミットを決めて2つめのアプリを開発しています。

なぜRails, jQuery, Docker, CircleCIを使うことにしたのか?

RailsとjQueryを選んだ理由

最速で開発する方法として、これらの技術を選びました。なるべく早くアプリを完成させ、転職活動を開始し、1日も早くエンジニアとして働きたいと思ったためです。
(結果的に半年もかかったので説得力ありませんが...)

なぜRubyとjQueryを使えば最速で開発できると思ったかというと、スクールで簡単なCRUD機能を持ったアプリを開発した経験があり、他の言語に比べて理解していた部分が大きく開発する「こうやって作っていくんだ」というイメージがしやすかったためです。

AWS, Docker, CircleCIを使うことにした理由

これらの技術を使用した理由は、wantedlyで求人情報を見たところ、多くの企業でこれらの技術を使用していたためです。
「多くの企業で使われている技術はどんな技術なのだろう」と興味を持ったのと、実務で使うことを見越して「早いうちから自分で使って慣れておきたい」と考えたためです。

特に大変だったところ

特に挙げるとすると、下記の6点です。
詰まったエラーの解決法をQiita記事にアウトプットしていました。

どのように学習したのか

技術 学習方法
HTML/CSS/Ruby/Rails/jQuery スクールのカリキュラム
Boostrap4 Boostrap日本語リファレンス
AWS AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得
(デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
Docker 米国AI開発者がゼロから教えるDocker講座
CircleCI 米国AI開発者がゼロから教えるDocker講座
Chart.js Chart.js日本語ドキュメント

今後の課題

  • 2日連続投稿した時に「すごい!!」と表示されるようにする。
  • プロフィール画像を登録できるようにする。(現状は女性ユーザーも外国人男性がプロフィール画像になってしまう。)
  • 運動した日と運動しなかった日をカレンダーでわかるようにする。

ここまでお読みいただきありがとうございました。
現在、webエンジニアになるため転職活動を行っております。
もし企業の採用担当者の方で、この記事を読んで少しでも興味を持って頂くなんてことがもしありましたら、Twitterの@naota7118までDM頂ければ幸いです。
何卒よろしくお願いいたします。

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

【Node.js】 Dockerを用いてNode.js Express MySQLの環境を構築する

前回の記事で作ったdockerファイルを整理した内容です。

【Node.js】 Dockerを用いてNode.js Express MySQLの環境を構築するまでの道のり
https://qiita.com/sho_U/items/0ef3dfc7b07b5e13fa18

最初に用意するパッケージ

f5a0aa2aee3893379d8275aaa56a6f59.png

app.env

app.env
MYSQL_SERVER=mysql
MYSQL_USER=(ユーザー名)
MYSQL_PASSWORD=(パスワード)
MYSQL_DATABASE=(データーベース名)

docker-compose.yml:

node.jsコンテナとmysqlコンテナを管理するyml

docker-compose.yml
version: '3'
services:
  mysql:
    image: mysql:5.7
    container_name: (アプリ名)_db
    env_file: ./mysql/mysql.env
    environment:
      - TZ=Asia/Tokyo
    ports:
      - '3306:3306'
    volumes:
      - ./mysql/conf:/etc/mysql/conf.d/:ro
      - mysqldata:/var/lib/mysql
    networks:
      - backend

  app:
    build: .
    container_name: (アプリ名)_app
    env_file: ./app.env
    environment:
      - TZ=Asia/Tokyo
      - DEBUG=app:*
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - ./src:/app
    working_dir: /app
    command: npm starttre
    networks:
      - backend
    depends_on:
      - mysql

#使用するネットワークを作成。docker-composeの場合service以下の名前を使って名前解決されるため、appとmysqlが自動的に接続される。
networks:
  backend:

volumes:
  mysqldata:

Dockerfile:

アプリケーション用(node.js)コンテナを作るためのfile

dockerfile.
FROM node:12
WORKDIR /app

なぜかnpm installをRUNできないので,必要なパッケージはpackage.jsonに記載して、コンテナからnpm install を実施。

my.conf:

(コンテナ側の/etc/mysql/conf.d/に配置される。)

mysql/conf/my.conf
[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqldump]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
lower_case_table_names=1

# Enable access from the host machine.
bind-address=0.0.0.0

mysql.env

mysql/mysql.env
MYSQL_ROOT_HOST=%
MYSQL_ROOT_PASSWORD=(ルートパスワード)
MYSQL_USER=(ユーザー名)
MYSQL_PASSWORD=(パスワード)
MYSQL_DATABASE=(データーベース名)

src:

アプリケーション本体(空ディレクトリ)

package.json:

初期は空

package.json(空)
{}

アプリケーション用のコンテナを作成する

コンテナをビルドする。

ホスト.
docker-compose build
ホスト.
#コンテナを一時的に起動(--rmで停止後削除する。コンテナ起動後、bashに入る)
docker-compose run --rm app /bin/bash
コンテナ.
# express-generatorでアプリケーションのひな形を生成
npx express-generator --view=ejs

package.jsonに必要なパッケージを記載(必要に応じて追加)

package.json
{
  "name": "アプリ名",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "nodemon ./bin/www"
   //nodemon用起動scripts
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "ejs": "^3.1.5",
    "express": "~4.16.1",
    "express-generator": "^4.16.1",
    "express-session": "^1.17.1",
    "express-validator": "^6.7.0",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "nodemon": "^2.0.6",
    "sequelize": "^6.3.5",
    "sequelize-cli": "^6.2.0"
  }
}
コンテナ.
#インストール
npm install
コンテナ.
#コンテナを抜ける(この仮コンテナは削除される)
exit

※この時、コンテナは削除されるが

docker-compose.yml
    volumes:
      - ./src:/app

この記述により、.(docker-compose.ymlがあるディレクトリ。つまりnodoDockerディレクトリの配下のsrcディレクトリにマウントされているため、ホスト側のsrcディレクトリに作成した雛形は残っている。

コンテナを起動させる

host.
docker-compose up
docker-compose.yml
    command: npm start

の記載により、コンテナ起動後、自動的にExpress.jsのアプリケーションがnodemonで起動する。
http://localhost:3000/
で確認。

mysqlコンテナに入れるか確認

docker exec -it コンテナID bash
mysql -uroot -p

完成ディレクトリ
7c1c1a36ea3977d775c69f590d4ad3ab (1).png

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

CircleCI で DLC を(一部) 使わなくなった話

Increments × cyma (Ateam Inc.) Advent Calendar 2020 の7日目は、
Increments株式会社 プロダクト開発グループ Qiita開発チームの @atm-snag が担当します!

閑話

この記事を書いているときに,前日の記事がアップされていて,
それが CI 関連だったので, CI が連続するなあと思った(小並感

はじめに

Increments では,build や deploy などに circleci を使っています.
circleci には DLC(Docker Layer Cache) という機能があります.
今回は,DLC を使わなくなった話をします.

DLC とは…

  • circleci の executer を跨いで /var/lib/docker を共有する仕組みです.
    • docker のイメージレイヤをジョブをまたいで使うことができる
  • ジョブ実行 1 回ごとに 200 [クレジット] かかる(200 credits per job run)

です.

circleci に詳しくない人に軽く説明すると,

  • executor とは
    • ジョブの実行環境.
    • 通常 executer は別マシンで起動して不連続なので ,/var/lib/docker は共有されていない状態
      • docker build するときに過去のイメージレイヤのキャッシュがない → build が長い → 金銭的な死

DLC を使えば,どこかのジョブで docker build が終わっていれば,
次以降に起動する executor では,キャッシュを使って,docker build の実行をスキップ(USING CACHE) できるという訳です.
これは便利.

→ ジョブなどの概念はこちらが詳しそう

問題点

使っているうちにいくつか気付いたことがあります.

  • Dockerfile 等のビルドの実行に関係ある部分に変更が無い場合でもキャッシュを使わずに build が実行されていることがあった
    • おそらく,volume が複数あるために,docker イメージレイヤがキャッシュとして有効に使われていない状態だった
      • ドキュメントに,1つのvolume にアタッチできるのが1つの executor なため,volume は複数個になる(最大50個) ことがあると書いてある
      • volumen が消えるのが1週間後であり,どういう条件でどのvolume が使われるのかはランダム(?)
      • circleci の課金1が,ジョブの実行時間とリンクしているので,できれば無駄な docker build は避けたい
  • 結局安くなっているのか?
    • docker のイメージレイヤがキャッシュされていても,build が必要なステップがあれば,そのステップはは実行される
    • 速度的には,「キャッシュなし < DLC < 過去の image を pull してcache できるところはする」のような想定(下図)
      • 「image pull」 と 「DLC」 の差はdocker イメージレイヤをpull する時間がメイン
        • docker build が成功する確率が高い前提
    • 1回 200クレジットかかる.
      • 例えば,machine executor medium で 10 [クレジット/分]1

スクリーンショット 2020-11-30 15.55.29.png

200[クレジット] / 10[クレジット/分] → build 時間を20分以上高速化できないとコスト的には微妙ではないか?
もっと言うと,docker pull する時間が 20分を越えなければ DLC より docker pull の方が(コスト的には)良いのではないか?2
(時間的にはdocker pull する分だけ悪くなるために一長一短ではある.あと volume が複数あることでbuild する可能性があること.もある)

やったこと

  • docker pull を build よりも前に実行するようにした

DLC も良いところもある

  • 例えば,色んなジョブで DLC を使うことで,キャッシュヒット率を上げる
    • docker pull を使うと,失敗した build の image layer の情報は残らないため,そのようなものを積極的に使おうとするならば有効かもしれない
    • とはいえ,これはエッジケース寄りな感じがする.circleci のジョブでdocker build をなるべく失敗させないように運用でカバーすることもできる.
  • 提案っぽいもの
    • DLC ではなくジョブで使えるキャッシュ機能も存在してそちらはどのキャッシュをなるべく使う指定ができるので,どういうvolume を優先して使うかを指定できるとある程度使い易くなるのではないか?
    • なんかこう,branchとか開発project みたいな感じで,そっちのvolume を優先的に使いたい.みたいなケース.
  • 今回試した方法は docker pull に依存しているので,docker pull に何らかの制限をかけられるとローカルのキャッシュの方がありがたい
    • 例えば,pull に回数制限かけられたりした場合

その他

  • 試してみたプロジェクトでは,docker save → store cache → restore cache → docker load がめちゃ時間かかったので,docker pull を採用しました
    • 近いところでやるから速くなると思ったんだけど,やっぱり計測してみないとわからないもんですね.

まとめ

  • DLC を使わなくなりました(一部)
    • 今回のプロジェクトではマッチしなかったので使わなくなったけど,有意に使える場面もあるかもしれない.
    • とはいえ,中身を知らないといつ使えるんだということになるので,今回のように調べることができたのは良かった.

Increments × cyma (Ateam Inc.) Advent Calendar 2020 の8日目は、エイチームのEC事業本部の @hibiheion がお送りします!!

LINK


  1. circieci pricing 

  2. 転送量課金とかできたら,docker pullの方が不利になることも起きるだろうか? 

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

docker-composeを使った開発環境構築実践! Rails + Nuxt.js + MySQLを動かす

はじめに

docker-composeを使ったローカル開発環境構築について解説します!

ここでは、フロントエンドにNuxt.js, バックエンドにRails, DBにMySQLを使った構成にします。

YouTube動画

動画で確認したい方はこちらもどうぞ!
【YouTube動画】 docker-compose による開発環境構築入門
docker-compose による開発環境構築入門

GitHub

GitHubにコードを載せているので、実際に動かしてみたい方はこちらもどうぞ!
https://github.com/yassun-youtube/docker-compose-sample

git clone git@github.com:yassun-youtube/docker-compose-sample.git


実際のコード
docker-compose.yml
version: "3.8"
services:
  rails:
    build: ./rails-sample
    ports:
      - 3000:3000
    volumes:
      - ./rails-sample:/app
      - /app/node_modules
    stdin_open: true
    tty: true
    command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
    depends_on:
      - mysql
  nuxt:
    build: ./nuxt-sample
    ports:
      - 8000:8000
    volumes:
      - ./nuxt-sample:/app
      - /app/node_modules
    command: sh -c "yarn && yarn dev"
  mysql:
    image: mysql:8.0.22
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_ROOT_HOST: '%'
      MYSQL_DATABASE: test-database
volumes:
  db-data:
# ./nuxt-sample/Dockerfile
FROM node:14.15.1-alpine3.12

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

CMD ["yarn", "dev"]
# ./rails-sample/Dockerfile
FROM ruby:2.7.1-alpine

RUN set -x && apk add --no-cache \
                      # for mysql
                      mysql-dev \
                      # for nokogiri
                      build-base \
                      # for tzinfo-data
                      tzdata \
                      yarn
WORKDIR /app

COPY Gemfile Gemfile.lock package.json yarn.lock ./

RUN bundle install
RUN yarn install

CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]
database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  username: root
  password:
  database: rails-sample-dev
  host: mysql

test:
  <<: *default
  username: root
  password:
  database: rails-sample-test
  host: mysql
nuxt.config.js
...
  proxy: {
    '/api': 'http://rails:3000'
  },
...


docker-composeとは

docker-composeとは複数コンテナやネットワーク、ボリュームを一括管理できるツールです。
Dockerをインストールすれば、ついてくるので、別途インストールする必要はありません。

よく使うコマンド

docker-composeでよく使うコマンドを紹介します。

docker-compose up

docker-compose.ymlに記載されたコンテナを起動するために使います。
-d オプションを付けると、デタッチモードで起動します。

docker-compose down

起動したコンテナを停止して削除するときに使います。
削除しない場合は、CTRL + Cを押すか docker-compose stopで止めることができます。

コンテナをデタッチモードで動かしているときは、docker-compose psと併用して使います。

docker-compose build

docker-compose.ymlに記載されたサービス (nuxtとかrails, mysql) をビルドするときに使います。
ymlファイル内のimage:またはbuildに書かれているパスにあるDockerfileのイメージを参照して、ビルドを開始します。

docker-compose run <サービス名> <コマンド>

docker-compose.ymlに記載されたサービスを指定してコマンドを実行するときに使います。

docker-compose exec <サービス名> <コマンド>

既に起動しているコンテナを指定して、コマンドを実行するときに使います。

docker-compose.ymlの概要

docker-compose.ymlで指定できる、version services networks volumesについて紹介します。

version

docker-composeの書き方のバージョンを指定するときに使います。
この記事を書いている段階 (2020/11/29) では、3.8です。

services

コンテナを定義するために使います。
ここで、railsとかnuxt, mysqlのDockerfileを指定したり、イメージを直接指定して使います。

networks

各サービスがどのネットワークと接続するかを定義できます。

volumes

ホストOSとゲストOSでデータを同期するときに使います。
今回はMySQLのデータを同期するために使います。

実際の設定ファイル

実際の設定ファイルは以下のようになります。

docker-compose.yml
version: "3.8"
services:
  rails:
    build: ./rails-sample
    ports:
      - 3000:3000
    volumes:
      - ./rails-sample:/app
      - /app/node_modules
    stdin_open: true
    tty: true
    command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
    depends_on:
      - mysql
  nuxt:
    build: ./nuxt-sample
    ports:
      - 8000:8000
    volumes:
      - ./nuxt-sample:/app
      - /app/node_modules
    command: sh -c "yarn && yarn dev"
  mysql:
    image: mysql:8.0.22
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_ROOT_HOST: '%'
      MYSQL_DATABASE: test-database
volumes:
  db-data:

大枠の設定

上記設定ファイルの大枠をみていきます。
設定ファイルはバージョン3.8を利用し、サービスにはrails, nuxt, mysqlを指定しています。
DBのデータを同期するために、volumes: db-data:を指定しています。

docker-compose.yml
version: "3.8"
services:
  rails: ...
  nuxt: ...
  mysql: ...
volumes:
  db-data:

services: mysqlの設定

imageでMySQL 8.0.22のDockerイメージを取得し、volumesでデータを同期しています。
environmentで環境変数を設定でき、ここではrailsからROOTユーザーとして、アクセスできるようにしています。
また、作成するDB名はtest-databaseとしました。

docker-compose.yml
mysql:
  image: mysql:8.0.22
  volumes:
    - db-data:/var/lib/mysql
  environment:
    MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    MYSQL_ROOT_HOST: '%'
    MYSQL_DATABASE: test-database

services: nuxtの設定

nuxtは別途Dockerfileを作成し、そこからイメージを取るようにしました。
Dockerfileの場所をbuildで指定しています。

portsでは、ホストOSの8000ポートとゲストOSの8000ポートを繋げる設定をしています。

volumesの1行目./nuxt-sample:/appは、ホストOSのnuxt-sampleをゲストOSのappと同期するための設定です。
2行目の/app/node_modulesはホストOSのnode_moduleとゲストOSのnode_moduleを同期しないための設定です。
node_modulesはOS依存のパッケージが入る可能性があるので、このように除外しています。

commandでは、コンテナ起動時にシェルで実行するコマンドを設定しています。
node_modulesを作るために、yarnを実行し、yarn devでnuxtを起動しています。

docker-compose.yml
nuxt:
  build: ./nuxt-sample
  ports:
    - 8000:8000
  volumes:
    - ./nuxt-sample:/app
    - /app/node_modules
  command: sh -c "yarn && yarn dev"

次にDockerfileをみていきます。
FROMで使用するDockerイメージを指定します。
開発環境なので、軽量なalpineにしています。

WORKDIRで以後、コマンドを実行するディレクトリを指定します。

COPY, RUN, CMDでパッケージをゲストOSにコピーし、yarn, yarn devを実行しています。
docker-compose.yml側で同じ設定をしているので、なくても大丈夫です。

# ./nuxt-sample/Dockerfile
FROM node:14.15.1-alpine3.12

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

CMD ["yarn", "dev"]

services: railsの設定

build, ports, volumesは先ほどと同じような意味です。

dockerでbinding.pryなどのデバッグができるように、stdin_open: truetty: trueを指定しています。

depends_onでは、mysqlを指定し、mysqlのコンテナが起動するまではrailsのコンテナが起動しないようにしています。

docker-compose.yml
rails:
  build: ./rails-sample
  ports:
    - 3000:3000
  volumes:
    - ./rails-sample:/app
    - /app/node_modules
  stdin_open: true
  tty: true
  command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
  depends_on:
    - mysql

Dockerfileの方もnuxtと同じように依存パッケージをインストールして、railsサーバーを起動しています。

# ./rails-sample/Dockerfile
FROM ruby:2.7.1-alpine

RUN set -x && apk add --no-cache \
                      # for mysql
                      mysql-dev \
                      # for nokogiri
                      build-base \
                      # for tzinfo-data
                      tzdata \
                      yarn
WORKDIR /app

COPY Gemfile Gemfile.lock package.json yarn.lock ./

RUN bundle install
RUN yarn install

CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]

database.ymlの設定

RailsサーバーとMySQLを接続するために、docker-compose.ymlのサービスで指定している名前をdatabase.ymlで設定する必要があります。

services: mysqlと設定していたので、database.ymlのhostにもmysqlと設定しておきます。

database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  username: root
  password:
  database: rails-sample-dev
  host: mysql

test:
  <<: *default
  username: root
  password:
  database: rails-sample-test
  host: mysql

nuxt.config.jsの設定

NuxtからRailsにプロキシしたい場合は、nuxt.config.jsのproxyにサービス名を記述するだけでプロキシできます。

nuxt.config.js
...
  proxy: {
    '/api': 'http://rails:3000'
  },
...

おわりに

実際にコードを見ながら、動かしながら学んだ方が理解が深まると思うので、ぜひGitHubのリポジトリもご確認ください!
https://github.com/yassun-youtube/docker-compose-sample

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

docker-composeを使った開発環境構築実践! Rails + Nuxt + MySQL

はじめに

docker-composeを使ったローカル開発環境構築について解説します!

ここでは、フロントエンドにNuxt.js, バックエンドにRails, DBにMySQLを使った構成にします。

YouTube動画

動画で確認したい方はこちらもどうぞ!
【YouTube動画】 docker-compose による開発環境構築入門
docker-compose による開発環境構築入門

GitHub

GitHubにコードを載せているので、実際に動かしてみたい方はこちらもどうぞ!
https://github.com/yassun-youtube/docker-compose-sample

git clone git@github.com:yassun-youtube/docker-compose-sample.git


実際のコード
docker-compose.yml
version: "3.8"
services:
  rails:
    build: ./rails-sample
    ports:
      - 3000:3000
    volumes:
      - ./rails-sample:/app
      - /app/node_modules
    stdin_open: true
    tty: true
    command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
    depends_on:
      - mysql
  nuxt:
    build: ./nuxt-sample
    ports:
      - 8000:8000
    volumes:
      - ./nuxt-sample:/app
      - /app/node_modules
    command: sh -c "yarn && yarn dev"
  mysql:
    image: mysql:8.0.22
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_ROOT_HOST: '%'
      MYSQL_DATABASE: test-database
volumes:
  db-data:
# ./nuxt-sample/Dockerfile
FROM node:14.15.1-alpine3.12

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

CMD ["yarn", "dev"]
# ./rails-sample/Dockerfile
FROM ruby:2.7.1-alpine

RUN set -x && apk add --no-cache \
                      # for mysql
                      mysql-dev \
                      # for nokogiri
                      build-base \
                      # for tzinfo-data
                      tzdata \
                      yarn
WORKDIR /app

COPY Gemfile Gemfile.lock package.json yarn.lock ./

RUN bundle install
RUN yarn install

CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]
database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  username: root
  password:
  database: rails-sample-dev
  host: mysql

test:
  <<: *default
  username: root
  password:
  database: rails-sample-test
  host: mysql
nuxt.config.js
...
  proxy: {
    '/api': 'http://rails:3000'
  },
...


docker-composeとは

docker-composeとは複数コンテナやネットワーク、ボリュームを一括管理できるツールです。
Dockerをインストールすれば、ついてくるので、別途インストールする必要はありません。

よく使うコマンド

docker-composeでよく使うコマンドを紹介します。

docker-compose up

docker-compose.ymlに記載されたコンテナを起動するために使います。
-d オプションを付けると、デタッチモードで起動します。

docker-compose down

起動したコンテナを停止して削除するときに使います。
削除しない場合は、CTRL + Cを押すか docker-compose stopで止めることができます。

コンテナをデタッチモードで動かしているときは、docker-compose psと併用して使います。

docker-compose build

docker-compose.ymlに記載されたサービス (nuxtとかrails, mysql) をビルドするときに使います。
ymlファイル内のimage:またはbuildに書かれているパスにあるDockerfileのイメージを参照して、ビルドを開始します。

docker-compose run <サービス名> <コマンド>

docker-compose.ymlに記載されたサービスを指定してコマンドを実行するときに使います。

docker-compose exec <サービス名> <コマンド>

既に起動しているコンテナを指定して、コマンドを実行するときに使います。

docker-compose.ymlの概要

docker-compose.ymlで指定できる、version services networks volumesについて紹介します。

version

docker-composeの書き方のバージョンを指定するときに使います。
この記事を書いている段階 (2020/11/29) では、3.8です。

services

コンテナを定義するために使います。
ここで、railsとかnuxt, mysqlのDockerfileを指定したり、イメージを直接指定して使います。

networks

各サービスがどのネットワークと接続するかを定義できます。

volumes

ホストOSとゲストOSでデータを同期するときに使います。
今回はMySQLのデータを同期するために使います。

実際の設定ファイル

実際の設定ファイルは以下のようになります。

docker-compose.yml
version: "3.8"
services:
  rails:
    build: ./rails-sample
    ports:
      - 3000:3000
    volumes:
      - ./rails-sample:/app
      - /app/node_modules
    stdin_open: true
    tty: true
    command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
    depends_on:
      - mysql
  nuxt:
    build: ./nuxt-sample
    ports:
      - 8000:8000
    volumes:
      - ./nuxt-sample:/app
      - /app/node_modules
    command: sh -c "yarn && yarn dev"
  mysql:
    image: mysql:8.0.22
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_ROOT_HOST: '%'
      MYSQL_DATABASE: test-database
volumes:
  db-data:

大枠の設定

上記設定ファイルの大枠をみていきます。
設定ファイルはバージョン3.8を利用し、サービスにはrails, nuxt, mysqlを指定しています。
DBのデータを同期するために、volumes: db-data:を指定しています。

docker-compose.yml
version: "3.8"
services:
  rails: ...
  nuxt: ...
  mysql: ...
volumes:
  db-data:

services: mysqlの設定

imageでMySQL 8.0.22のDockerイメージを取得し、volumesでデータを同期しています。
environmentで環境変数を設定でき、ここではrailsからROOTユーザーとして、アクセスできるようにしています。
また、作成するDB名はtest-databaseとしました。

docker-compose.yml
mysql:
  image: mysql:8.0.22
  volumes:
    - db-data:/var/lib/mysql
  environment:
    MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    MYSQL_ROOT_HOST: '%'
    MYSQL_DATABASE: test-database

services: nuxtの設定

nuxtは別途Dockerfileを作成し、そこからイメージを取るようにしました。
Dockerfileの場所をbuildで指定しています。

portsでは、ホストOSの8000ポートとゲストOSの8000ポートを繋げる設定をしています。

volumesの1行目./nuxt-sample:/appは、ホストOSのnuxt-sampleをゲストOSのappと同期するための設定です。
2行目の/app/node_modulesはホストOSのnode_moduleとゲストOSのnode_moduleを同期しないための設定です。
node_modulesはOS依存のパッケージが入る可能性があるので、このように除外しています。

commandでは、コンテナ起動時にシェルで実行するコマンドを設定しています。
node_modulesを作るために、yarnを実行し、yarn devでnuxtを起動しています。

docker-compose.yml
nuxt:
  build: ./nuxt-sample
  ports:
    - 8000:8000
  volumes:
    - ./nuxt-sample:/app
    - /app/node_modules
  command: sh -c "yarn && yarn dev"

次にDockerfileをみていきます。
FROMで使用するDockerイメージを指定します。
開発環境なので、軽量なalpineにしています。

WORKDIRで以後、コマンドを実行するディレクトリを指定します。

COPY, RUN, CMDでパッケージをゲストOSにコピーし、yarn, yarn devを実行しています。
docker-compose.yml側で同じ設定をしているので、なくても大丈夫です。

# ./nuxt-sample/Dockerfile
FROM node:14.15.1-alpine3.12

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

CMD ["yarn", "dev"]

services: railsの設定

build, ports, volumesは先ほどと同じような意味です。

dockerでbinding.pryなどのデバッグができるように、stdin_open: truetty: trueを指定しています。

depends_onでは、mysqlを指定し、mysqlのコンテナが起動するまではrailsのコンテナが起動しないようにしています。

docker-compose.yml
rails:
  build: ./rails-sample
  ports:
    - 3000:3000
  volumes:
    - ./rails-sample:/app
    - /app/node_modules
  stdin_open: true
  tty: true
  command: sh -c "yarn && bundle exec rails server -b 0.0.0.0 -p 3000"
  depends_on:
    - mysql

Dockerfileの方もnuxtと同じように依存パッケージをインストールして、railsサーバーを起動しています。

# ./rails-sample/Dockerfile
FROM ruby:2.7.1-alpine

RUN set -x && apk add --no-cache \
                      # for mysql
                      mysql-dev \
                      # for nokogiri
                      build-base \
                      # for tzinfo-data
                      tzdata \
                      yarn
WORKDIR /app

COPY Gemfile Gemfile.lock package.json yarn.lock ./

RUN bundle install
RUN yarn install

CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]

database.ymlの設定

RailsサーバーとMySQLを接続するために、docker-compose.ymlのサービスで指定している名前をdatabase.ymlで設定する必要があります。

services: mysqlと設定していたので、database.ymlのhostにもmysqlと設定しておきます。

database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  username: root
  password:
  database: rails-sample-dev
  host: mysql

test:
  <<: *default
  username: root
  password:
  database: rails-sample-test
  host: mysql

nuxt.config.jsの設定

NuxtからRailsにプロキシしたい場合は、nuxt.config.jsのproxyにサービス名を記述するだけでプロキシできます。

nuxt.config.js
...
  proxy: {
    '/api': 'http://rails:3000'
  },
...

おわりに

実際にコードを見ながら、動かしながら学んだ方が理解が深まると思うので、ぜひGitHubのリポジトリもご確認ください!
https://github.com/yassun-youtube/docker-compose-sample

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

Cloud Native Ecosystemの成熟度から見る2021年の動向

記事を書いたきっかけとお詫び

  • Kubernetesとそのエコシステムが実に幅広く、知れば知るほど何もわからなくなってしまいました
  • Kubernetes自体は使用してみて1年弱ですが、今後何をどこまで深堀りしていくか取捨選択が必要になってきたため、成熟度の観点とトレンドを基に2021年に何をしようか考えてみることにした
  • 特にCNCF自体も宣言している通りプロジェクトの統廃合も進む年になるので、少し俯瞰して考えてみる
  • 余談として、コミュニティとの関わりなど個人的な期待を備忘的に残すことにした

※普段アウトプットが少ないにもかかわらず初めてAdvent Calendarを書くため、大きなテーマを取り上げてしまったことを反省しています。こんなこと考えている人もいるんだな、くらいの温度感で読んでいただけるとよきです。同じような境遇の方などの参考に少しでもなれば幸いです。

Kubernetesとクラウドネイティブの現状

  • KubeConでもKubernetes自体のアップデートより、CNCF Landscapeを中心とした周辺技術の活性化の方が注目されてきた
  • 方で、エンタープライズにおいてはKubernetesやDockerは「VMからコンテナ化して軽量化」という文脈で語られることが未だ少なくない印象で、クラウドネイティブ化という大きなパラダイムシフトの観点が欠けているケースが散見される。今まさに各社では文化や意識の改革を迫られ、キャズムが発生している状態である。
  • クラウドネイティブエコシステムについて、何をどの程度深堀すべきかは未だ流動的な状態である。

Kubernetesとキャズム越え

技術採用のライフサイクル(Technology Adaption Lifecycle)の図でいうと、Kubernetesはキャズムを越えるか、超えないかというステータスであるという意見が昨年ごろから散見された。

越えたか越えてないかはさほど重要でなく、現状のトレンドを見る限り多くの人がKubernetesを活用していくことに対して否定的な意見は多くない状況かと思う。

https://miro.medium.com/max/700/1*JzEpa6aK92q5KTyJGYDn_g.png

参考: https://medium.com/@shivayogiks/what-is-technology-adoption-life-cycle-and-chasm-e07084e7991f

上記とは別にCNCFもMaturity Levels(成熟度合い)を定義しており、CNCF ProjectとしてIncubatingからGraduatedになったものはキャズムを越えていると定義している。

Untitled.png

参考: https://www.cncf.io/projects/

KubernetesとEcosystemに関するキャズム

CNCF Landscapeの変遷

KubernetesのEcosystemは、Cloud NativeなプロダクトであるCNCF Lanscapeとしてある程度表現されていると捉えられる。

Cloud Nativeなプロジェクトを記載したCNCF Landscapeは最早豆粒のようなものしか見えない程度にまで成長し、全てのカテゴリで新しい製品が作り出され続けている。

この中でも特に、成熟度が高いGraduatedなプロジェクトの変遷をみてみる。

https://landscape.cncf.io/images/landscape.png

CNCF Graduated Projects

  • 2020/12/4現在、13のProjectがGraduatedとなっている。

Screen Shot 2020-11-29 at 14.29.27.png

参考: https://www.cncf.io/projects/

Graduated Project認定時期

この3年弱でGraduatedとなったプロジェクトを時系列でまとめてみた。

OPA, CRI-Oに関しては、近々Graduateするとのことだったため時期未定で追加した。

参考: https://github.com/cncf/toc/projects

Untitled 2.png

2020年以前にGraduatedとなった9 Projects

2020年にGraduatedとなった5 Projects

  • 2020年にGraduatedとなった5 Projects

    Helm - Packaging Manager

    2020/4/30

    Untitled 3.png

    Harbor - Cloud native registry

    2020/6/23

    Untitled 4.png

    TiKV - Cloud native key-value database

    2020/9/30

    Untitled 5.png

    Rook - Cloud native storage tool

    2020/10/7

    Untitled 6.png

    etcd - distributed, reliable key-value store

    2020/11/24

    Untitled 7.png

標準化やコンパティビリティ

Kubernetesのエコシステムは様々な標準化によって支えられていて、CRI, CNI, CSI, SMI, OpenTelemetryなどがある。

標準化されたインタフェースを把握することで枝葉の部分の各プロダクトを厳密に理解しなくてはよいため、興味の対象を絞ることができる。もちろん運用をする場合はさらに詳しく見ていく必要はあることは間違いない。

一方でここであげているインタフェースに関してもあくまで一部でしかないが、これらを体系的にまとめた資料などは見つけられていない。

Untitled 8.png

また、運用のトイルを減らすべく、Kubernetes Operatorも活用例が増えてきている。

Operator作成に用いるツールに関してもoperator-sdk, kubebuilderがあったが、2020/7に実質の統合が行われoperator-sdk側が事実上のスタンダードとなった。詳細は下記にまとめている。

【Kubernetes Operator】operator-sdkとkubebuilder統合に関する注意点 - Qiita

また、operator-sdkが含まれるOperator Frameworkは同じ2020/7にCNCF Incubating Projectになっている。Operatorを作るほど体力がないケースがほとんどと思われるため、Operatorをどこまで突き詰められるかは環境に依存するところが大きそう。

下記の記事でも少しだけ触れている。

Kubernetes Internal #2に参加してみた - Qiita

Kubernetes界隈の今後の予測

※ここまでで述べた事実に基づき、ここからは個人的な推測混じりの感想と展望を記載します。

個人的な期待や予測

Kubernetesやエコシステムの今後

KubeCon NA 2020にて述べられた通り、Sandbox Projectとして承認される敷居が下がるため、Sandbox Projectの統廃合が進むことが示された。これはつまりGraduated, Incubatingの指す意味が今までより一層MatureなProjectであることを裏付けてくれる。

その意味では、今後はよりIncubatingとGraduatedに焦点を当ててキャッチアップしていく戦略が求められそう。下記のCNCFのページにもその2カテゴリがリストされている。

https://www.cncf.io/projects/

KubeCon NA Virtual 2020における、Graduated, Incubatingの講演

文字なしで画像だけですべてのGraduated, Incubatingを紹介してくれる貴重な資料なのでこちらも参考になる

講演概要: https://kccncna20.sched.com/event/ek9f/a-flight-over-the-cloud-native-landscape-carson-anderson-weave

講演資料: https://static.sched.com/hosted_files/kccncna20/a9/Carson-Anderson_CNCF-Flyover.pdf

コミュニティ活動の今後

Meetupもコロナによってあり方が大きく変わった。仕事終わりに会場まで足を運び、現地で軽食をつまみながら現地の空気感を味わえる体験は、リモートのそれと比較すると両方に良さがあるように思う。詳細は別記事で別途まとめることとするが、リモート化したMeetupの体験をよりよくする動きは今後も継続して模索されていくと期待できる。

初学者向けのMeetupもできてはいるが、偉大な先人が数年前に作成した資料がすでにゴロゴロ存在していたりするため、内容はより事例や詳細、エコシステム群などに特化していくことが予想される。

過去の良い資料などが再利用性を高めて保持されたり、登壇自体が目的とならないように、コミュニティ活動のスタイルが変わったりというような変遷が来年にかけて起こっていくといいな、という期待がある。

ここに関するコミュニティ活動改善のアイデアは別途まとめて、フィードバックをもらえる場所で公開したい。

企業におけるクラウドネイティブ

旧来型のアジリティではアップデートに追従するだけで、相当な体力が必要なことは各企業で叫ばれている。

今後ますます塩漬けは厳しくなっていくと予想していたが、先日のKubeCon NA 2020にてCNCF Projectのリリースライフサイクルを低下させる提案が発表された。これは、各企業でアップデートに追従できていないことを示唆している。

Cloud NativeなProjectがより採用されやすくなることで、Late Majorityをうまく引き込むための歩み寄りと捉えることができる。一方で、旧来の塩漬け運用に逆行するわけでないことは改めて認識しなければいけない。

2021年の注目技術

KubeCon NA 2020にて、2021年に注目する技術として紹介された5つの技術が下記である。

今後どのように発展していくか注目していく必要がありそう。

  • Chaos Engineering
  • Kubernetes Edge
  • Service Mesh
  • WASM and eBPF
  • Developer & Operator Experience

このうち、Chaos Engineering FrameworkのLitmusについては下記の記事にてまとめた。

https://qiita.com/iaoiui/items/00369f232a23d2e30b2c

まとめ

Kubernetesは2年前のKubeConの時点でboring(退屈)と言われていたように、KubeConはエコシステム側への考慮がより深まって行っている状況である。

現状はKubernetesとクラウドネイティブの潮流はキャズムを迎え、より幅広い層に利用されていく過程にある。

その一方でエコシステム自体は拡大を続けているため、現状のアーリーアダプターや市場がどのような方向にシフトしていくかを注視していくことがますます重要になる。

特に、CNCFが2021年に注目する技術である、下記の5点は今後の方向性を見定めていく必要がある。

  • Chaos Engineering
  • Kubernetes Edge
  • Service Mesh
  • WASM and eBPF
  • Developer & Operator Experience

また、1つの指標としてCNCF Graduated, Incubating Projectを基に、成熟したプロジェクトの変遷を改めて振り返り今後の傾向予測の参考とした。

今後何を学んでいくべきか迷った時に振り返ろうと思う。

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

Dockerを使って最速で社内DNSを構築してみた

この記事は 生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020 の1日目の記事です。

2日目の記事:未定

社内だけで使えるサービスやシステムを複数運営していると、IPアドレスでのアクセスは大変になってきます。

そこで、社内サービスにもドメインを使ってアクセスできるように社内DNSを整備しました。

前提

  • ドメインは取得済み
  • ドメインのワイルドカード証明書取得済み
    → これに関しては取得していなくても大丈夫ですが、SSL化された通信を行いたい場合は取得しておきましょう
  • 取得ドメイン:choipre.com

構築後のネットワーク図は以下のような感じになります
スクリーンショット 2020-11-29 13.46.45.png

構築

DNSはDockerを使って構築します。CoreDnsというDocker-imageが公開されているので、そちらを利用します。フォルダ構成としては以下の感じです。

drwxr-xr-x   - nomunomu  2 11 18:01 dns
.rw-r--r-- 244 nomunomu  4 11 16:00 ├── docker-compose.yml
.rw-r--r-- 115 nomunomu  4 11 16:00 ├── Dockerfile
drwxr-xr-x   - nomunomu  2 11 17:58 └── volumes
drwxr-xr-x   - nomunomu  4 11 16:14    └── config
.rw-r--r-- 181 nomunomu  4 11 16:32       ├── Corefile
.rw-r--r--  53 nomunomu  4 11 16:14       └── hosts

Docker系設定

docker-compose.yml
version: '3.1'
services:
  coredns:
    build: .
    container_name: coredns
    restart: on-failure
    expose:
      - '53'
      - '53/udp'
    ports:
      - '53:53'
      - '53:53/udp'
    volumes:
      - './volumes/config:/etc/coredns'
Dockerfile
FROM coredns/coredns:1.7.0

EXPOSE 53
EXPOSE 53/udp

ENTRYPOINT ["/coredns"]
CMD ["-conf", "/etc/coredns/Corefile"]

CoreDns設定

どのドメインとIPアドレスが紐づくかをhostsファイルに記述します。Corednsの設定はファイルはCorefileというファイルに記述します。

Corefile
. {
    whoami
    forward . 192.168.0.100:53   # ここはPublic-DNSでもよい
    errors
    log . "{proto} {remote} is Request: {name} {type} {>id}"
    hosts /etc/coredns/hosts {
        fallthrough
    }
    reload
}
hosts
192.168.0.110 xxxxxx.choipre.com
192.168.0.111 yyyyyy.choipre.com
192.168.0.112 zzzzzz.choipre.com

起動

docker-compose.ymlがあるディレクトリで以下のコマンドを流すと、DNSが起動します。

docker-compose up

docker-composeを走らせたPC(192.168.0.100)へ各クライアントのDNS解決先を向けることでローカルのIPに対してもドメインでアクセスすることができるようになります。

社内のネットワークを整備して、快適なネットワークLifeを!!

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

docker-composeを使って最速で社内DNSを構築してみた

この記事は 生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020 の1日目の記事です。

2日目の記事:未定

社内だけで使えるサービスやシステムを複数運営していると、IPアドレスでのアクセスは大変になってきます。

そこで、社内サービスにもドメインを使ってアクセスできるように社内DNSを整備しました。

前提

  • ドメインは取得済み
  • ドメインのワイルドカード証明書取得済み
    → これに関しては取得していなくても大丈夫ですが、SSL化された通信を行いたい場合は取得しておきましょう
  • 取得ドメイン:choipre.com

構築後のネットワーク図は以下のような感じになります
スクリーンショット 2020-11-29 13.46.45.png

構築

DNSはDockerを使って構築します。CoreDnsというDocker-imageが公開されているので、そちらを利用します。フォルダ構成としては以下の感じです。

drwxr-xr-x   - nomunomu  2 11 18:01 dns
.rw-r--r-- 244 nomunomu  4 11 16:00 ├── docker-compose.yml
.rw-r--r-- 115 nomunomu  4 11 16:00 ├── Dockerfile
drwxr-xr-x   - nomunomu  2 11 17:58 └── volumes
drwxr-xr-x   - nomunomu  4 11 16:14    └── config
.rw-r--r-- 181 nomunomu  4 11 16:32       ├── Corefile
.rw-r--r--  53 nomunomu  4 11 16:14       └── hosts

Docker系設定

docker-compose.yml
version: '3.1'
services:
  coredns:
    build: .
    container_name: coredns
    restart: on-failure
    expose:
      - '53'
      - '53/udp'
    ports:
      - '53:53'
      - '53:53/udp'
    volumes:
      - './volumes/config:/etc/coredns'
Dockerfile
FROM coredns/coredns:1.7.0

EXPOSE 53
EXPOSE 53/udp

ENTRYPOINT ["/coredns"]
CMD ["-conf", "/etc/coredns/Corefile"]

CoreDns設定

どのドメインとIPアドレスが紐づくかをhostsファイルに記述します。Corednsの設定はファイルはCorefileというファイルに記述します。

Corefile
. {
    whoami
    forward . 192.168.0.100:53   # ここはPublic-DNSでもよい
    errors
    log . "{proto} {remote} is Request: {name} {type} {>id}"
    hosts /etc/coredns/hosts {
        fallthrough
    }
    reload
}
hosts
192.168.0.110 xxxxxx.choipre.com
192.168.0.111 yyyyyy.choipre.com
192.168.0.112 zzzzzz.choipre.com

起動

docker-compose.ymlがあるディレクトリで以下のコマンドを流すと、DNSが起動します。

docker-compose up

docker-composeを走らせたPC(192.168.0.100)へ各クライアントのDNS解決先を向けることでローカルのIPに対してもドメインでアクセスすることができるようになります。

社内のネットワークを整備して、快適なネットワークLifeを!!

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

Dockerのバージョン確認方法

端末(PowerShell)から

docker version

こんな感じ。
image.png

GUIから

クジラさんを右クリック。
image.png
ここ!
image.png
ここ!
image.png

バージョン

Windows10 Pro バージョン1909 OSビルド19042.630
Docker Desktop:2.5.0.1(49550) Engine:19.03.13
PSVersion 5.1.19041.610

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

Flutterをとりあえず試してみたい人向け

この記事について

  • 最近Flutterを聞くけど、あんまり環境を汚したくないという人向けにFlutterのweb環境構築を用意しました
  • dockerを使います
  • vscodeを(必ず)使います
  • dockerでflutter for webなので、windowsでもmacでもokです
  • ひとまず試したい人向けに書いているので、パッケージの永続化とかはしていませんし、本格的にやるならばローカルにきちんと構築するべきだと思います
  • リポジトリ

やること

  • リポジトリをクローン
  • docker-compose build
  • docker-compose up -d workspace
  • vscodeのremote-container機能でworkspaceコンテナを開きます
  • flutter create .
  • flutter run
  • chromeを開きながらコーディング!

詳しく

上の説明でわかればもう読まなくて十分です。
まず、dockerを使う必要があるので、dockerのインストールと基本的なことは終わらせておいてください。
その後、コンテナのイメージをbuildでビルドし、コンテナをup -dで作成します。

ここからが重要なのですが、flutter runするときは必ずvscodeのremote-containerでコンテナに入った状態でflutter runしてください。そうしないと、localhostでうまく接続できません

最後に、開発を終了したい時はCtrl+Cでserverを停止してdocker-compose downでコンテナ停止&削除して終了です。

終わり

最近流行りのFlutterをとりあえず試してみたい人は使ってみてください

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

Cloudflare + Dockerで自動更新可能ワイルドカード証明書を発行して社内サービスをSSL化してみた

この記事は 生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020 の3日目の記事です。

2日目の記事:腰痛のためのリマインダー機能 by @ryu3
4日目の記事:エンジニアのための目を休ませる最高の環境 @newt0

Chromeでhttpサイトが見れなくなる??

Chromeの開発元であるGoogleは以下のような声明を出しました。
(引用元: https://security.googleblog.com/2019/10/no-more-mixed-messages-about-https_3.html

Today we’re announcing that Chrome will gradually start ensuring that https:// pages can only load secure https:// subresources. In a series of steps outlined below, we’ll start blocking mixed content (insecure http:// subresources on https:// pages) by default. This change will improve user privacy and security on the web, and present a clearer browser security UX to users.

本日、Chrome では、https:// ページが安全な https:// サブリソースのみを読み込むことができるようにすることを段階的に開始することを発表しました。以下に概説する一連の手順で、混合コンテンツ ( https:// ページの安全でない http:// サブリソース) をデフォルトでブロックするようになります。この変更により、ウェブ上でのユーザーのプライバシーとセキュリティが改善され、より明確なブラウザセキュリティUXをユーザーに提示することができます。

混合コンテンツ

混合コンテンツとは、https内に存在するhttpなコンテンツのことを指します。
つまり「https://xxxxxxxxx.com/」というセキュアなサイト内で「http://yyyyyyyyyyy.com/image/test.png」のようなセキュアでないコンテンツを呼び出している状態を意味します。

つまり、httpなサイトはChromeで閲覧できなくなる可能性があるということです。
さらにこの問題が顕著なのは、日本におけるChromeの利用率が高いという点です。
(参照元: https://lab.syncer.jp/Statistic/Browser/2019/10/

・ デスクトップのシェア:66.14%(1位)
・ モバイルのシェア:26.46%(2位)
・ タブレットのシェア:36.56%(2位)

社内だけのサービス(退勤管理やソース管理など)だからといって、セキュア化していないとアクセスできない。なんてことにならないように社内のネットワーク整備をすることにしました。

では、社会人1年目、新卒入社の筆者が社内ネットワーク整備に奮闘した一部始終をどうぞ!!

環境

  • CentOS 7
    → 社内サービスがDocker on CentOS7で動いてた
  • Let's Encrypt
    → 無料で使えるSSL証明書。90日で期限が切れるため更新が必須
  • Cloudflare
    → ワイルドカード証明書を発行するのにDNSレコードを変更する必要があるため、無料で使えるCloudflareを採用。(このためだけにNSを変更したといっても過言ではない)
  • lego(https://go-acme.github.io/lego/
    → Let's Encryptの環境がさくっと作れるDocker環境。大体のDNS Providerに対応してて、それぞれの設定方法や実行方法が書いてあってありがたい。 (対応してるDNS Provider一覧はこちら

改修フロー

https化へのざっくりとしたフローはこちらです。

  1. 社内サービスへのアクセスをサブドメインで行えるようにする
  2. ドメインのネームサーバー(NS)をCloudflareに変更
  3. Cloudflareでソーン編集用APIアクセスキーを作成
  4. 社内サービスコンテナ内で自動更新スクリプト等の作成
  5. Nginxなどに証明書を食わせる

今回は検証用の個人的なドメイン(choipre.com)(Google Domains)を使って解説します。
ドメイン取ったけど、個人サービスが完成していないので、何しても大丈夫だし。

!! 注意 !!
設定を間違えるとサイトにアクセスできなくなったりする可能性があります。必ず変更点(Diff)などはメモするようにしておいた方が、万が一のためです。バックアップなどを取りつつ作業を進めることをおすすめします。

1. 社内サービスへのアクセスをサブドメインで行えるようにする

これまで、社内サービスにはIPアドレスを使ってアクセスしていました。そのためhttps化できず、httpな状態で運用していました。まずは、社内サービスへのアクセスをサブドメインでアクセスできるようにするため、社内DNSを整備します。ドメインは、会社HPなどで元々利用しているものを利用しました。その内容は別記事として割愛します。

参照: Dockerを使って最速で社内DNSを構築してみた

2. ドメインのNSをCloudflareに変更

なぜCloudflareに変更したかというと、CloudflareではAPIを使ってドメインのゾーン情報(A, AAAA, TXTなどのDNSレコード情報)を書き換えることができます。
(参考: https://api.cloudflare.com/#zone-subscription-zone-subscription-details

この仕組みを利用して、スクリプト上でワイルドカードのSSL証明書を発行するのに必要なレコード内容を自動で書き込みたかったからです。
(証明書更新する度に手動でDNSレコードに追記したり、削除したりするのって面倒だし、ネットワークの知識がない人が更新しないといけないってなったときに、このコマンド一発叩けばいいよ!の方がいいよね?)

Cloudflareにドメインを登録

Cloudflareのアカウントを持っていない人はアカウント作成してください。

アカウント作成後、トップ画面に 【サイトを追加する】 を押します。
(※ 画像は既に登録済みのドメインがあるため、Cloudflareの管理下にあるドメイン一覧がありますが、初期登録後の人は何も表示されていません。)
スクリーンショット 2020-11-23 17.56.06.png

Cloudflareで管理したいドメインを入力します。
スクリーンショット 2020-11-23 17.58.27.png

プラン選択画面が表示されるので 【Freeプラン】 を選択します。
(Freeプランでここまで出来るってCloudflare様様...)
スクリーンショット 2020-11-23 18.00.12.png

Cloudflareに既存DNSレコードを移植

ドメインの登録が完了すると、現在設定されているDNSレコードを読み取って、Cloudflareに書き込み準備をしてくれます。このときにDNSレコードを修正することもできますが、必要がない人はそのまま 【続行】 します。
ただし、AレコードとMXレコードが同一の場合、AレコードをCloudflareのプロキシから外す必要があります。プロキシから外してDNS解決のみにしないとメールサーバーが正常に動作しないためです。
(参考: Cloudflareの使用時にメールが配信不能になる - メール関連のDNSレコード
スクリーンショット 2020-11-23 18.00.25.png
スクリーンショット 2020-11-23 18.05.43.png

CloudflareのNSに変更する

Cloudflareに取り込むDNSレコードの設定が終わったら、ドメインのNSをCloudflareに変更するように促されます。
スクリーンショット 2020-11-23 18.06.54.png

各ドメインの管理画面からドメインのNSを変更します。今回の検証用ドメインはGoogle Domainsで取得しているため、Google Domainsの設定画面から変更します。
スクリーンショット 2020-11-23 18.09.02.png

ドメインのNS変更が終わったら、Cloudflareで引き続き設定を行います。ここでは、ドメインへのアクセス、コンテンツのキャッシュ・圧縮設定ができます。利用に応じた設定を行ってください。
スクリーンショット 2020-11-23 18.15.56.png

検証用ドメインでは、以下のように設定しました。
スクリーンショット 2020-11-23 18.17.03.png

Cloudflare-NSの変更チェック

次にNSレコードのチェックをします。既にNSの変更が検知できている場合は、以下のような表示になります。
スクリーンショット 2020-11-23 18.20.43.png

まだ、検知できていない場合は以下のような表示になります。ドメインの設定がネットワーク全体に浸透するまでは24~48時間程かかります。Cloudflareでチェックしても変更されていなかった場合は、少し時間をおいてください。ちなみに、Cloudflareで正常にNSが変更されていることを検知すると、アカウント登録時に設定したメールアドレスに通知がきます。
スクリーンショット 2020-11-23 18.20.25.png

3. ソーン編集用APIアクセスキーを作成

legoのライブラリを利用するために必要な、CloudflareのDNSゾーン情報APIアクセスキーを作成します。キーは2種類作成します。
ゾーン情報の【DNS編集キー】と【ゾーン編集キー】です。Cloudflareのアカウント設定のAPIトークンから作成することができます。
スクリーンショット 2020-11-24 0.28.27.png

まず、APIアクセスキーを作成する前に、画面下部にある「Global Api key」も取得しておきましょう。4.のdocker-compose.ymlに記述する必要があるためです。
スクリーンショット 2020-11-28 15.37.07.png

アクセスキーを作成する際に、いくつかテンプレートが用意されています。今回は【ゾーンDNSを編集する】というテンプレートを編集して利用します。テンプレートを利用せずに0から作成することもできますが、慣れてから使うか、似たテンプレートを変更したほうが無難そうです。
スクリーンショット 2020-11-24 0.30.16.png

1つのトークンに対して、複数の権限を付与することができますが、トークンが増えてくると管理がしづらくなるので、1トークン1権限で運用することとします。アクセス許可に以下を、それぞれ設定して2つのトークンを作成します。

  • 1つ目のトークン
    → ゾーン:DNS:編集
  • 2つ目のトークン
    → ゾーン:ゾーン:編集
  • 2つの共通設定(ゾーンリソース)
    → 包含:特定のゾーン:ワイルドカード証明書を発行したいドメイン

スクリーンショット 2020-11-24 0.33.24.png

トークン作成を進めると、以下のような画面が表示されます。このときに表示されるトークンをメモしてください。ここで表示されたトークンは、画面にもあるように再表示されません。そのため、必ずメモするようにしてください。メモし忘れたら、APIトークンを削除して、再作成してください。
スクリーンショット 2020-11-24 0.56.49.png

4. SSL証明書の自動更新スクリプトの作成

会社の社内サービスが動いているDockerでは、以下のような運用がされています。

  • 平日(月〜金)は昼夜問わず常時起動
  • 休日(土日)に自動シャットダウン
  • 月曜にサービスを立ち上げる

このことから、サービスを立ち上げるときにSSL証明書の更新処理を走るようにしておけば、最低週に1回は確認することになり、更新忘れによる証明書失効を防ぐことが出来ると考えました。サービス自体がDockerで運用されているため、SSL更新処理もDocker化して、Serviceとして登録する方向にしました。

lego(https://go-acme.github.io/lego/)を使ったSSL証明書更新用Dockerは以下のように設定しました。

docker-compose.yml
services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      run
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

docker-compose.yml を作成して、docker-composeを実行します。

$ docker-compose up

実行が終わると、以下のようなログが流れ、/opt/cert 配下に証明書本体が格納されているディレクトリと、更新に必要なアカウント情報が含まれているディレクトリが生成されます。

❯ docker-compose up
Recreating certbot-cloudflare_certbot-lego_1 ... done
Attaching to certbot-cloudflare_certbot-lego_1
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] acme: Registering account for [Cloudflareに登録したメールアドレス]
certbot-lego_1  | !!!! HEADS UP !!!!
certbot-lego_1  |
certbot-lego_1  | Your account credentials have been saved in your Let's Encrypt
certbot-lego_1  | configuration directory at "/lego/accounts".
certbot-lego_1  |
certbot-lego_1  | You should make a secure backup of this folder now. This
certbot-lego_1  | configuration directory will also contain certificates and
certbot-lego_1  | private keys obtained from Let's Encrypt so making regular
certbot-lego_1  | backups of this folder is ideal.
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] [*.choipre.com, choipre.com] acme: Obtaining bundled SAN certificate
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315819
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315820
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] acme: use dns-01 solver
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: tls-alpn-01
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: http-01

(省略)

certbot-lego_1  | 2020/11/28 06:44:11 [INFO] [*.choipre.com, choipre.com] acme: Validations succeeded; requesting certificates
certbot-lego_1  | 2020/11/28 06:44:12 [INFO] [*.choipre.com] Server responded with a certificate.
certbot-cloudflare_certbot-lego_1 exited with code 0
drwxr-xr-x     - nomunomu 28 11 15:43   └── opt
drwxr-xr-x     - nomunomu 28 11 15:44      └── cert
drwx------     - nomunomu 28 11 15:43         ├── accounts
drwx------     - nomunomu 28 11 15:43         │  └── acme-v02.api.letsencrypt.org
drwx------     - nomunomu 28 11 15:44         │     └── xxxxxxxxxxx@gmail.com
.rw-------   225 nomunomu 28 11 15:44         │        ├── account.json
drwx------     - nomunomu 28 11 15:43         │        └── keys
.rw-r--r--   227 nomunomu 28 11 15:43         │           └── xxxxxxxxxx@gmail.com.key
drwx------     - nomunomu 28 11 15:44         └── certificates
.rw-------  3.3k nomunomu 28 11 15:44            ├── _.choipre.com.crt
.rw-------  1.6k nomunomu 28 11 15:44            ├── _.choipre.com.issuer.crt
.rw-------   234 nomunomu 28 11 15:44            ├── _.choipre.com.json
.rw-------   227 nomunomu 28 11 15:44            └── _.choipre.com.key

この生成されたフォルダで、accountsフォルダは今後証明書を更新していくなかで必要になるフォルダです。証明書類はcertificatesに保管されています。
「_.choipre.com.crt」がchoipre.comのワイルドカード証明書になります。

一度、証明書発行を実行したので、今後は更新という処理を行う設定にしておく必要があります。そのため、docker-compose.ymlを以下のように変更します。

services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      renew
      --days 30
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

変更点は、run から renew コマンドに変更することです。パラメーターとして --days を指定することで指定した日数を切ってから更新させることができます。

この、docker-composeの実行をcronなどに設定することで自動更新を行えるようになります。

5. ワイルドカードをnginxに適用する

4.で生成した証明書をNginxに適用していきます。証明書類は/opt/cert配下にあるものとします。Nginxの設定ファイルに以下の記述を追加します。
追記場所はNginxの設定ファイルの使用したいServer設定の中です。デフォルト構成を利用している人は server{ ... } の中に記述します。

ssl_certificate      /opt/cert/_.choipre.com.crt;
ssl_certificate_key  /opt/cert/_.choipre.com.key;

記述ができたら、Nginxのプロセスを再起動します。Nginxのプロセスを再起動したら、対象のアドレスに対してhttpsアクセスをすると証明書が適用されていることが分かります。

まとめ

以上で、自動更新可能なワイルドカード証明書発行の実装が終わりました。
初期設定は大変ですが、今後はあらゆるサブドメインに対してSSL通信を行うことができます。これでChromeでhttpコンテンツが閲覧できなくなっても、安心ですね。

生産性を向上してHappy Lifeを!!

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

Cloudflare + Dockerを使った自動更新可能ワイルドカード証明書で社内サービスをSSL化してみた

この記事は 生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020 の3日目の記事です。

2日目の記事:腰痛のためのリマインダー機能 by @ryu3
4日目の記事:エンジニアのための目を休ませる最高の環境 @newt0

Chromeでhttpサイトが見れなくなる??

Chromeの開発元であるGoogleは以下のような声明を出しました。
(引用元: https://security.googleblog.com/2019/10/no-more-mixed-messages-about-https_3.html

Today we’re announcing that Chrome will gradually start ensuring that https:// pages can only load secure https:// subresources. In a series of steps outlined below, we’ll start blocking mixed content (insecure http:// subresources on https:// pages) by default. This change will improve user privacy and security on the web, and present a clearer browser security UX to users.

本日、Chrome では、https:// ページが安全な https:// サブリソースのみを読み込むことができるようにすることを段階的に開始することを発表しました。以下に概説する一連の手順で、混合コンテンツ ( https:// ページの安全でない http:// サブリソース) をデフォルトでブロックするようになります。この変更により、ウェブ上でのユーザーのプライバシーとセキュリティが改善され、より明確なブラウザセキュリティUXをユーザーに提示することができます。

混合コンテンツ

混合コンテンツとは、https内に存在するhttpなコンテンツのことを指します。
つまり「https://xxxxxxxxx.com/」というセキュアなサイト内で「http://yyyyyyyyyyy.com/image/test.png」のようなセキュアでないコンテンツを呼び出している状態を意味します。

つまり、httpなサイトはChromeで閲覧できなくなる可能性があるということです。
さらにこの問題が顕著なのは、日本におけるChromeの利用率が高いという点です。
(参照元: https://lab.syncer.jp/Statistic/Browser/2019/10/

・ デスクトップのシェア:66.14%(1位)
・ モバイルのシェア:26.46%(2位)
・ タブレットのシェア:36.56%(2位)

社内だけのサービス(退勤管理やソース管理など)だからといって、セキュア化していないとアクセスできない。なんてことにならないように社内のネットワーク整備をすることにしました。

では、社会人1年目、新卒入社の筆者が社内ネットワーク整備に奮闘した一部始終をどうぞ!!

環境

  • CentOS 7
    → 社内サービスがDocker on CentOS7で動いてた
  • Let's Encrypt
    → 無料で使えるSSL証明書。90日で期限が切れるため更新が必須
  • Cloudflare
    → ワイルドカード証明書を発行するのにDNSレコードを変更する必要があるため、無料で使えるCloudflareを採用。(このためだけにNSを変更したといっても過言ではない)
  • lego(https://go-acme.github.io/lego/
    → Let's Encryptの環境がさくっと作れるDocker環境。大体のDNS Providerに対応してて、それぞれの設定方法や実行方法が書いてあってありがたい。 (対応してるDNS Provider一覧はこちら

改修フロー

https化へのざっくりとしたフローはこちらです。

  1. 社内サービスへのアクセスをサブドメインで行えるようにする
  2. ドメインのネームサーバー(NS)をCloudflareに変更
  3. Cloudflareでソーン編集用APIアクセスキーを作成
  4. 社内サービスコンテナ内で自動更新スクリプト等の作成
  5. Nginxなどに証明書を食わせる

今回は検証用の個人的なドメイン(choipre.com)(Google Domains)を使って解説します。
ドメイン取ったけど、個人サービスが完成していないので、何しても大丈夫だし。

!! 注意 !!
設定を間違えるとサイトにアクセスできなくなったりする可能性があります。必ず変更点(Diff)などはメモするようにしておいた方が、万が一のためです。バックアップなどを取りつつ作業を進めることをおすすめします。

1. 社内サービスへのアクセスをサブドメインで行えるようにする

これまで、社内サービスにはIPアドレスを使ってアクセスしていました。そのためhttps化できず、httpな状態で運用していました。まずは、社内サービスへのアクセスをサブドメインでアクセスできるようにするため、社内DNSを整備します。ドメインは、会社HPなどで元々利用しているものを利用しました。その内容は別記事として割愛します。

参照: Dockerを使って最速で社内DNSを構築してみた

2. ドメインのNSをCloudflareに変更

なぜCloudflareに変更したかというと、CloudflareではAPIを使ってドメインのゾーン情報(A, AAAA, TXTなどのDNSレコード情報)を書き換えることができます。
(参考: https://api.cloudflare.com/#zone-subscription-zone-subscription-details

この仕組みを利用して、スクリプト上でワイルドカードのSSL証明書を発行するのに必要なレコード内容を自動で書き込みたかったからです。
(証明書更新する度に手動でDNSレコードに追記したり、削除したりするのって面倒だし、ネットワークの知識がない人が更新しないといけないってなったときに、このコマンド一発叩けばいいよ!の方がいいよね?)

Cloudflareにドメインを登録

Cloudflareのアカウントを持っていない人はアカウント作成してください。

アカウント作成後、トップ画面に 【サイトを追加する】 を押します。
(※ 画像は既に登録済みのドメインがあるため、Cloudflareの管理下にあるドメイン一覧がありますが、初期登録後の人は何も表示されていません。)
スクリーンショット 2020-11-23 17.56.06.png

Cloudflareで管理したいドメインを入力します。
スクリーンショット 2020-11-23 17.58.27.png

プラン選択画面が表示されるので 【Freeプラン】 を選択します。
(Freeプランでここまで出来るってCloudflare様様...)
スクリーンショット 2020-11-23 18.00.12.png

Cloudflareに既存DNSレコードを移植

ドメインの登録が完了すると、現在設定されているDNSレコードを読み取って、Cloudflareに書き込み準備をしてくれます。このときにDNSレコードを修正することもできますが、必要がない人はそのまま 【続行】 します。
ただし、AレコードとMXレコードが同一の場合、AレコードをCloudflareのプロキシから外す必要があります。プロキシから外してDNS解決のみにしないとメールサーバーが正常に動作しないためです。
(参考: Cloudflareの使用時にメールが配信不能になる - メール関連のDNSレコード
スクリーンショット 2020-11-23 18.00.25.png
スクリーンショット 2020-11-23 18.05.43.png

CloudflareのNSに変更する

Cloudflareに取り込むDNSレコードの設定が終わったら、ドメインのNSをCloudflareに変更するように促されます。
スクリーンショット 2020-11-23 18.06.54.png

各ドメインの管理画面からドメインのNSを変更します。今回の検証用ドメインはGoogle Domainsで取得しているため、Google Domainsの設定画面から変更します。
スクリーンショット 2020-11-23 18.09.02.png

ドメインのNS変更が終わったら、Cloudflareで引き続き設定を行います。ここでは、ドメインへのアクセス、コンテンツのキャッシュ・圧縮設定ができます。利用に応じた設定を行ってください。
スクリーンショット 2020-11-23 18.15.56.png

検証用ドメインでは、以下のように設定しました。
スクリーンショット 2020-11-23 18.17.03.png

Cloudflare-NSの変更チェック

次にNSレコードのチェックをします。既にNSの変更が検知できている場合は、以下のような表示になります。
スクリーンショット 2020-11-23 18.20.43.png

まだ、検知できていない場合は以下のような表示になります。ドメインの設定がネットワーク全体に浸透するまでは24~48時間程かかります。Cloudflareでチェックしても変更されていなかった場合は、少し時間をおいてください。ちなみに、Cloudflareで正常にNSが変更されていることを検知すると、アカウント登録時に設定したメールアドレスに通知がきます。
スクリーンショット 2020-11-23 18.20.25.png

3. ソーン編集用APIアクセスキーを作成

legoのライブラリを利用するために必要な、CloudflareのDNSゾーン情報APIアクセスキーを作成します。キーは2種類作成します。
ゾーン情報の【DNS編集キー】と【ゾーン編集キー】です。Cloudflareのアカウント設定のAPIトークンから作成することができます。
スクリーンショット 2020-11-24 0.28.27.png

まず、APIアクセスキーを作成する前に、画面下部にある「Global Api key」も取得しておきましょう。4.のdocker-compose.ymlに記述する必要があるためです。
スクリーンショット 2020-11-28 15.37.07.png

アクセスキーを作成する際に、いくつかテンプレートが用意されています。今回は【ゾーンDNSを編集する】というテンプレートを編集して利用します。テンプレートを利用せずに0から作成することもできますが、慣れてから使うか、似たテンプレートを変更したほうが無難そうです。
スクリーンショット 2020-11-24 0.30.16.png

1つのトークンに対して、複数の権限を付与することができますが、トークンが増えてくると管理がしづらくなるので、1トークン1権限で運用することとします。アクセス許可に以下を、それぞれ設定して2つのトークンを作成します。

  • 1つ目のトークン
    → ゾーン:DNS:編集
  • 2つ目のトークン
    → ゾーン:ゾーン:編集
  • 2つの共通設定(ゾーンリソース)
    → 包含:特定のゾーン:ワイルドカード証明書を発行したいドメイン

スクリーンショット 2020-11-24 0.33.24.png

トークン作成を進めると、以下のような画面が表示されます。このときに表示されるトークンをメモしてください。ここで表示されたトークンは、画面にもあるように再表示されません。そのため、必ずメモするようにしてください。メモし忘れたら、APIトークンを削除して、再作成してください。
スクリーンショット 2020-11-24 0.56.49.png

4. SSL証明書の自動更新スクリプトの作成

会社の社内サービスが動いているDockerでは、以下のような運用がされています。

  • 平日(月〜金)は昼夜問わず常時起動
  • 休日(土日)に自動シャットダウン
  • 月曜にサービスを立ち上げる

このことから、サービスを立ち上げるときにSSL証明書の更新処理を走るようにしておけば、最低週に1回は確認することになり、更新忘れによる証明書失効を防ぐことが出来ると考えました。サービス自体がDockerで運用されているため、SSL更新処理もDocker化して、Serviceとして登録する方向にしました。

lego(https://go-acme.github.io/lego/)を使ったSSL証明書更新用Dockerは以下のように設定しました。

docker-compose.yml
services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      run
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

docker-compose.yml を作成して、docker-composeを実行します。

$ docker-compose up

実行が終わると、以下のようなログが流れ、/opt/cert 配下に証明書本体が格納されているディレクトリと、更新に必要なアカウント情報が含まれているディレクトリが生成されます。

❯ docker-compose up
Recreating certbot-cloudflare_certbot-lego_1 ... done
Attaching to certbot-cloudflare_certbot-lego_1
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] acme: Registering account for [Cloudflareに登録したメールアドレス]
certbot-lego_1  | !!!! HEADS UP !!!!
certbot-lego_1  |
certbot-lego_1  | Your account credentials have been saved in your Let's Encrypt
certbot-lego_1  | configuration directory at "/lego/accounts".
certbot-lego_1  |
certbot-lego_1  | You should make a secure backup of this folder now. This
certbot-lego_1  | configuration directory will also contain certificates and
certbot-lego_1  | private keys obtained from Let's Encrypt so making regular
certbot-lego_1  | backups of this folder is ideal.
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] [*.choipre.com, choipre.com] acme: Obtaining bundled SAN certificate
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315819
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315820
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] acme: use dns-01 solver
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: tls-alpn-01
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: http-01

(省略)

certbot-lego_1  | 2020/11/28 06:44:11 [INFO] [*.choipre.com, choipre.com] acme: Validations succeeded; requesting certificates
certbot-lego_1  | 2020/11/28 06:44:12 [INFO] [*.choipre.com] Server responded with a certificate.
certbot-cloudflare_certbot-lego_1 exited with code 0
drwxr-xr-x     - nomunomu 28 11 15:43   └── opt
drwxr-xr-x     - nomunomu 28 11 15:44      └── cert
drwx------     - nomunomu 28 11 15:43         ├── accounts
drwx------     - nomunomu 28 11 15:43         │  └── acme-v02.api.letsencrypt.org
drwx------     - nomunomu 28 11 15:44         │     └── xxxxxxxxxxx@gmail.com
.rw-------   225 nomunomu 28 11 15:44         │        ├── account.json
drwx------     - nomunomu 28 11 15:43         │        └── keys
.rw-r--r--   227 nomunomu 28 11 15:43         │           └── xxxxxxxxxx@gmail.com.key
drwx------     - nomunomu 28 11 15:44         └── certificates
.rw-------  3.3k nomunomu 28 11 15:44            ├── _.choipre.com.crt
.rw-------  1.6k nomunomu 28 11 15:44            ├── _.choipre.com.issuer.crt
.rw-------   234 nomunomu 28 11 15:44            ├── _.choipre.com.json
.rw-------   227 nomunomu 28 11 15:44            └── _.choipre.com.key

この生成されたフォルダで、accountsフォルダは今後証明書を更新していくなかで必要になるフォルダです。証明書類はcertificatesに保管されています。
「_.choipre.com.crt」がchoipre.comのワイルドカード証明書になります。

一度、証明書発行を実行したので、今後は更新という処理を行う設定にしておく必要があります。そのため、docker-compose.ymlを以下のように変更します。

services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      renew
      --days 30
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

変更点は、run から renew コマンドに変更することです。パラメーターとして --days を指定することで指定した日数を切ってから更新させることができます。

この、docker-composeの実行をcronなどに設定することで自動更新を行えるようになります。

5. ワイルドカードをnginxに適用する

4.で生成した証明書をNginxに適用していきます。証明書類は/opt/cert配下にあるものとします。Nginxの設定ファイルに以下の記述を追加します。
追記場所はNginxの設定ファイルの使用したいServer設定の中です。デフォルト構成を利用している人は server{ ... } の中に記述します。

ssl_certificate      /opt/cert/_.choipre.com.crt;
ssl_certificate_key  /opt/cert/_.choipre.com.key;

記述ができたら、Nginxのプロセスを再起動します。Nginxのプロセスを再起動したら、対象のアドレスに対してhttpsアクセスをすると証明書が適用されていることが分かります。

まとめ

以上で、自動更新可能なワイルドカード証明書発行の実装が終わりました。
初期設定は大変ですが、今後はあらゆるサブドメインに対してSSL通信を行うことができます。これでChromeでhttpコンテンツが閲覧できなくなっても、安心ですね。

生産性を向上してHappy Lifeを!!

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

Cloudflare + docker-composeで自動更新可能ワイルドカード証明書を発行して社内サービスをSSL化してみた

この記事は 生産性向上のための環境整備2020 【PR】 Lenovo Advent Calendar 2020 の3日目の記事です。

2日目の記事:腰痛のためのリマインダー機能 by @ryu3
4日目の記事:エンジニアのための目を休ませる最高の環境 @newt0

Chromeでhttpサイトが見れなくなる??

Chromeの開発元であるGoogleは以下のような声明を出しました。
(引用元: https://security.googleblog.com/2019/10/no-more-mixed-messages-about-https_3.html

Today we’re announcing that Chrome will gradually start ensuring that https:// pages can only load secure https:// subresources. In a series of steps outlined below, we’ll start blocking mixed content (insecure http:// subresources on https:// pages) by default. This change will improve user privacy and security on the web, and present a clearer browser security UX to users.

本日、Chrome では、https:// ページが安全な https:// サブリソースのみを読み込むことができるようにすることを段階的に開始することを発表しました。以下に概説する一連の手順で、混合コンテンツ ( https:// ページの安全でない http:// サブリソース) をデフォルトでブロックするようになります。この変更により、ウェブ上でのユーザーのプライバシーとセキュリティが改善され、より明確なブラウザセキュリティUXをユーザーに提示することができます。

混合コンテンツ

混合コンテンツとは、https内に存在するhttpなコンテンツのことを指します。
つまり「https://xxxxxxxxx.com/」というセキュアなサイト内で「http://yyyyyyyyyyy.com/image/test.png」のようなセキュアでないコンテンツを呼び出している状態を意味します。

つまり、httpなサイトはChromeで閲覧できなくなる可能性があるということです。
さらにこの問題が顕著なのは、日本におけるChromeの利用率が高いという点です。
(参照元: https://lab.syncer.jp/Statistic/Browser/2019/10/

・ デスクトップのシェア:66.14%(1位)
・ モバイルのシェア:26.46%(2位)
・ タブレットのシェア:36.56%(2位)

社内だけのサービス(退勤管理やソース管理など)だからといって、セキュア化していないとアクセスできない。なんてことにならないように社内のネットワーク整備をすることにしました。

では、社会人1年目、新卒入社の筆者が社内ネットワーク整備に奮闘した一部始終をどうぞ!!

環境

  • CentOS 7
    → 社内サービスがDocker on CentOS7で動いてた
  • Let's Encrypt
    → 無料で使えるSSL証明書。90日で期限が切れるため更新が必須
  • Cloudflare
    → ワイルドカード証明書を発行するのにDNSレコードを変更する必要があるため、無料で使えるCloudflareを採用。(このためだけにNSを変更したといっても過言ではない)
  • lego(https://go-acme.github.io/lego/
    → Let's Encryptの環境がさくっと作れるDocker環境。大体のDNS Providerに対応してて、それぞれの設定方法や実行方法が書いてあってありがたい。 (対応してるDNS Provider一覧はこちら

改修フロー

https化へのざっくりとしたフローはこちらです。

  1. 社内サービスへのアクセスをサブドメインで行えるようにする
  2. ドメインのネームサーバー(NS)をCloudflareに変更
  3. Cloudflareでソーン編集用APIアクセスキーを作成
  4. 社内サービスコンテナ内で自動更新スクリプト等の作成
  5. Nginxなどに証明書を食わせる

今回は検証用の個人的なドメイン(choipre.com)(Google Domains)を使って解説します。
ドメイン取ったけど、個人サービスが完成していないので、何しても大丈夫だし。

!! 注意 !!
設定を間違えるとサイトにアクセスできなくなったりする可能性があります。必ず変更点(Diff)などはメモするようにしておいた方が、万が一のためです。バックアップなどを取りつつ作業を進めることをおすすめします。

1. 社内サービスへのアクセスをサブドメインで行えるようにする

これまで、社内サービスにはIPアドレスを使ってアクセスしていました。そのためhttps化できず、httpな状態で運用していました。まずは、社内サービスへのアクセスをサブドメインでアクセスできるようにするため、社内DNSを整備します。ドメインは、会社HPなどで元々利用しているものを利用しました。その内容は別記事として割愛します。

参照: Dockerを使って最速で社内DNSを構築してみた

2. ドメインのNSをCloudflareに変更

なぜCloudflareに変更したかというと、CloudflareではAPIを使ってドメインのゾーン情報(A, AAAA, TXTなどのDNSレコード情報)を書き換えることができます。
(参考: https://api.cloudflare.com/#zone-subscription-zone-subscription-details

この仕組みを利用して、スクリプト上でワイルドカードのSSL証明書を発行するのに必要なレコード内容を自動で書き込みたかったからです。
(証明書更新する度に手動でDNSレコードに追記したり、削除したりするのって面倒だし、ネットワークの知識がない人が更新しないといけないってなったときに、このコマンド一発叩けばいいよ!の方がいいよね?)

Cloudflareにドメインを登録

Cloudflareのアカウントを持っていない人はアカウント作成してください。

アカウント作成後、トップ画面に 【サイトを追加する】 を押します。
(※ 画像は既に登録済みのドメインがあるため、Cloudflareの管理下にあるドメイン一覧がありますが、初期登録後の人は何も表示されていません。)
スクリーンショット 2020-11-23 17.56.06.png

Cloudflareで管理したいドメインを入力します。
スクリーンショット 2020-11-23 17.58.27.png

プラン選択画面が表示されるので 【Freeプラン】 を選択します。
(Freeプランでここまで出来るってCloudflare様様...)
スクリーンショット 2020-11-23 18.00.12.png

Cloudflareに既存DNSレコードを移植

ドメインの登録が完了すると、現在設定されているDNSレコードを読み取って、Cloudflareに書き込み準備をしてくれます。このときにDNSレコードを修正することもできますが、必要がない人はそのまま 【続行】 します。
ただし、AレコードとMXレコードが同一の場合、AレコードをCloudflareのプロキシから外す必要があります。プロキシから外してDNS解決のみにしないとメールサーバーが正常に動作しないためです。
(参考: Cloudflareの使用時にメールが配信不能になる - メール関連のDNSレコード
スクリーンショット 2020-11-23 18.00.25.png
スクリーンショット 2020-11-23 18.05.43.png

CloudflareのNSに変更する

Cloudflareに取り込むDNSレコードの設定が終わったら、ドメインのNSをCloudflareに変更するように促されます。
スクリーンショット 2020-11-23 18.06.54.png

各ドメインの管理画面からドメインのNSを変更します。今回の検証用ドメインはGoogle Domainsで取得しているため、Google Domainsの設定画面から変更します。
スクリーンショット 2020-11-23 18.09.02.png

ドメインのNS変更が終わったら、Cloudflareで引き続き設定を行います。ここでは、ドメインへのアクセス、コンテンツのキャッシュ・圧縮設定ができます。利用に応じた設定を行ってください。
スクリーンショット 2020-11-23 18.15.56.png

検証用ドメインでは、以下のように設定しました。
スクリーンショット 2020-11-23 18.17.03.png

Cloudflare-NSの変更チェック

次にNSレコードのチェックをします。既にNSの変更が検知できている場合は、以下のような表示になります。
スクリーンショット 2020-11-23 18.20.43.png

まだ、検知できていない場合は以下のような表示になります。ドメインの設定がネットワーク全体に浸透するまでは24~48時間程かかります。Cloudflareでチェックしても変更されていなかった場合は、少し時間をおいてください。ちなみに、Cloudflareで正常にNSが変更されていることを検知すると、アカウント登録時に設定したメールアドレスに通知がきます。
スクリーンショット 2020-11-23 18.20.25.png

3. ソーン編集用APIアクセスキーを作成

legoのライブラリを利用するために必要な、CloudflareのDNSゾーン情報APIアクセスキーを作成します。キーは2種類作成します。
ゾーン情報の【DNS編集キー】と【ゾーン編集キー】です。Cloudflareのアカウント設定のAPIトークンから作成することができます。
スクリーンショット 2020-11-24 0.28.27.png

まず、APIアクセスキーを作成する前に、画面下部にある「Global Api key」も取得しておきましょう。4.のdocker-compose.ymlに記述する必要があるためです。
スクリーンショット 2020-11-28 15.37.07.png

アクセスキーを作成する際に、いくつかテンプレートが用意されています。今回は【ゾーンDNSを編集する】というテンプレートを編集して利用します。テンプレートを利用せずに0から作成することもできますが、慣れてから使うか、似たテンプレートを変更したほうが無難そうです。
スクリーンショット 2020-11-24 0.30.16.png

1つのトークンに対して、複数の権限を付与することができますが、トークンが増えてくると管理がしづらくなるので、1トークン1権限で運用することとします。アクセス許可に以下を、それぞれ設定して2つのトークンを作成します。

  • 1つ目のトークン
    → ゾーン:DNS:編集
  • 2つ目のトークン
    → ゾーン:ゾーン:編集
  • 2つの共通設定(ゾーンリソース)
    → 包含:特定のゾーン:ワイルドカード証明書を発行したいドメイン

スクリーンショット 2020-11-24 0.33.24.png

トークン作成を進めると、以下のような画面が表示されます。このときに表示されるトークンをメモしてください。ここで表示されたトークンは、画面にもあるように再表示されません。そのため、必ずメモするようにしてください。メモし忘れたら、APIトークンを削除して、再作成してください。
スクリーンショット 2020-11-24 0.56.49.png

4. SSL証明書の自動更新スクリプトの作成

会社の社内サービスが動いているDockerでは、以下のような運用がされています。

  • 平日(月〜金)は昼夜問わず常時起動
  • 休日(土日)に自動シャットダウン
  • 月曜にサービスを立ち上げる

このことから、サービスを立ち上げるときにSSL証明書の更新処理を走るようにしておけば、最低週に1回は確認することになり、更新忘れによる証明書失効を防ぐことが出来ると考えました。サービス自体がDockerで運用されているため、SSL更新処理もDocker化して、Serviceとして登録する方向にしました。

lego(https://go-acme.github.io/lego/)を使ったSSL証明書更新用Dockerは以下のように設定しました。

docker-compose.yml
services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      run
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

docker-compose.yml を作成して、docker-composeを実行します。

$ docker-compose up

実行が終わると、以下のようなログが流れ、/opt/cert 配下に証明書本体が格納されているディレクトリと、更新に必要なアカウント情報が含まれているディレクトリが生成されます。

❯ docker-compose up
Recreating certbot-cloudflare_certbot-lego_1 ... done
Attaching to certbot-cloudflare_certbot-lego_1
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] acme: Registering account for [Cloudflareに登録したメールアドレス]
certbot-lego_1  | !!!! HEADS UP !!!!
certbot-lego_1  |
certbot-lego_1  | Your account credentials have been saved in your Let's Encrypt
certbot-lego_1  | configuration directory at "/lego/accounts".
certbot-lego_1  |
certbot-lego_1  | You should make a secure backup of this folder now. This
certbot-lego_1  | configuration directory will also contain certificates and
certbot-lego_1  | private keys obtained from Let's Encrypt so making regular
certbot-lego_1  | backups of this folder is ideal.
certbot-lego_1  | 2020/11/28 06:44:01 [INFO] [*.choipre.com, choipre.com] acme: Obtaining bundled SAN certificate
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315819
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/8920315820
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [*.choipre.com] acme: use dns-01 solver
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: tls-alpn-01
certbot-lego_1  | 2020/11/28 06:44:03 [INFO] [choipre.com] acme: Could not find solver for: http-01

(省略)

certbot-lego_1  | 2020/11/28 06:44:11 [INFO] [*.choipre.com, choipre.com] acme: Validations succeeded; requesting certificates
certbot-lego_1  | 2020/11/28 06:44:12 [INFO] [*.choipre.com] Server responded with a certificate.
certbot-cloudflare_certbot-lego_1 exited with code 0
drwxr-xr-x     - nomunomu 28 11 15:43   └── opt
drwxr-xr-x     - nomunomu 28 11 15:44      └── cert
drwx------     - nomunomu 28 11 15:43         ├── accounts
drwx------     - nomunomu 28 11 15:43         │  └── acme-v02.api.letsencrypt.org
drwx------     - nomunomu 28 11 15:44         │     └── xxxxxxxxxxx@gmail.com
.rw-------   225 nomunomu 28 11 15:44         │        ├── account.json
drwx------     - nomunomu 28 11 15:43         │        └── keys
.rw-r--r--   227 nomunomu 28 11 15:43         │           └── xxxxxxxxxx@gmail.com.key
drwx------     - nomunomu 28 11 15:44         └── certificates
.rw-------  3.3k nomunomu 28 11 15:44            ├── _.choipre.com.crt
.rw-------  1.6k nomunomu 28 11 15:44            ├── _.choipre.com.issuer.crt
.rw-------   234 nomunomu 28 11 15:44            ├── _.choipre.com.json
.rw-------   227 nomunomu 28 11 15:44            └── _.choipre.com.key

この生成されたフォルダで、accountsフォルダは今後証明書を更新していくなかで必要になるフォルダです。証明書類はcertificatesに保管されています。
「_.choipre.com.crt」がchoipre.comのワイルドカード証明書になります。

一度、証明書発行を実行したので、今後は更新という処理を行う設定にしておく必要があります。そのため、docker-compose.ymlを以下のように変更します。

services:
  certbot-lego:
    image: goacme/lego:latest
    environment:
      - CLOUDFLARE_API_EMAIL=[Cloudflareで登録したメールアドレス]
      - CLOUDFLARE_API_KEY=[3.で取得したGlobal Api Key]
      - CLOUDFLARE_DNS_API_TOKEN=[3.で作成したゾーン:DNS編集APIキー]
      - CLOUDFLARE_ZONE_API_TOKEN=[3.で作成したゾーン:ゾーン編集APIキー]
    command: >
      --path /lego
      --dns cloudflare          # 利用しているDNSプロバイダに書き換えてください
      --dns.resolvers 8.8.8.8   # DNSレコードが伝搬していない可能性があるのでパブリックDNSで解決させる
      --email [Cloudflareで登録したメールアドレス]
      --domains "*.choipre.com" # 適宜置き換えてください
      --domains "choipre.com"   # 適宜置き換えてください
      --accept-tos
      renew
      --days 30
    volumes:
      - /opt/cert:/lego         # /opt/cert 配下に証明書等が吐き出されます。適宜書き換えてください

変更点は、run から renew コマンドに変更することです。パラメーターとして --days を指定することで指定した日数を切ってから更新させることができます。

この、docker-composeの実行をcronなどに設定することで自動更新を行えるようになります。

5. ワイルドカードをnginxに適用する

4.で生成した証明書をNginxに適用していきます。証明書類は/opt/cert配下にあるものとします。Nginxの設定ファイルに以下の記述を追加します。
追記場所はNginxの設定ファイルの使用したいServer設定の中です。デフォルト構成を利用している人は server{ ... } の中に記述します。

ssl_certificate      /opt/cert/_.choipre.com.crt;
ssl_certificate_key  /opt/cert/_.choipre.com.key;

記述ができたら、Nginxのプロセスを再起動します。Nginxのプロセスを再起動したら、対象のアドレスに対してhttpsアクセスをすると証明書が適用されていることが分かります。

まとめ

以上で、自動更新可能なワイルドカード証明書発行の実装が終わりました。
初期設定は大変ですが、今後はあらゆるサブドメインに対してSSL通信を行うことができます。これでChromeでhttpコンテンツが閲覧できなくなっても、安心ですね。

生産性を向上してHappy Lifeを!!

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

[Fargate 入門] ECS(Fargate)でrakeタスクを実行するまで

Fargateで単純なrakeタスクを実行するまでの手順。
タスク定義やコンテナの設定などがややこしかったため備忘録として。

準備

実行するrakeタスクとコンテナイメージを用意します。

rakeタスクの作成

今回はrakeタスク実行が確認できれば良いので単純なタスクを用意。

namespace :ecs_task do
  task :hoge do
    puts "task started"
  end
end

コンテナイメージの用意

以下のようなDockerfileを作成し、rakeタスクが実行できる環境を用意します。

Dockerfile
FROM ruby:2.5.3

# 環境変数
ENV LANG C.UTF-8
ENV APP_ROOT /app

# ソースをコンテナに転送
ADD ./ $APP_ROOT

# コンテナ内の作業ディレクトリの設定
WORKDIR $APP_ROOT

# gemのインストール
RUN gem update bundler
RUN bundle install

コンテナイメージをECRへプッシュする

Fargateでタスクを実行するためにDockerfileからイメージを作成してECRにプッシュします。
(Docker Hubでも良いですが今回はECRを利用)

マネジメントコンソールからリポジトリを作成しましょう。
下記のようにリポジトリが作成されたらOKです。
repository.png
プッシュコマンドの表示を押すと、ECRへイメージをプッシュする手順が表示されるので、手順にしたがってプッシュします。
プッシュ後、下記のようにイメージが存在すればOKです。
ecr image.png

準備は完了したので、ECSでクラスターとタスク定義を作成していきましょう。

ECS

マネジメントコンソール上でクラスターとタスク定義を作成していきます。

クラスターの作成

ECS > クラスターからクラスターを作成します。
今回はFargateを利用するので、ネットワーキングのみ(AWS Fargateを使用)を選択。
cluster template.png

クラスターの名前を入れて作成。
今回は既存のVPCを利用するのでVPCは作成しませんでした。
cluster setting.png
これでクラスター作成は完了しました。

タスク定義の作成

次にクラスターで実行させるタスクを作成していきます。
起動タイプの互換性の選択で、こちらもFargateを選択します。

タスクとコンテナの設定

次にタスクとコンテナの設定をしていきます。
task1.png

タスクロール

タスクを実行するコンテナに付与するIAMロールです。タスクでS3やRDSなどAWSサービスにアクセスする必要がある場合は、必要な権限を持ったロールを設定します。
今回は不要なのでスキップ。

タスクの実行IAMロール

タスクを実行(開始)するために必要なロールです。
説明にもありますが、コンテナイメージをECRからプルしたり、コンテナのログをCloudWatch Logsに吐き出すための権限を持ったロールが必要になります。

run_task_role.png
初回は新しいロールの作成で自動的に必要なロールを作成してくれるのでこのままでOK。

タスクサイズ

タスクの実行に使用されるメモリとCPUを設定します。(Fargateでは必須)
ひとまず最小限のメモリとCPUを設定しました。
task_size.png

コンテナの設定

タスク実行に必要なコンテナの設定をします。

基本設定

container_standard.png

スタンダード(基本設定)
コンテナ名 コンテナの名前
イメージ コンテナのURI(ECRからコピーできます)
プライベートレジストリの認証 プライベートのリポジトリからイメージをプルする場合に必要(ECRを利用する場合は不要)
メモリ制限(MiB) コンテナに対するメモリの制限ですが、Fargateではタスクに対してサイズを設定しているので、コンテナで制限をかける意味はよくわかっていません。
ポートマッピング コンテナのポートとホストインスタンスのポートを紐づける場合に設定します。
今回は単純なrake実行のみなので使用しません。

環境

コンテナ環境で実行したいコマンドと作業ディレクトリを以下のように指定。
container_env.png

その他

ヘルスチェックやネットワークの設定などがありますが今回は使用しないので入力する必要はありません。

以上でタスク定義の設定は終了です。

タスクの実行

さっそくタスクを実行していきましょう。

タスクにチェックを入れてタスクの実行をクリック。
start_task.png

タスク実行時の設定を入力していきます。
起動タイプはFARGATE、タスクを実行するVPCやサブネットなどを入力し、タスクの実行をクリック。
run_task.png

タスクのプロビジョニングが開始されます。
task_provisioning.png

しばらく待っているとRUNNINGに。
task_running.png

ログの確認

ちゃんとタスクが実行されているかログを確認してみましょう。
タスクの実行ログはデフォルトではCloudWatch Logsに吐き出されます。

ロググループに/ecs/タスク名が作成されていますのでクリック。
タスクが実行されたことがわかりました。
log.png

所感

初めてECSを触ったということもありますが、色々設定することが多く初めは手間取りました。
タスク定義(コンテナ周り)など、まだまだ今回使っていない設定項目は多数あるので、今後調べていきます。
また今回は1コンテナ、単純なrakeタスクの実行しかしていないので、複数コンテナの連携(フロント、バックエンド、DB)などをECSで行ってみようと思います。

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