Cloud BuildでGKEのデプロイ
Cloud BuildでGAE/Goデプロイ by Slack の番外編として、Cloud Build を使ってGKE(Google Kubernetes Engine)にデプロイをする設定を実施してみたいと思います。
アプリのコードはこちらです。アプリ自体はGo言語のWebアプリケーションフレームワークGinのQuick Startを少し改変したものです。
Cloud BuildでGAE/Goデプロイ by Slack の番外編として、Cloud Build を使ってGKE(Google Kubernetes Engine)にデプロイをする設定を実施してみたいと思います。
アプリのコードはこちらです。アプリ自体はGo言語のWebアプリケーションフレームワークGinのQuick Startを少し改変したものです。
前回 Cloud BuildでGAE/Goデプロイ by Slack vol.3
Cloud BuildでGAE/Goデプロイ by Slack vol.4ということで、
今回はCloud BuildでGAE/Goをデプロイする設定を行います。
といっても、
ここまでの設定ができていれば、
デプロイ自体はgcloudコマンドを使えば、コマンド一発で済むので難しいことはありません。
では、早速やってみましょう。
前回 Cloud BuildでGAE/Goデプロイ by Slack vol.2
Cloud BuildでGAE/Goデプロイ by Slack vol.3ということで、
今回はCloud Buildをフックする部分について、実施したいと思います。
前回までで、Cloud Source Repositoriesへのマージの連携までできていますので、
このマージをフックしてCloud Build を起動する流れとなります。
前回 Cloud BuildでGAE/Goデプロイ by Slack vol.1
Cloud BuildでGAE/Goデプロイ by Slack vol.2ということで、
今回はSlackとBitBucketとCloud Source Repositoryを連携する設定を行いたいと思います。
(BitBucketのアカウント、およびリポジトリはすでに存在する前提で話を進めます)
目次
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
スマホアプリはJavaやObjective-Cなどでごりごり書くのが最もスタンダードな方法ですが、HTMLからアプリを生成してくれるフレームワークを使うハイブリッドアプリと呼ばれる方法もあります。 Angular と Cordova からアプリの機能を提供する機会があったので、まとめます。
npm install @angular/cli --save
npm install cordova --save
npmパッケージをローカルのnode_modules以下にインストールしています。
グローバルを汚してもよい方は -g オプションでどうぞ。
npx cordova create bibioapp
同じフォルダに bibioapp が作成されます。
このままアプリを作成することも可能ですが、今回はAngularのアプリを作成をすすめます。
npx は、ローカルにいれたnpm パッケージのコマンドを実行するコマンドです
はじめに、www 以下とpackage.jsonを待避します
mv bibioapp/www bibioapp/www.bak
mv bibioapp/package.json bibioapp/package.json.bak
npx ng new bibioapp
デフォルトで使用するブラウザで開きます。
cd bibioapp
npx ng serve --open
Cordovaでビルドできるように angular.json
を編集します。
(5から6になって、ファイル名がかわりました。Angular は設定がころころ変わりますね)outputPath
を www
に変更します。
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "www",
"index": "src/index.html",
"main": "src/main.ts",
ビルドを実行します
npx ng build
www 以下にbundleされたhtml,css,jsが出力されます。
src/index.html がビュー側のエントリポイントとなります。
Angularアプリを作成する前にとったバックアップから必要なタグを追加します
変更点を列挙していきます。
<base href="./">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<script type="text/javascript" src="cordova.js"></script>
widget要素 の id 属性がパッケージ名になるので、適当に変更する。
今回は com.example.bibioapp
にしました。
Android を追加します。
npx cordova platform add android@6.4.0
なお、パッケージ名を書き換えた場合は、一度削除してから再度追加しましょう。
npx cordova platform remove android
Android Studioを起動し、アプリルート/platforms/android
を開きます。
SDKを追加します。
Tools > SDK Manager を選択し、SDK Platforms タブから Android 8.1(API Level27)を選択します。
その後、エミュレータを追加します。
AVD Managerを起動して、エミュレータを追加します。
Android Studio のメニューバー Toolsから AVD Managerを起動します。
Create Virtual Deviceボタンをクリックし、Nexus 5Xを選択しNextをクリック、Oreo(API Level27)をDownloadしたあとに Nextをクリック、最後に内容を確認したあとに Finishをクリックします。
その後、エミュレータを起動します。
npx cordova emulate android
ビルドが開始され、しばらくするとアプリが起動します。
どんなアプリケーションであれ、
世の中に価値を提供するためには、デプロイメントを行う必要があります。
そして、
アプリケーションを一度作ったら終わりということは稀で、
継続的に、かつ頻繁に改修を加えていくことが多いので、
必然的にデプロイも継続的に、かつ頻繁に行うことになります。
いわゆるCI/CDですね。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
JavascriptでレンダーされるWebページの特定部分の情報を取ってくるみたいなことをするとき casperjs を使ったスクリプトが便利だけれど、cron実行しようとしたところ思うように動くまでに手こずったのでメモ。
環境
$ uname -mprsv
Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64 i386
$ node -v
v10.7.0
$ phantomjs --version
2.1.1
$ casperjs --version
1.1.4
$ python --version
Python 2.7.15
スクリプト
$ cat /Users/kadosawa/bin/doruby
#!/usr/bin/env casperjs
var url = "https://doruby.jp/";
var casper = require('casper').create();
casper.start(url, function() {
var that = this;
var title = casper.evaluate(function() {
return $('#newest-entries div.entry').first().text();
});
this.echo(new Date + ' ' + title);
}); //開始
casper.run();
crontab内容
PATH=$PATH:/usr/bin:/usr/local/bin
* * * * * /Users/kadosawa/bin/doruby >> /tmp/doruby.log.txt 2>&1
ポイント
crontab だと node や phantomjs や python やらのパスがなくてエラーになるのでPATH変数を設定してさしあげます。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
長いことsshコマンドの横着方法を検討しておりましたが「これでいいや」と思うことにしました。そこで使った小技を書きます。
linux を覚えたころ bashrc や bash_profile に alias xxx=’ssh -p 65522 -l loginu’ のようなことをしていました。.ssh/config を利用することで scp, rsync のときにオプションが落ちるという課題が解決されましたが、他のマシンに移動させるときや対象を増やすときの手数が少し多いことが課題でした。若干原始的ですが実行ファイルを作成する方法です。
環境
$ uname -mprsv
Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64 i386
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.4.0)
## 省略 ##
基礎:実行すると自身のファイル名を返すスクリプト
#!/bin/bash
basename $0
※ 適当な名前のファイルにして実行権限を与えておきます。
解説
$0 を呼び出すとコマンド名(ファイル名) が返されます。
パスも含まれる為 basename で脱がせます。ファイル名だけになります。
応用:ssh横着に役立てる
~/bin/localhost というパスのファイルを作成しました。
#!/bin/bash
timestamp=`date "+%y%m%d_%H%M%S"`$1
mkdir -p $HOME/sshlog
DST=`basename $0`
logfile="$HOME/sshlog/$USER.`uname -n`_to_$DST.$timestamp.log"
ssh $DST $* | tee $logfile
echo $logfile
所感
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
Googlebotでjavascriptが読み込める様になってきてはいますが、最新のjavascriptの機能には対応しておらず、chrome41で動いているようです(2018/7ではバージョン67)。そのためブラウザでは正常に表示されていてもgooglebotではエラーになり、javascriptが実行されない状態でキャッシュされてしまう可能性があるので注意です。ちなみにこのレンダリング機能のことをWebレンダリングサービス(WRS)と言うそうです。
chrome41のWRSでサポートされている機能、されていない機能は以下で確認できます。
●chrome41でサポートされている機能
https://www.chromestatus.com/features#milestone%3C%3D41
●chrome41でサポートされていない機能
https://www.chromestatus.com/features#milestone%3E41
個人的な感覚ではIEと同じような対応範囲です。逆にIEにjavascriptが対応していればgooglebotでも動くかなと思います。
また、googlebotはchrome41といってもブラウザの表示と全く同じではなく、
などの違いがあります。
このようにブラウザの表示と違いがあるため、googlebotがどのようにページを取得しているかちゃんと確認する必要があります。
search consoleの
・Fetch as Google
https://www.google.com/webmasters/tools/googlebot-fetch
・(スマホの場合)モバイルフレンドリーテスト
https://search.google.com/test/mobile-friendly
などで確認でき、エラーがあった場合もエラー内容が返却されるためわかりやすいです。
javascriptで画面を作成した後は、googlebotで正常に動くか確かめた方がよいかもしれません。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
今ならAWSの諸機能が、特定条件下なら1年無料で使えるとのことだったので、試しにRailsアプリをAWS上で作成・公開出来るようにしてみました。
以下のサイトなどを参考にしています。
(デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
【AWS】Ruby on Rails + Nginx + Unicorn + MySQL 環境構築
Cloud9とは、AWS上で利用できるクラウドIDEです。
AWSコンソールのCloud9から、環境を構築できます。
EC2インスタンスは、t2.microタイプであれば無料枠の範囲で利用できるので、こちらを選択します
構築が終わると、cloud9のコンソールが開きます。
rubyとrailsはインストールされているようなので、今回はこのままアプリを作成します。
$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
$ rails -v
Rails 5.2.0
# アプリの作成
$ rails new test-app
$ rails g scaffold user
# マイグレートとアセットプリコンパイル
$ rake db:migrate RAILS_ENV=production
$ rake assets:precompile
Gemファイルに追記してUnicornを使えるようにします。
# Gemfile 追記
group :production, :staging do
gem 'unicorn'
end
# インストール
$ bundle install
config配下に、unicornの設定ファイル(unicorn.rb)を作成・編集します。
# unicron.rb
# set lets
$worker = 2
$timeout = 30
$app_dir = "/home/ec2-user/environment/test-app/" #アプリの場所
$listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
$pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
# set config
worker_processes $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen $listen
pid $pid
# loading booster
preload_app true
# before starting processes
before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
Process.kill "QUIT", File.read(old_pid).to_i
rescue Errno::ENOENT, Errno::ESRCH
end
end
end
# after finishing processes
after_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
# Nginxの導入
$ sudo yum install nginx
-- 省略 --
Complete!
# 設定ファイルの書き換え
$ sudo vi /etc/nginx/nginx.conf
pid "/var/run/nginx.pid";
events {
worker_connections 2048;
}
http {
upstream unicorn {
server unix:/home/ec2-user/environment/test-app/tmp/sockets/.unicorn.sock;
}
server {
listen 80;
server_name XXX.XXX.XXX.XXX; ←EC2インスタンスに割り当てられたIP
root /home/ec2-user/environment/test-app/;
error_log /home/ec2-user/environment/test-app/log/nginx.log;
include /etc/nginx/mime.types;
location / {
if (-f $request_filename) { break; }
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
}
}
NginxとUnicornを起動して、webページが閲覧出来るか確認してみます。
# unicornの起動
$ bundle exec unicorn_rails -E production -c config/unicorn.rb -D
# 起動確認
$ ps aux | grep unicorn
#nginxの起動
$ sudo service nginx start
#起動確認
$ ps aux | grep nginx
起動後、EC2インスタンスのIPアドレスにアクセスしたところ無事繋がりました。
(なにもない簡素なページですが。。。)
AWSを利用して、railsで作成したアプリをweb公開できました。
NginxやUnicornについて理解がまだ浅いので、どんな設定が出来るのかなど理解を深めていきたいと思います。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
巨大なテーブル同士をjoinしてから検索すると遅くなるのでjoinせずに検索する方法を記述します。
Post ー* TagPost ー* Tag
|
*
Comment
# 投稿
class Post < ActiveRecord::Base
has_many :comments
has_many :post_tags
has_many :tags, though: :post_tags
end
# 中間テーブル
class PostTag< ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
# タグ
class Tag < ActiveRecord::Base
has_many :post_tags
has_many :posts, though: :post_tags
end
# コメント
class Comment < ActiveRecord::Base
belongs_to :post
end
上記の状態でコメントとタグのタイトルに「あ」という文字が入っている投稿を取得
したい場合はテーブルをjoinして検索すると思います。
Post.joins(:comments, :tags).where(['comments.title LIKE ? AND tags.title LIKE ?', '%あ%', '%あ%' ])
ですががレコード数がそれぞれ数十万件以上
だった場合とてもjoinしていられません。かなり遅くなるかと思います。そこで
# コメントのpost_id取得
comment_post_ids = Comment.where(['title LIKE ?', '%あ%']).pluck(:post_id)
# タグのid取得
tag_ids = Tag.where(['title LIKE ?', '%あ%']).pluck(:id)
# タグのpost_id取得
tag_post_ids = PostTag.where(tag_id: tag_ids).pluck(:post_ids)
# 取得したpost_idが一致しているものを取得
post_ids = comment_post_ids & tag_post_ids
# 投稿を検索!
posts = Post.where(id: post_ids)
ポイント
SQLを複数回実行しますが巨大なテーブル同士をjoinするよりは早くなることがあります。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
ActiveRecordのwhereの挙動が同じだったり違ったりするのでメモ
例として使うテーブル
# 投稿
class Post < ActiveRecord::Base
has_many :comments
end
# コメント
class Comment < ActiveRecord::Base
belongs_to :post
end
1.whereにhash
Post.where(title: 'タイトル').to_sql
SELECT posts.* FROM posts WHERE posts.name = 'タイトル' ORDER BY posts.id ASC
default_scopeがつく
2.whereにArray
Post.where(['title = ?', 'タイトル']).to_sql
SELECT posts.* FROM posts WHERE (name = 'タイトル') ORDER BY posts.id ASC
whereの条件にテーブル名がつかない。()がつく。
3.Arrayの部分にテーブル名を入れる
Post.where(['posts.title = ?', 'タイトル']).to_sql
SELECT posts.* FROM posts WHERE (posts.name = 'タイトル') ORDER BY posts.id ASC
テーブル名がつく。()がつく。
4.whereに空配列
Post.where([]).to_sql
SELECT posts.* FROM posts ORDER BY posts.id ASC
where条件なし。全件取得。default_scopeがつく。
5.whereに空配列
Post.where([[]]).to_sql
SELECT posts.* FROM posts WHERE () ORDER BY posts.id ASC
全件取得。where ()がつく。
6.whereにString
Post.where("posts.title = 'タイトル'").to_sql
SELECT posts.* FROM posts WHERE (posts.name = 'タイトル') ORDER BY posts.id ASC
Arrayのときとかわらない。
7.whereに空文字
Post.where('').to_sql
SELECT posts.* FROM posts ORDER BY posts.id ASC
where条件なし。全件取得。default_scopeがつく。
8.whereにtrue
Post.where(true).to_sql
RuntimeError: unsupported: TrueClass
例外。
9.whereに’true’
Post.where('true').to_sql
SELECT posts.* FROM posts WHERE (true) ORDER BY posts.id ASC
全件取得。
10.whereに’false’
Post.where('false').to_sql
SELECT posts.* FROM posts WHERE (false) ORDER BY posts.id ASC
0件。
11.joinしてwhereにhash
Post.joins(:comments).where(title: 'タイトル', comments: {title: 'コメントのタイトル'}).to_sql
SELECT posts.* FROM posts INNER JOIN comments ON comments.color_id = posts.id WHERE posts.title = 'タイトル' AND comments.title = 'コメントのタイトル' ORDER BY posts.id ASC
Postのdefault_scopeがつく。
12.joinしてmerge
Post.joins(:comments).where(title: 'タイトル').merge(Comment.where(title: 'コメントのタイトル')).to_sql
SELECT posts.* FROM posts INNER JOIN comments ON comments.color_id = posts.id WHERE posts.title = 'タイトル' AND comments.title = 'コメントのタイトル' ORDER BY posts.id ASC, comments.id ASC
PostとCommentのdefault_scopeつく。
AWS S3(以下、S3)に画像ファイルをアップロードした際、
AWS Lambda(以下、Lambda)で画像加工を行う、というのは
よく使われるケースの一つかと思います。
そこで、Lambda on Python 2.7でOpenCVライブラリを使用するための手順について、ご紹介したいと思います。
AWS Fargate(以下Fargate)は、
AWSが提供するコンテナ実行サービスであるElastic Container Service (以下ECS)のサービスの一種です。
バージニア北部のリージョンでのみ提供されていたサービスですが、
ついに、2018年07月東京リージョンでも提供が開始されました!!
既存のECSの仕組みが、ユーザが管理するEC2のクラスタの上でコンテナが起動されるのに対し、
FargateはEC2の管理をする必要がなく、コンテナが使用するvCPU、メモリを指定するだけでコンテナを実行できます。
冒頭でECSのサービスの一種です、という言い方をしましたが、
基本的には、ECSの仕組みと同じように動作します。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
セイバープラグイン、ライトセイバーのようなエフェクト他パチンコとかによくあるオーラ系の演出で使われるエフェクトが簡単に作れます
https://www.flashbackj.com/video_copilot/saber/
Color Vibrance、真っ白や真っ黒な画像でも色相や彩度を自在に補正かけることができます。
https://www.flashbackj.com/video_copilot/free_plugin/
サンプルとしてカグヅチさんに燃えていただきました
ざっくりですが手順としましては
1AfterEffectsにエフェクトつけたい画像を読み込む
2レイヤー→オートトレースでキャラとかエフェクトをつけたい物の型のパスを取る
3オートトレースしたレイヤーにエフェクトからセイバーを選択。今回はカグヅチなので火をベースにするためPresetはInfernoを元に適当に数値いじります(この辺は個人差あるので適当にいじってもらった方が楽しいかもです)
Customize Coreの項目にあるCore typeをLayer Maskにするとエフェクトがトレースしたパスに沿ってオーラをまとった感じになります
そのままだとリアルなエフェクトになるのでキャラの雰囲気に合わせて
ポスタリゼーション、ブラー(詳細)、カートゥーンのエフェクトを入れていい感じに調整したら
VC Color Vibranceで好みの色味に調整します。
これは別にサンプルなんで適当にざっくりやっちゃってますがもう少し細かく数値設定してあげればもう少し面白く仕上がるかなと思います。
ちなみにセイバープラグインはAfterEffectsの最新バージョンだと対応していないため要注意です
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
VirtualBox 上で CentOS や Ubuntu を起動させ、 Samba でファイル共有
sudo yum install -y samba
sudo chmod 755 /home/$USER
sudo smbpasswd -a $USER
sudo cp -a /etc/samba/smb.conf /etc/samba/smb.conf.org
sudo vi /etc/samba/smb.conf # 編集方法は以下参照
sudo /etc/rc.d/init.d/smb start
sudo /etc/rc.d/init.d/nmb start
sudo chkconfig smb on
sudo chkconfig nmb on
sudo setsebool -P samba_export_all_rw 1
sudo /etc/rc.d/init.d/iptables stop
sudo chkconfig iptables off
sudo chkconfig ip6tables off
58 ### START ###
59 unix charset = UTF-8
60 dos charset = CP932
61 display charset = UTF-8
62 ### END ###
79 ### START ###
80 # workgroup = MYGROUP
81 workgroup = WORKGROUP
82 ### END ###
89 ### START ###
90 hosts allow = 127.0.0.1 10. 172.16. 192.168.
91 ### END ###
232 ### START ###
233 # load printers = yes
234 load printers = no
235 disable spoolss = yes
236 ### END ###
267 ### START ###
268 create mask = 644
269 directory mask = 755
270 ### END ###
sudo yum install -y samba
sudo chmod 755 /home/$USER
sudo smbpasswd -a $USER
sudo cp -a /etc/samba/smb.conf /etc/samba/smb.conf.org
sudo cp /etc/samba/smb.conf.example /etc/samba/smb.conf
sudo vi /etc/samba/smb.conf # 編集方法は以下参照
sudo systemctl enable smb.service
sudo systemctl enable nmb.service
sudo systemctl restart smb.service
sudo systemctl restart nmb.service
sudo setsebool -P samba_export_all_rw 1
sudo systemctl stop firewalld
差分が以下のようになるよう修正する
[admin@localhost ~]$ diff -uprN /etc/samba/smb.conf.example /etc/samba/smb.conf
--- /etc/samba/smb.conf.example 2017-11-28 01:21:52.000000000 +0900
+++ /etc/samba/smb.conf 2018-05-02 20:50:00.157765018 +0900
@@ -60,6 +60,9 @@
#======================= Global Settings =====================================
[global]
+unix charset = UTF-8
+dos charset = CP932
+display charset = UTF-8
# ----------------------- Network-Related Options -------------------------
#
@@ -81,13 +84,13 @@
# hosts deny = the hosts not allowed to connect. This option can also be used on
# a per-share basis.
#
- workgroup = MYGROUP
+ workgroup = WORKGROUP
server string = Samba Server Version %v
; netbios name = MYSERVER
; interfaces = lo eth0 192.168.12.2/24 192.168.13.2/24
-; hosts allow = 127. 192.168.12. 192.168.13.
+ hosts allow = 127.0.0.1 10. 172.16. 192.168.
# --------------------------- Logging Options -----------------------------
#
@@ -244,7 +247,8 @@
# printcap name = used to specify an alternative printcap file.
#
- load printers = yes
+ load printers = no
+ disable spoolss = yes
cups options = raw
; printcap name = /etc/printcap
@@ -278,6 +282,8 @@
writable = yes
; valid users = %S
; valid users = MYDOMAIN\%S
+ create mask = 644
+ directory mask = 755
[printers]
comment = All Printers
sudo apt-get install -y samba
sudo pdbedit -a $USER
sudo cp -a /etc/samba/smb.conf /etc/samba/smb.conf.org
sudo vi /etc/samba/smb.conf # 以下参照
sudo systemctl restart smbd
sudo systemctl restart nmbd
差分が以下のようになるよう修正する
$ diff -uprN /etc/samba/smb.conf.org /etc/samba/smb.conf
--- /etc/samba/smb.conf.org 2018-05-02 18:16:25.567600455 +0900
+++ /etc/samba/smb.conf 2018-05-02 18:20:40.762445925 +0900
@@ -190,13 +190,13 @@
# Un-comment the following (and tweak the other settings below to suit)
# to enable the default home directory shares. This will share each
# user's home directory as \\server\username
-;[homes]
-; comment = Home Directories
-; browseable = no
+[homes]
+ comment = Home Directories
+ browseable = no
# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
-; read only = yes
+ read only = no
# File creation mask is set to 0700 for security reasons. If you want to
# create files with group=rw permissions, set next parameter to 0775.
@@ -211,7 +211,7 @@
# Un-comment the following parameter to make sure that only "username"
# can connect to \\server\username
# This might need tweaking when using external authentication schemes
-; valid users = %S
+ valid users = %S
# Un-comment the following and create the netlogon directory for Domain Logons
# (you need to configure Samba to act as a domain controller too.)
sudo ufw allow 137
sudo ufw allow 138
sudo ufw allow 139
sudo ufw allow 445
sudo ufw default ALLOW
sudo apt-get install -y cifs-utils
sudo mkdir /mnt/XXX
※「XXX」は任意
sudo mount.cifs //AAA.AAA.AAA.AAA/BBB /mnt/XXX/ -o username=BBB,uid=$(id -u),gid=$(id -g)
AAA : サーバIP
BBB : サーバ側のユーザ名
sudo umount /mnt/XXX
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
今年に入って花粉症を発症し、症状がひどくストレスに満ちた生活を送っているBe82Mです。
集中力が散漫になりがちで困っているので、今回軽減するために必要なことをまとめてみました。
どの病気にも言えることですが、睡眠をしっかりとって免疫力を高めることが大切です。
また、帰ってきたときに服を軽く叩くなど極力家に花粉を持ち込まないようにし、こまめに部屋の掃除を行いましょう。
外出した日は特に体に付着した花粉を洗い流すため、朝シャンは避けて寝る前に入る方がいいそうです。
外出の必要がない日は無闇に外出せず、花粉を必要以上に吸引しないように心がけましょう。
ストレスも免疫を低めてしまう原因になっているので、極力ストレスは趣味や適度な運動を行うことで発散するようにしましょう。
花粉症の症状がひどくなると、なかなか寝付けなかったり、普段の生活でも花粉症の症状だけで大きなストレスになってしまい、悪循環になってしまいます。
症状はすぐに軽減できないので、他のストレスとなる要因を絶ったり、どうしようもない場合は発散する時間を作るように心がけましょう。
アルコールは血管を拡張させるため、目の充血や鼻づまりを引き起こしてしまう要因となるようです。
また、粘膜を乾燥させてしまうため体内への花粉の侵入を防ぎにくくなってしまいます。
加湿器などを使って空気の乾燥を防ぐことで粘膜の乾燥も防ぐことは可能ですが、水分補給を行うなど内部からも水分を補うように心がけましょう。
煙が鼻の粘膜を刺激することで、鼻づまりなど症状を悪化させてしまうようです。
そのため喫煙者の近くにいるだけでも症状悪化の原因となってしまいます。
しかし、タバコに含まれるニコチンは血管を収縮させる作用があり、症状が軽減される要素も含んでいます。
粘膜の乾燥を防ぎ、煙によって症状を引き起こさないように対策しつつ、周囲に気を遣って喫煙をすれば特に問題はないかもしれません。
先々月に奥多摩町に遊びに行ったことを激しく後悔しています。とても楽しかったですが、あれから本当に症状がひどくなり、その後数日まで症状がひどい状態が続きました。
興味本位で1平方センチメートルあたりの花粉飛散量を調べましたが、23区内の平均が40〜50個なのに対し、奥多摩町は6000個を超えているそうです…。
確かに辺りは靄のようになっているし、1時間足らずで車が緑色になってしまうくらい目に見えて飛散量が違いました。
必要以上に対策したにも関わらず、目は真っ赤で涙がボロボロ出るし、くしゃみは止まらない…普段よりひどい症状に苦しめられる結果になりました。
景観はいいし、車やバイクで走るにもトレッキングにも最適。また、わらび餅が美味しいことで有名で魅力多い町ですが、花粉症を発症してしまったり、既に発症している人は症状悪化に繋がってしまいます。
観光に行こうと思っていた方は時期をずらして行くことをおすすめします。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢🍢
みなさーん! 快適Railsライフ送ってますかー!!?? 私は快適ではありません……。先日も訳の分からないエラーに引っかかって四苦八苦しました……。
メモ化という事柄に関してです。
メモ化って便利だよなー。マスタを一々データベースから参照せずに取ってこれるから高速に取ってこれるんだぜ!
使いやすいgemもあるし。
/app/models/oden_master.rb
class OdenMaster < ActiveRecord::Base
extend Memoist
class << self
def oden_data_memo(oden_code)
find_by(code: oden_code)
end
memoize :oden_data_memo
end
end
こんな感じにしちゃえば、同じ名前のおでんマスタは1度参照して来てしまえばキャッシュされるからもうSQLを呼ばずに取って来れる!
某日:
くらいあんと「おでん情報にユーザーの好みくっつけて送ってくれない?」
ぼく「わかりました!」
ぼく「うーん、どうしようかな。インスタンスに属性付けちゃえば楽だな」
/app/models/oden_master.rb
class OdenMaster < ActiveRecord::Base
extend Memoist
attr_accessor :preference_data
class << self
def oden_data_memo(oden_code)
find_by(code: oden_code)
end
memoize :oden_data_memo
end
def set_user_preference_data(user_data)
self.preference_data = user_data
end
end
で、コントローラはこんな感じにして、後はviewをいい感じに作れば完了!(結構簡略化してます)
app/controllers/oden_controller.rb
def current_oden
user = User.find_by(code: params[:user_code])
raise InvalidUser unless user
oden_code = params[:oden_code]
@oden_master = OdenMaster.oden_data_memo(oden_code)
raise InvalidOden unless oden_master
user_oden_data = user.oden_preferences.find_by(oden_code: oden_code)
@oden_master.set_user_preference_data(user_oden_data) if user_oden_data
end
end
テストも簡単に作って、通ったし問題無いな! メモ化して一度呼んできたマスタはもう取ってきてあるし、大丈夫!
コミットしてマージしてプッシュして開発環境にデプロイして(要するにクライアントが開発環境で試せる環境を作る)。
くらいあんと「大丈夫そうですね」
ぼく「お仕事完了!」
……しかしこのコードには致命的なミスがあるのがまだ、この時点では分からなかった。
数日後
てすたー「なんか別のユーザーのデータ入ってきてるよ」
ぼく「えっ」
ぼく「なんでだろう……。コンソール上で実際に動かしても何の問題も無いし……。うーん、うーん……」
てすたー「まだ、このおでんマスタに対するおでんデータ作ってないのに、入っちゃってるんだよね。それに私、こんなに辛子を大根に付けないんですよ」
ぼく「そうですか……。何でだろう。因みに私はたっぷり付けてゲホゲホ言いながら食べるのが好きです。」
てすたー「変態かよ。まあ、おでんデータ入れればちゃんと自分の入ってくるんだけど」
ぼく「むせる感覚が最高なんですよ。なんでこんな短いコードでそんな事が起きるんだろうなぁ……。調べてみます」
多分悩んだのは30分~1時間位だった。
問題は、memoizeをちゃんと読み込んでいなかった事にありました。
以下が、memoizeのソースになります。
def memoize(*method_names)
if method_names.last.is_a?(Hash)
identifier = method_names.pop[:identifier]
end
method_names.each do |method_name|
unmemoized_method = Memoist.unmemoized_method_for(method_name, identifier)
memoized_ivar = Memoist.memoized_ivar_for(method_name, identifier)
Memoist.memoist_eval(self) do
include InstanceMethods
if method_defined?(unmemoized_method)
warn "Already memoized #{method_name}"
return
end
alias_method unmemoized_method, method_name
if instance_method(method_name).arity == 0
# define a method like this;
# def mime_type(reload=true)
# skip_cache = reload || !instance_variable_defined?("@_memoized_mime_type")
# set_cache = skip_cache && !frozen?
#
# if skip_cache
# value = _unmemoized_mime_type
# else
# value = @_memoized_mime_type
# end
#
# if set_cache
# @_memoized_mime_type = value
# end
#
# value
# end
module_eval <<-EOS, __FILE__, __LINE__ + 1
def #{method_name}(reload = false)
skip_cache = reload || !instance_variable_defined?("#{memoized_ivar}")
set_cache = skip_cache && !frozen?
if skip_cache
value = #{unmemoized_method}
else
value = #{memoized_ivar}
end
if set_cache
#{memoized_ivar} = value
end
value
end
EOS
else
# define a method like this;
# def mime_type(*args)
# reload = Memoist.extract_reload!(method(:_unmemoized_mime_type), args)
#
# skip_cache = reload || !memoized_with_args?(:mime_type, args)
# set_cache = skip_cache && !frozen
#
# if skip_cache
# value = _unmemoized_mime_type(*args)
# else
# value = @_memoized_mime_type[args]
# end
#
# if set_cache
# @_memoized_mime_type ||= {}
# @_memoized_mime_type[args] = value
# end
#
# value
# end
module_eval <<-EOS, __FILE__, __LINE__ + 1
def #{method_name}(*args)
reload = Memoist.extract_reload!(method(#{unmemoized_method.inspect}), args)
skip_cache = reload || !(instance_variable_defined?(#{memoized_ivar.inspect}) && #{memoized_ivar} && #{memoized_ivar}.has_key?(args))
set_cache = skip_cache && !frozen?
if skip_cache
value = #{unmemoized_method}(*args)
else
value = #{memoized_ivar}[args]
end
if set_cache
#{memoized_ivar} ||= {}
#{memoized_ivar}[args] = value
end
value
end
EOS
end
if private_method_defined?(unmemoized_method)
private method_name
elsif protected_method_defined?(unmemoized_method)
protected method_name
end
end
end
# return a chainable method_name symbol if we can
method_names.length == 1 ? method_names.first : method_names
end
まあ、コードの解説は抜きにして、端的に言えば、メモ化で参照されるデータは単一のものである、という事です。
その単一のものに対して破壊的変更をしてしまえば、そのメモ化で参照されるデータにも勿論影響が及びます。
上記のコードだと、
ユーザーA: おでんコードXに対するユーザーデータを持つ ユーザーB: おでんコードXに対するユーザーデータは持たない
と言う条件の下で、
1. ユーザーAがおでんコードXに対する情報を取得 メモ化されたおでんコードXのマスタの属性にデータが入る。 2. ユーザーBがおでんコードXに対する情報を取得 メモ化されたおでんコードXのマスタの属性はユーザーAのものが入ったままデータが送られてしまう。
と言う事が起きてしまう訳です。カラムに変更を掛けてしまっても同じ事が起こります。
まあ、策としては色々あります。
・メモ化して取ってきてくる時に属性を初期化する
・データが無くてもnilなどを明示的に入れる
・属性を使わない。メモ化したデータを弄る事をそもそもしないように心掛ける
等々。
自分は一番上の、メモ化して取ってきてくる時に属性を初期化する、を選びました。下のような感じにメソッドを作ったりしてそれを取ってくるようにして。
def attr_initialized_oden_data_memo(oden_code)
oden_data = oden_data_memo(oden_code)
oden_data.preference_data = nil
oden_data
end
理由としては、まあ実装上の設計の問題みたいな感じですが。
そこ辺りは設計と相談にもなってきます。
それではより良いおでんライフを。
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
Unityのシェーダーについて自分で調べたことをまとめました。
どうもmotsuka です。
今回はシェーダーを書いてみたくなったのでいろいろと調べてみたことをまとめてみたいと思います。
シェーダーとはシェーディング処理(陰影処理)を行うプログラムのことで、オブジェクトの頂点や色を変えるプログラムのことを指します。ポリゴンやテクスチャ等の画像をどのように画面に表示するかを決めるプログラムです。
またUnityでは3つのシェーダーがあり、
Unityでシェーダーを書くときこれらを使い分けて書く必要があります。
これらを簡単に説明すると
これらUnityで動くすべてのシェーダーでShaderLabという書式で書かれます。
これらの項目はまとめにURLが書いてあるので詳しく読みたい方はそちらをご覧ください。
では、簡単なシェーダーを書いてみましょう
今回は簡単な例として画面上に置かれた立方体の色を変えるプログラムを書いていきたいと思います。
まず、プロジェクト内で右クリックをして Create -> Shader -> Standard Surface Shaderをクリックしてシェーダーを作ります。
それをテキストエディタで開いてみましょう。
Shader "Custom/Test" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse" }
上のようなソースができたと思います。
上から読んでいきましょう
大きく分けて二つの枠に分けることができます。
ではこのソースを変えてこのシェーダーがついているオブジェクトの色を変えましょう。
_Color (“Color”, Color) = (1,1,1,1)
の行を下のように書き換えます。
_Color (“Color”, Color) = (1,0,0,1)
に変えて保存したシェーダーからマテリアルをつくって適当なオブジェクトにアタッチしてみてください。
そうすると色が赤色に変わったことが確認できます。
書いたことがなかったシェーダーですが、やってみるとあまり難しくなくさっくりとできる印象ですので皆さんもやってみてはいかがでしょうか?ですが、C#とは全く違う書き方や最初はよくわからないパラメータが多く出てくるので最初はきついかもしれませんが、慣れるとすんなり読めるようになるので皆さんもシェーダーを書いてみましょう。
次は文字のアウトラインをシェーダーで書いてみたいですね。余裕があったらまた書きたいと思います。
参考にしたURLを下にのせておくのでそこから読んでもらうと理解がより深まると思います。
Unity Documentation シェーダーマニュアル
https://docs.unity3d.com/ja/current/Manual/ShadersOverview.html
Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた
http://tips.hecomi.com/entry/2014/03/16/233943
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
アニメやゲーム等、どこかで聞いたことありそうな物理学ワードを、生まれた背景や意味などを添えて集めてみました。意味が分かることで、より世界観を楽しめるようになるのではないでしょうか。
恐らくこの記事で最も有名な物理学ワードです。
これは、量子力学という分野において、粒子の状態が1つに決まらないことを元にしたパラドックスになります。
日常的に考えると、物事の状態は必ず一つに決まっていきます。(コインを投げれば表か裏かのどちらかに決まる、など)
しかし、量子力学の世界では、小さな粒子は複数の状態の重ね合わせで表現され、人間が観測するまで状態が決まりません。これが日常的認識と大きく違っているために、この量子力学を批判する次のような逸話が生まれました。
「Aの状態とBの状態の重ね合わせで表現される粒子があり、Aの状態になると毒ガスが出る箱を作って、猫を閉じ込める。
すると、箱を開けて観測するまで、粒子はAとBの重ね合わせなので、猫もまた生きている状態と死んでいる状態の重ね合わせになってしまう。」
※これは思考実験であり、実際に猫が犠牲にされた実験ではありません。
これがシュレディンガーの猫と言われるパラドックスです。
猫の生きている状態と死んでいる状態との重ね合わせという、日常的にあり得ないことが起こってしまう、と批判している文言なのですが、非常に小さい粒子の状態を、猫という大きなものへ影響させるということは、現代の技術でも発展途上のため、この話の真偽はまだ分かりません。
これも量子力学の分野の話です。
ディラックという有名な物理学者が、量子力学の世界での粒子の状態を表す式を導き出しました。しかし、この式ではエネルギーがいくらでもマイナスの状態である粒子が存在しても良いことが分かりました。粒子の性質として、エネルギーが小さい方へ行く性質があるので、これでは実在する全ての粒子がマイナス状態へ落ちていってしまう、と懸念されました。
これを説明するために、「マイナスの状態はすでに粒子が満員状態になっている」という概念を提唱しました。
これがディラックの海と呼ばれるものです。これらは、のちに別の理論によって解決され、ディラックの海は不要となってしまいました。
これは単純に物理学用語です。
エントロピーは物事の状態の「散らかり具合」を示す量で、物理学だけでなく、情報理論にも用いられている概念です。
このエントロピーは増える方向(散らかっていく方向)にしか動かない性質があり、エントロピー増大の法則と言われます。
(局所的にはエントロピーは減少することもあり得ます。しかし、全体で見れば増加しています)
これは物理学だけでなく情報理論にも関わるお話です。
空気の温度は、空気中の分子の温度の高いモノと低いモノの平均で出来上がっています。そこで、マクスウェルという物理学者は次のような思考実験を考えました。
「仕切りで2つの部屋に分けた箱を用意し、温度の高いモノを右の部屋へ、低いモノを左の部屋へ移すことが出来れば、何も特別なこと(「仕事」と言います)をする必要もなしに部屋の温度を上げたり下げたりできるのではないか。」
この思考実験は、上述のエントロピー増大則に反するため、注目を浴びました。
文中の、「熱い分子と冷たい分子を見分ける存在」が、のちにマクスウェルの悪魔と呼ばれるようになりました。
この問題の解決には、物理学だけでなく情報理論の助けも必要でした。
この見分けている悪魔が、何の仕事もしていないように見えて実は仕事をしていたのです。この悪魔は粒子状態の情報を取得し、次の粒子を観測するために、前の情報を消去する必要があり、この過程で仕事をしていることが分かったため、結論として熱力学の法則と矛盾しない、ということが分かりました。
物理学というよりは少し哲学的なお話です。
止まっている物Bに、物Aがぶつかって物Bを吹き飛ばしたとします。この時、物Aと物Bの重さ等の性質が分かっていれば、物Bがどのぐらいの速さで吹き飛んでいったのか計算することが出来ます。
つまり、物同士がぶつかる前からその先の未来を予言できてしまうわけです。
これの究極的な主張として、
「現在の、この世の全ての物の状態が分かってしまえば、この先の未来全ての状態が分かってしまうだろう。また、逆に現在より過去の全ての状態も分かってしまうだろう。」
ということを数学者ラプラスが主張しました。のちに、この世全ての状態を知っている存在が、「ラプラスの悪魔」と呼ばれるようになりました。
これは、この世のすべての出来事は決まっていることなのだ、という決定論的な考えにも見ることが出来ます。
現代では非常に小さい粒子の挙動は確率で記述されるため、起こるまで分からないという見方がされています。
一方で、確率変動で世界が分からないのではなく、粒子が取り得る状態の数だけ世界が分岐しているという見方もされています(エヴェレットの多世界解釈)。
いかがでしたでしょうか。結構聞いたことがある言葉が多かったのではないでしょうか。
これで今後の創作物にこのようなワードが出てきた時も、にやにやしながら世界に浸ることが出来ますね。