Docker で Ruby on Rails5 の開発環境を構築する
Docker で Ruby on Rails5 の開発環境のベースイメージを作成したときの手順メモ
設定ファイルおよび操作手順について
こちらのサイトに記載されている手順で rails5 もセットアップできました。
qiita.com
以下、内容を変更した設定ファイルです。
Dockerfile
# # ruby 2.3 + rails 5.0.0.1 # # 2016-10-05 # FROM ruby:2.3 MAINTAINER takaya030 ENV APP_ROOT /usr/src/myapp WORKDIR $APP_ROOT RUN apt-get update && \ apt-get install -y nodejs \ mysql-client \ postgresql-client \ sqlite3 \ --no-install-recommends && \ rm -rf /var/lib/apt/lists/* COPY Gemfile $APP_ROOT COPY Gemfile.lock $APP_ROOT RUN \ echo 'gem: --no-document' >> ~/.gemrc && \ cp ~/.gemrc /etc/gemrc && \ chmod uog+r /etc/gemrc && \ bundle config --global build.nokogiri --use-system-libraries && \ bundle config --global jobs 4 && \ bundle install && \ rm -rf ~/.gem # bundle install でカレントディレクトリに rails5 をインストールした後、 # 以下をコメントアウトして再度 docker build を実行する #COPY . $APP_ROOT # #EXPOSE 3000 #CMD ["rails", "server", "-b", "0.0.0.0"]
Gemfile
source "https://rubygems.org" gem 'rails', '5.0.0.1'
docker-compose.yml
version: '2' services: app: build: . image: developer_name/project_name container_name: project_name_app environment: RAILS_ENV: development command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/usr/src/myapp ports: - "3000:3000"
Docker で nginx + php-fpm + Laravel5.3 の開発環境を作る
Docker で Laravel 5.3 の開発環境を構築した際の手順メモ
検証環境
以下の環境で検証しました
VirtualBox、Docker はインストール済みの前提で話を進めます
Windows10 Home Edition VirtualBox 5.0.16 docker 1.10.3 docker-machine 0.6.0 docker-compose 1.6.2
準備作業
Windowsのエディタで php のコードを編集した結果を直ちに反映させるため、Windows のフォルダを VirtualBox にマウントし、そこに Laravel をインストールします
マウント手順は下記の記事を参照してください
takaya030.hatenablog.com
C:\workspace をマウントした後、C:\workspace\laravel53 フォルダを作成します
Docker イメージの作成のための各種ファイル
ファイル構成
l53 │ docker-compose.yml │ ├─nginx │ Dockerfile │ server.conf │ └─php7 bashrc Dockerfile index.php mysupervisord.conf
各ファイルの内容
l53/docker-compose.yml
nginx: build: ./nginx ports: - "80:80" - "9000:9000" links: - php7 php7: build: ./php7 hostname: laraweb ports: - "2022:22" volumes: - /workspace/laravel53:/webapp
l53/nginx/Dockerfile
FROM nginx:latest MAINTAINER takaya030 ADD server.conf /etc/nginx/conf.d/server.conf
l53/nginx/server.conf
server { listen 80 default; server_name _; root /webapp/public; index index.php index.html index.htm; charset utf-8; access_log off; error_log off; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ ^/index.php$ { fastcgi_pass l53_php7_1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } server { listen 9000 default; server_name _; root /var/www/html; index index.php index.html index.htm; charset utf-8; access_log off; error_log off; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ ^/index.php$ { fastcgi_pass l53_php7_1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
l53/php7/bashrc
# .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # git prompt if [ -f $HOME/.git-completion.bash ]; then source $HOME/.git-completion.bash fi if [ -f $HOME/.git-prompt.sh ]; then source $HOME/.git-prompt.sh export PS1='\[\033]0;$TITLEPREFIX:${PWD//[^[:ascii:]]/?}\007\]\n\[\033[32m\]\u@\h\[\033[35m\]: \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$ ' fi # User specific aliases and functions alias ls='ls -F --color=auto' alias ll='ls -la --color=auto' alias la='ls -a --color=auto' alias sl='ls -F --color=auto' alias glog='git log --oneline --decorate --graph --branches --tags --remotes'
l53/php7/Dockerfile
# # php7-fpm # # 2016-09-18 # PHP 7.0.11 FROM php:7-fpm MAINTAINER takaya030 # php RUN apt-get update \ && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \ && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt \ && apt-get clean # sshd, scp, sudo, unzip, tar RUN apt-get install -y openssh-server openssh-client sudo tar unzip supervisor && \ apt-get clean # gcc (for building git) RUN apt-get install -y build-essential libssl-dev gettext curl expat openssl zlibc libcurl4-openssl-dev \ && apt-get clean # git RUN curl -O https://www.kernel.org/pub/software/scm/git/git-2.9.3.tar.gz && \ tar xvzf git-2.9.3.tar.gz && \ cd git-2.9.3 && \ make configure && \ ./configure --prefix=/usr/local --with-curl --with-expat && \ make all && \ make install && \ cd .. && \ rm -r git-2.9.3 git-2.9.3.tar.gz # for git prompt RUN curl -L https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > /etc/skel/.git-completion.bash && \ curl -L https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > /etc/skel/.git-prompt.sh ADD ./bashrc /etc/skel/.bashrc # composer RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer # phpunit RUN curl -L https://phar.phpunit.de/phpunit.phar > /usr/local/bin/phpunit && \ chmod +x /usr/local/bin/phpunit # node, npm, gulp RUN apt-get install -y nodejs npm && \ npm cache clean && \ npm install n -g && \ n stable && \ apt-get purge -y nodejs npm && \ apt-get clean && \ /usr/local/bin/npm install --global gulp-cli # initialize for ssh RUN sed -i '/pam_loginuid\.so/s/required/optional/' /etc/pam.d/sshd && \ /usr/sbin/service ssh start && \ /usr/sbin/service ssh stop # create login user RUN useradd -d /home/laravel -m -s /bin/bash laravel && \ echo laravel:****laravel | chpasswd && \ echo 'laravel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers # timezone RUN cp -p /usr/share/zoneinfo/Japan /etc/localtime && \ echo "date.timezone = Asia/Tokyo" > /usr/local/etc/php/conf.d/myphp.ini # supervisor COPY ./mysupervisord.conf /etc/supervisor/conf.d/ COPY index.php /var/www/html/ EXPOSE 22 9000 CMD ["/usr/bin/supervisord"]
l53/php7/index.php
<?php phpinfo();
l53/php7/mysupervisord.conf
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
nodaemon=true ; (start in foreground if true;default false)
[program:sshd]
command=/usr/sbin/sshd -D
[program:php-fpm]
command=/usr/local/sbin/php-fpm
Docker イメージの作成
Docker ホストに上記のファイルを配置した後、以下のコマンドでイメージを作成します
$ cd l53
$ docker-compose build
コンテナの起動
$ cd l53 $ docker-compose up -d
ssh でログイン
$ ssh -p 2022 laravel@192.168.99.100 ※パスワードは "****laravel"
Laravel 5.3 のインストール
ssh でログインしたコンテナ上で以下のコマンドを実行する
$ cd /webapp $ composer create-project "laravel/laravel" --prefer-dist .
動作確認
WEBブラウザで http://192.168.99.100 にアクセスすると Laravel の welcome ページが表示されます
また http://192.168.99.100:9000 にアクセスすると phpinfo が表示されます
参考サイト
更新履歴
- (2016-09-27) l53/php7/Dockerfile に node, npm, gulp のインストールを追加
oriceon/oauth-5-laravel を使った Google API の OAuth 認証
前回手動で Google API の Access Token と Refresh Token を取得したので、それを使って oriceon/oauth-5-laravel で OAuth 認証を検証したときのメモ
検証環境
$ php --version PHP 5.5.19 (cli) (built: Nov 12 2014 12:35:44) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies $ php artisan --version Laravel Framework version 5.2.45
oriceon/oauth-5-laravel のインストール
composer.json に下記を追加
"require": { "oriceon/oauth-5-laravel": "dev-master" },
composer update を実行
$ composer update
OAuth クライアント ID、Refresh Token の取得
前回の記事を参考に予め取得する
Google API の Access Token を手動で取得する - takaya030の備忘録
サンプルコード
.env に下記を追加
# oauth GOOGLE_CLIENT_ID=Your-Clinet-Id GOOGLE_CLIENT_SECRET=Your-Clinet-Secret GOOGLE_ACCESS_TOKEN=Your-Access-Token GOOGLE_REFRESH_TOKEN=Your-Refresh-Token
config/oauth-5-laravel.php
<?php return [ /* |-------------------------------------------------------------------------- | oAuth Config |-------------------------------------------------------------------------- */ /** * Storage */ 'storage' => '\\OAuth\\Common\\Storage\\Session', /** * Consumers */ 'consumers' => [ 'Google' => [ 'client_id' => env('GOOGLE_CLIENT_ID'), 'client_secret' => env('GOOGLE_CLIENT_SECRET'), 'scope' => ['https://mail.google.com/'], ], ] ];
app/Http/Controllers/GmailController.php
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use OAuth\OAuth2\Token\StdOAuth2Token; class GmailController extends Controller { public function loginOAuth(Request $request) { // get data from request $access_token = env("GOOGLE_ACCESS_TOKEN"); $refresh_token = env("GOOGLE_REFRESH_TOKEN"); // get google service $googleService = \OAuth::consumer('Google'); if( !is_null($access_token) && !is_null($refresh_token) ) { $dummy_token = new StdOAuth2Token( $access_token, $refresh_token ); $token = $googleService->refreshAccessToken($dummy_token); $params = [ 'maxResults' => '3', 'q' => 'is:inbox', ]; // Send a request with it $result = json_decode($googleService->request('https://www.googleapis.com/gmail/v1/users/me/messages?'.http_build_query($params),'GET'), true); dd($result); } else { dd('No Access Token or Refresh Token.'); } } }
app/Http/routes.php
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('gmail', 'GmailController@loginOAuth' );
autoload 更新
$ php artisan optimize
Google API の Access Token を手動で取得する
はじめに
Google App Engine (GAE) を運用する場合通常サービスアカウントを使用しますが、サービスアカウントから個人の Gmail などにアクセスする際には別途 OAuth 認証を行って Access Token、Refresh Token を取得する必要があるため、その手順のメモ
OAuth クライアント ID の取得
Authorization Code 取得
Webブラウザで下記 URL にアクセスする
https://accounts.google.com/o/oauth2/auth?client_id=12345-xxxxx.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://mail.google.com/&response_type=code&approval_prompt=force&access_type=offline
client_id は上で取得したもの
scope は例として Gmail API のものを指定している。他の API を使う場合はに適宜変更すること
ブラウザに認証コードが表示されるのでメモする
scope を複数指定する場合
下記のように %20 で区切って指定する
scope=https://mail.google.com/%20https://www.googleapis.com/auth/datastore
Access Token 取得
上で取得した Authorization Code を使って Access Token を取得する (code で指定)
curl -k -d client_id=12345-xxxxx.apps.googleusercontent.com -d client_secret=xxxxx -d redirect_uri=urn:ietf:wg:oauth:2.0:oob -d grant_type=authorization_code -d code=xxxxx https://accounts.google.com/o/oauth2/token
下記JSONがレスポンスで返されるので access_token、refresh_token をメモする
{ "access_token" : "xxxxx...", "token_type" : "Bearer", "expires_in" : 3600, "refresh_token" : "xxxxx..." }
oriceon/oauth-5-laravel を使った Pocket API の OAuth 認証
oriceon/oauth-5-laravel で Pocket API の OAuth 認証を検証したときのメモ
検証環境
$ php --version PHP 5.5.19 (cli) (built: Nov 12 2014 12:35:44) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies $ php artisan --version Laravel Framework version 5.2.43
oriceon/oauth-5-laravel のインストール
composer.json に下記を追加
"require": { "oriceon/oauth-5-laravel": "dev-master" }
composer update を実行
$ composer update
consumer key の取得
下記リンク先で予め consumer key を取得します
Pocket: Developer API
サンプルコード
.env に下記を追加
# oauth POCKET_CLIENT_ID=Your-Consumer-Key
config/oauth-5-laravel.php
<?php return [ /* |-------------------------------------------------------------------------- | oAuth Config |-------------------------------------------------------------------------- */ /** * Storage */ 'storage' => '\\OAuth\\Common\\Storage\\Session', /** * Consumers */ 'consumers' => [ 'Pocket' => [ 'client_id' => env('POCKET_CLIENT_ID'), 'client_secret' => null, // Pocket API doesn't have a secret key. 'scope' => [], ], ] ];
app/Http/Controllers/PocketController.php
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class PocketController extends Controller { public function loginOAuth(Request $request) { // get pocket service $pocketService = \OAuth::consumer('Pocket',url('/loginresult')); // get request token $reqToken = $pocketService->requestRequestToken(); $request->session()->put( 'code', $reqToken ); // get pocketService authorization $url = $pocketService->getAuthorizationUri([ 'request_token' => $reqToken ]); // return to pocket login url return redirect((string)$url); } public function loginResult(Request $request) { // get data from request $code = $request->session()->get('code'); // get pocket service $pocketService = \OAuth::consumer('Pocket',url('/loginresult')); // if code is provided get user data and sign in if ( ! is_null($code)) { // This was a callback request from pocket, get the token $token = $pocketService->requestAccessToken($code); $params = [ 'consumer_key' => env('POCKET_CLIENT_ID'), 'access_token' => $token->getAccessToken(), 'sort' => 'newest', 'count' => '1', ]; // get a post (test) $json_result = $pocketService->request('https://getpocket.com/v3/get', 'POST', json_encode($params), [ 'Content-Type' => 'application/json' ]); $result = json_decode( $json_result ); dd($result); } else { dd('code is null.'); } } }
app/Http/routes.php
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('login', 'PocketController@loginOAuth' ); Route::get('loginresult', 'PocketController@loginResult' );
autoload 更新
$ php artisan optimize
Google Cloud Monitoring を使ってみた
Google Container Engine (GKE) のモニタリングについてのメモ
Cloud Monitoring の有効化
GKE でコンテンナクラスタを作成するときに "Cloud Monitoring を有効にする" にチェックを入れます。
初回は StackDriver のユーザー登録を行った後、使用可能になります。
2016年7月23日現在、BETA期間中につき無料で使用できます。
Kubernetes で Lumen を動かす
Google Container Engine (GKE) で Kubernetes を使って Lumen を動かしたときの手順メモ。
今回は ReplicationController で pod を 3 個立ててみました。
Docker イメージの作成
1 個の pod 内で nginx と php-fpm の 2 つのコンテナを起動させます。そのための Docker イメージを作成します。
nginx の Dockerfile
FROM nginx:latest MAINTAINER takaya030 ADD server.conf /etc/nginx/conf.d/server.conf
server.conf
同じ pod のコンテナは同じホストで起動するので php-fpm を localhost:9000 で参照する設定にしています。
server {
listen 80 default;
server_name _;
root /webapp/public;
index index.php index.html index.htm;
charset utf-8;
access_log off;
error_log off;
rewrite ^(.+)/$ $1;
location / {
# try_files $uri $uri/ /index.php$is_args$args;
try_files $uri /index.php?$query_string;
}
location ~ ^/index.php$ {
fastcgi_pass localhost:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
nginx イメージのビルド
$ docker build -t gcr.io/my_project_id/lumen_nginx .
php-fpm + lumen の Dockerfile
k8s_lumen フォルダはこちらで作成した Lumen の実行環境になります。
FROM php:7-fpm MAINTAINER takaya030 RUN apt-get update \ && apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng12-dev libmcrypt-dev \ && docker-php-ext-install pdo_mysql mysqli mbstring gd iconv mcrypt RUN mkdir /webapp COPY k8s_lumen /webapp
php-fpm イメージのビルド
$ docker build -t gcr.io/my_project_id/lumen_php7 .
イメージを Container Registry へ push
$ gcloud docker push gcr.io/my_project_id/lumen_nginx $ gcloud docker push gcr.io/my_project_id/lumen_php7
ReplicationController の作成
rc-k8slumen.yaml
apiVersion: v1 kind: ReplicationController metadata: name: k8slumen spec: replicas: 3 selector: app: weblumen template: metadata: name: k8slumen labels: app: weblumen spec: containers: - name: nginx image: gcr.io/my-project-id/lumen_nginx ports: - containerPort: 80 - name: lumen image: gcr.io/my-project-id/lumen_php7 ports: - containerPort: 9000
ReplicationController の作成
$ kubectl create -f rc-k8slumen.yaml replicationcontroller "k8slumen" created
ReplicationController の作成確認
$ kubectl get rc NAME DESIRED CURRENT AGE k8slumen 3 3 27s
service の作成
service-k8slumen.yaml
apiVersion: v1 kind: Service metadata: name: lumentest spec: ports: - port: 80 targetPort: 80 selector: app: weblumen type: LoadBalancer
service の作成
$ kubectl create -f service-k8slumen.yaml service "lumentest" created
service の作成確認
$ kubectl get services NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.3.240.1 <none> 443/TCP 7m lumentest 10.3.255.153 80/TCP 17s
動作確認
この状態で pod が 3 個起動しています。
$ kubectl get pods -l app=weblumen -o wide NAME READY STATUS RESTARTS AGE NODE k8slumen-5r9jc 2/2 Running 0 1m gke-cluster-1-default-pool-a58af72c-3ais k8slumen-itl2h 2/2 Running 0 1m gke-cluster-1-default-pool-a58af72c-yx7i k8slumen-xfed2 2/2 Running 0 1m gke-cluster-1-default-pool-a58af72c-4rtd
service を作成してから 1 分程経過するとグローバルIP (EXTERNAL-IP) が割り当てられるので、 http://EXTERNAL-IP にブラウザでアクセスして以下のように表示されれば成功です。
ロードバランスされているので、ブラウザをリロードした際、前回と別の pod にリクエストしたときは以下のように Server IP が変化します。
フェイルオーバー(failover)の検証
試しに pod を一つ削除してみます。
$ kubectl delete pod k8slumen-5r9jc pod "k8slumen-5r9jc" deleted
kubernetes が pod の減少を検知して自動で pod を立ち上げます。
pod のリストを見ると新しい pod が追加されているのが分かります。
$ kubectl get pods -l app=weblumen -o wide NAME READY STATUS RESTARTS AGE NODE k8slumen-itl2h 2/2 Running 0 31m gke-cluster-1-default-pool-a58af72c-yx7i k8slumen-w468c 2/2 Running 0 12s gke-cluster-1-default-pool-a58af72c-3ais k8slumen-xfed2 2/2 Running 0 31m gke-cluster-1-default-pool-a58af72c-4rtd
後始末
service、ReplicationController の削除
ReplicationController を削除すれば pod も自動で削除されます
$ kubectl delete -f service-k8slumen.yaml service "lumentest" deleted $ kubectl delete -f rc-k8slumen.yaml replicationcontroller "k8slumen" deleted