- 投稿日:2020-02-12T23:58:16+09:00
docker exec & pecoが思いの外捗る
dockerを使いはじめて2年くらいなのですが、今までコンテナに入るまでこんなことをしていました。
y-nishi@yutaroon: laravel-docker-template [master] » docker ps [23:44:39] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0fd143ed3db0 laravel-docker-template_nginx "nginx -g 'daemon of…" 10 seconds ago Up 10 seconds 0.0.0.0:3333->80/tcp nginx 286b79e909a4 laravel-docker-template_php "docker-php-entrypoi…" 11 seconds ago Up 10 seconds 9000/tcp php cef83b6bb200 laravel-docker-template_mysql "docker-entrypoint.s…" 11 seconds ago Up 10 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql y-nishi@yutaroon: laravel-docker-template [master] » docker exec -it 286b79e909a4 sh [23:44:52] # echo 'mendokuseeee' mendokuseeee #コンテナIDを調べたりコマンド打ったりとてもめんどうです。
僕の場合、
dexec
というエイリアスを登録して、これを叩くことでコンテナ選択に遷移するようにしています、コンテナIDを意識せずに、コンテナ名を直感的に指定できるのでとても良いです。
コンテナがたくさん立ち上がっている環境だと一層操作しやすくなるのではないでしょうか。やり方
僕はfishを使っているので、
~/.config/fish/config.fish
に下記を追記します。
bashの人は~/.bashrc
によしなに登録してください。alias dps='docker ps --format "{{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Command}}\t{{.RunningFor}}"' alias dexec='docker exec -it (dps | peco | cut -f 1) sh'
- 投稿日:2020-02-12T23:43:36+09:00
dockerのPHPでxdebugを使ってみる
概要
xdebugをdocker環境で使えるようにしたかったので調べてみた。
Dockerを準備する
作ったコードは、下記githubにまとめているので大雑把に書きます。
※ Github: https://github.com/reflet/php5.6-xdebugdocker/httpd/DockerfileFROM php:5.6-apache # install xdebug RUN pecl install xdebug-2.5.5 && docker-php-ext-enable xdebug # update php.ini COPY ./php.ini /usr/local/etc/php/php.ini WORKDIR /var/www/htmlphp.iniの設定
下記の設定を追加する。
docker/httpd/php.ini[xdebug] xdebug.idekey="PHPStorm" xdebug.remote_host = "docker.for.mac.host.internal" xdebug.default_enable = 1 xdebug.remote_autostart = 1 xdebug.remote_connect_back = 0 xdebug.remote_enable = 1 xdebug.remote_handler = "dbgp" xdebug.remote_port = 9000docker-compose.yml
dockerの構成を記述します。
docker-compose.ymlversion: "3.7" services: httpd: container_name: httpd image: httpd:development build: context: ./docker/httpd dockerfile: Dockerfile ports: - "80:80" volumes: - ./src:/var/wwwサーバ起動
下記コマンドでサーバを起動します。
ターミナル$ docker-compose build $ docker-compose up -dIDE設定 (IntelliJ)
お使いのIDEで9000番ポートを指定する。
以上
参考サイト
- 投稿日:2020-02-12T18:23:19+09:00
docker-composeで開発/本番環境を切り替える
docker-composeで簡単に環境を切り替えたい
webアプリの開発でサーバーやDBを同時に立ち上げるためにdocker-composeを使用していて
テストや動作確認もコンテナ上で起動してやる場合、webアプリを動かすコンテナとして
- 「production環境」 最小限のパッケージとモジュールを入れて余分なキャッシュ等も消し、できるだけイメージサイズを小さくしたもの
- 「development環境」 テスト関連やgit、分析ツール等の開発に必要なものが入ったやや大きいサイズのイメージのもの
というふうに2種類以上の環境を使い分けたくなりますが、これをどう切り替えたらいいかという話
色々やり方は考えられますがdoker-compose内で展開できる環境ファイルの
.env
ファイルを使うのがよさそうです。この記事ではRailsアプリでnginxとMySQLを使用しdocker-composeはversion:3以上を使うのを想定してますが、他のケースでも応用できると思います。
.envをdocker-composeに展開する
.envファイルをdocker-compose.ymlと同じ階層に用意するとdocker-compose内で変数として展開できます。
これを利用するとbuildするDockerfileのファイル名も変数で切り替えることができます。docker.compose.yml
version: '3.7' services: nginx: build: containers/nginx volumes: - public:/myapp/public - sockets:/myapp/tmp/sockets/ ports: - '8080:80' depends_on: - rails rails: build: context: . dockerfile: Dockerfile_${DOCKER_RAILS_ENV} image: webapp_${DOCKER_RAILS_ENV} volumes: - .:/myapp - public:/myapp/public - sockets:/myapp/tmp/sockets/ ports: - "3000:3000" links: - db environment: RAILS_ENV: $DOCKER_RAILS_ENV DB_HOST: db DB_USERNAME: $DB_USERNAME DB_PASSWORD: $DB_PASSWORD RAILS_SERVE_STATIC_FILES: db: image: mysql:5.7 volumes: - mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: $DB_PASSWORD MYSQL_DATABASE: root ports: - "3306:3306" volumes: mysql-data: public: sockets:.env
DOCKER_RAILS_ENV=production DB_USERNAME=root DB_PASSWORD=passworddocker-compose.ymlの
dockerfile: "Dockerfile_${DOCKER_RAILS_ENV}"
の部分で
production環境用に作ったDocker_production
というファイルとDocker_development
というファイルを.envで定義した環境変数で指定し切り替えています。1
またbuild:の下のimage:webapp_${DOCKER_RAILS_ENV}
でビルドされるイメージ名を指定しています。2
ちなみに${DOCKER_RAILS_ENV:-development}
とすればデファルト値でdevelopmentになります
イメージ名にも同じことができるので必要であればimage: mysql:${DB_VER-5.7}
としてバージョンの指定なんかもできます。
参考:案外知られてないdocker-composeの環境変数定義の記法注意点
ホストマシンのLinux等に.envで指定した変数と同名の環境変数が設定されてる場合、ホストマシンの環境変数が優先されるので、意図的に使いたい場合を除いて名前がバッティングしないようにする必要があります。
今回の例だとRAILS_ENVは使われやすいので、DOCKER_RAILS_ENVとしてかぶらないようにしてます。またデフォルトで.gitignoreや.dockerignoreに.envは入ってないので間違ってもAWSへの接続情報などのクレデンシャルを.envに記述してgithubやdockerhub等にアップロードしないように注意しましょう。
Dockerfileは複数必要か
結局この方法だとdocker-composeは1つで済みますがDockerfileの方は2種類以上必要になります。
これも一つにできないかと考えたのですが、複雑になるのでやめました。3
アプリのルートをどうしてもDockerfile一つにしたい場合は、片方のDockerfileを配下に別のディレクトリを作って入れてdocker-composeのcontext:
の部分を切り替えるようにすればいいと思います。
- 投稿日:2020-02-12T18:23:19+09:00
docker-composeで.envで開発/本番環境を切り替える
docker-composeで簡単に環境を切り替えたい
webアプリの開発でサーバーやDBを同時に立ち上げるためにdocker-composeを使用していて
テストや動作確認もコンテナ上で起動してやる場合、webアプリを動かすコンテナとして
- 「production環境」 alpineをベースに最小限のパッケージとモジュールを入れて余分なキャッシュ等も消し、できるだけイメージサイズを小さくしたもの
- 「development環境」 テスト関連やgit、分析ツール等の開発に必要なものが入ったやや大きいサイズのイメージのもの
のように2種類以上の環境を使い分けたくなりますが、これをどう切り替えたらいいかという話
単純にdocker-compose.ymlを複数作って -f でファイル名を指定する方法や
公式ドキュメントにあるように拡張用のcomposeファイルを作る方法もありますが、doker-compose内で展開できる環境ファイルの.env
ファイルを使用して切り替えるのが色々と応用がきくのでお薦めです。作りたい環境に合わせたDockerfileを用意する
まず環境に合わせたDockerfileを用意します。
例えば
- 「Docker_production」
- 「Docker_development」
という感じに分けます。
.envを用意しdocker-composeに変数を指定する
.envファイルをdocker-compose.ymlと同じ階層に用意するとdocker-compose内で変数のように展開できます。
これを利用するとbuildするDockerfileのファイル名も変数で切り替えることができます。
以下はRailsを想定してますが、他のケースでも応用できると思います。docker.compose.yml
version: '3.7' ~ 省略 ~ rails: build: context: . dockerfile: Dockerfile_${DOCKER_RAILS_ENV} image: webapp_${DOCKER_RAILS_ENV} volumes: - .:/myapp - public:/myapp/public - sockets:/myapp/tmp/sockets/ ports: - "3000:3000" links: - db environment: RAILS_ENV: $DOCKER_RAILS_ENV DB_HOST: db DB_USERNAME: $DB_USERNAME DB_PASSWORD: $DB_PASSWORD RAILS_SERVE_STATIC_FILES: ~ 省略~.env
DOCKER_RAILS_ENV=production DB_USERNAME=root DB_PASSWORD=passwordbuildするDockerfile名に.envに書かれた環境変数を利用する
docker-compose.ymlの
dockerfile: "Dockerfile_${DOCKER_RAILS_ENV}"
の部分で
production環境用に作ったDocker_production
というファイルとDocker_development
というファイルを.envで定義した環境変数で指定し切り替えています。1
.envをDOCKER_RAILS_ENV=development
とすればdevelopment環境でupができます。作成されるイメージ名を指定する
デフォルトでは"ディレクトリの名前"_"指定したコンテナ名(rails)"になるので環境を変えても同じイメージ名がつきます。
build:の下にimage:を指定するとイメージ名を指定してビルドできます。
->https://docs.docker.com/compose/compose-file/#build
image:webapp_${DOCKER_RAILS_ENV}
でビルドされるイメージ名も環境で変わるようにしています。2ちなみに
${DOCKER_RAILS_ENV:-development}
とすれば変数が指定されていない場合のデファルト値がdevelopmentになります
必要であれば使用するDBのイメージ名でimage: mysql:${DB_VER-5.7}
として公式イメージのバージョンの指定にも応用できます。
参考:案外知られてないdocker-composeの環境変数定義の記法注意点
ホストマシンのLinux等に.envで指定した変数と同名の環境変数が設定されてる場合、ホストマシンの環境変数が優先されるので、意図的に使いたい場合を除いて名前がバッティングしないようにする必要があります。
今回の例だとRAILS_ENVは使われやすいので、DOCKER_RAILS_ENVとしてかぶらないようにしてます。またデフォルトで.gitignoreや.dockerignoreに.envは入ってないので間違ってもAWSのキーなどのクレデンシャルを.envに記述してgithubやdockerhub等にアップロードしないように注意しましょう。
Dockerfileは複数必要か
結局この方法だとdocker-composeは1つで済みますがDockerfileの方は2種類以上必要になります。
これも一つにできないかと考えたのですが、複雑になるのでやめました。3アプリのルートをどうしてもDockerfile一つにしたい場合は、片方のDockerfileを配下に別のディレクトリを作って入れてdocker-composeの
context:
の部分を切り替えるようにすればいいと思います。
- 投稿日:2020-02-12T16:34:24+09:00
SEしてるけど実はあんまりコード書いたことないんだよねって人に捧ぐ、Rails on Dockerハンズオン vol.7 - Secure password -
はじめに
第7回目となる今回は、モデルにセキュアなパスワードをもたらしてくれる
has_secure_password
メソッドの使い方を紹介していきます。
パスワードは他人に知られてはまずいものです。万が一、データを抜かれたり画面に表示されちゃったりしても一目でわからないようになっていることが望ましいですね。そんなことを実現してくれるメソッドがhas_secure_password
です。
has_secure_password
Railsでは、モデルにセキュアなパスワード属性を実装するメソッドとして、
has_secure_password
が用意されています。モデルに対してhas_secure_password
を適用することでモデルは以下の恩恵を受けることができます。
- 仮想属性として
password
とpassword_confirmation
を利用可能password
とpassword_confirmation
の同一性について勝手に検証してくれる- DBにはハッシュ化した
password_digest
を保存するようになる- ハッシュ値でパスワード検証をする
authenticate
メソッドを利用可能ハッシュ化についてちょっとお話ししておきます。ハッシュ化はある文字列を不可逆な別の文字列に変換してくれます。『不可逆』とは元に戻せないという意味です。
『暗号化』の場合は『復号化』することで元の文字列に変換しなおせるんです。これは『可逆』といいますね。では、早速モデルに
has_secure_password
メソッドを適用していきます。
has_secure_password
ではハッシュ化を行うためにbcrypt
gemを利用します。まずは、bcrypt
のインストールからやっていきます。Gemfile
の中身をみるとわかりますが、bcrypt
は最初からGemfile
の中に書かれておりコメントアウトされているだけです。なのでコメントアウトをとってdocker-compose build
をするだけでOKです。Gemfile... gem 'bcrypt', '~> 3.1.7' ...$ docker-compose build $ docker-compose up -dコンテナも立ち上げておきましょう。
次に、
has_secure_password
メソッドを使うようになるとpassword
をハッシュ化した値をpassword_digest
カラムにDB保存するようになります。マイグレーションファイルを作成しDBにpassword_digest
カラムを追加しておきます。# rails g migration add_password_digest_column_to_user password_digest:string Running via Spring preloader in process 251 invoke active_record create db/migrate/20200130075100_add_password_digest_column_to_user.rb # rails db:migrate == 20200130075100 AddPasswordDigestColumnToUser: migrating ==================== -- add_column(:users, :password_digest, :string) -> 0.0522s == 20200130075100 AddPasswordDigestColumnToUser: migrated (0.0533s) ===========そして、Userモデルにhas_secure_passwordメソッドを適用します。
app/models/user.rbclass User < ApplicationRecord ... has_secure_password ... endこれで完了です!簡単ですね!
では恩恵がちゃんと受けられているか確認してみましょう。
password
とpassword_confirmation
まずは
password
属性とpassword_confirmation
属性の二つの仮想属性が利用できることを確認してみます。> user = User.new(name: "hanako", email: "hanako@sample.com", password: "password", password_confirmation: "password") => #<User:0x0000563d32829928 id: nil, name: "hanako", email: "hanako@sample.com", created_at: nil, updated_at: nil, password_digest: [FILTERED]> > user.password => "password" > user.password_confirmation => "password" > user.password_digest => "$2a$12$OfB2RwhC2b2hHW.8bIpNqeEoqM9xS3OdLubSUS4Gew0Ece1dnTzDG"DBカラム的に
password_digest
しかないはずですが、password
、password_confirmation
が使えていることがわかります。さらにその結果がpassword_digest
として利用可能なのもわかりますね。
password
とpassword_confirmation
の一致性確認ここで一度
valid?
メソッドを使ってみましょう。これは今現在のモデルでvalidationを突破できるのかを確認できるメソッドです。先ほどまではsave
でvalidationできるかを確認していましたが、実はvalidationを調べるためだけであればこれでOK。> user.valid? User Exists? (3.6ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => true今は
password
とpassword_confirmation
がマッチしているのでvalidationは通っているようです。では、password_confirmation
を別の文字列に変更した場合どうでしょうか?> user.password = "password1" => "password1" > user.valid? User Exists? (35.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => false > user.errors.full_messages => ["Password confirmationとPasswordの入力が一致しません"]validationでエラーになっていることがわかりましたね...あ、日本語化していない。
日本語化しましょう!config/locales/ja.ymlja: activerecord: attributes: user: name: "お名前" email: "メールアドレス" password: "パスワード" password_confirmation: "確認用パスワード" ...> reload! Reloading... => true > user.valid? User Exists? (4.7ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => false > user.errors.full_messages => ["確認用パスワードとパスワードの入力が一致しません"]
password
とpassword_confirmation
が一致していない場合はエラーが起きていますね。
ただ、password_confirmation
のようなものは必要なのか?という論争もあると思います。
「登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK」
例えばこちらの記事では、確認用パスワードを用意するのではなく、パスワードの欄のマスクを外せるようにした方がコンバージョンが上がると述べられていたりします。
has_secure_password
では、password_confirmation
がnil
の場合、password
とpassword_confirmation
の一致を確認しません。> user.password_confirmation = nil => nil > user.valid? User Exists? (2.4ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => trueなので確認用パスワードを使う使わないによらず、
has_secure_password
メソッドは強力なのです。DBではハッシュ化された
password_digest
が使われる最初にもお話しした通り、ハッシュ化は不可逆なデータ変換です。
has_secure_password
ではpassword_digest
にハッシュ化されたpassword
を保存します。それを確認してみましょう!実際にUserを作成してみましょう。
> user.save (0.4ms) BEGIN User Exists? (2.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] User Create (69.4ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "hanako"], ["email", "hanako@sample.com"], ["created_at", "2020-01-31 20:35:57.284982"], ["updated_at", "2020-01-31 20:35:57.284982"], ["password_digest", "$2a$12$OfB2RwhC2b2hHW.8bIpNqeEoqM9xS3OdLubSUS4Gew0Ece1dnTzDG"]] (5.6ms) COMMIT => true > user.find(1) => #<User:0x0000563d32823898 id: 1, name: "hanako", email: "hanako@sample.com", created_at: Fri, 31 Jan 2020 20:35:57 JST +09:00, updated_at: Fri, 31 Jan 2020 20:35:57 JST +09:00, password_digest: [FILTERED]> > user.password => nil > user.password_digest => "$2a$12$OfB2RwhC2b2hHW.8bIpNqeEoqM9xS3OdLubSUS4Gew0Ece1dnTzDG"
user.password_digest
をみてもなんのことやらわかりませんね。ちょっと安心です。パスワード認証する
authenticate
メソッドさて、ハッシュ化されてセキュアになったのはいいのですが、不可逆なのでこのままではパスワードで認証ができません。
has_secure_password
ではハッシュ化されたパスワードの認証をするためのauthenticate
メソッドが用意されています。これは、password_digest
の値と入力したpassword
を同じハッシュ関数でハッシュ化した値の一致をチェックしてくれるものです。> User.find_by(email: "hanako@sample.com").authenticate("a") User Load (4.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => false > User.find_by(email: "hanako@sample.com").authenticate("password") User Load (2.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "hanako@sample.com"], ["LIMIT", 1]] => #<User:0x0000563d32d80688 id: 1, name: "hanako", email: "hanako@sample.com", created_at: Fri, 31 Jan 2020 20:35:57 JST +09:00, updated_at: Fri, 31 Jan 2020 20:35:57 JST +09:00, password_digest: [FILTERED]>このように
find_by
と組み合わせて使えばメールアドレスとパスワードの2key認証を実装できます。authenticate
は不一致の場合はfalse
を、一致の場合はモデルオブジェクトを返却します。
password
にvalidationを設ける仮想属性である
password
に対してもvalidationをつけることができます。
一方で、has_secure_password
で作られたpassword
にはデフォルトでpresence
のvalidationが設定されています。これに加えて6文字以上でないといけない文字数制限をつけてみましょう。
デフォルトでpresence
がついてはいるのですが、入力がない場合にpresence
とlength
の両方に引っかかってしまうのでpresence
については適用しない方がわかりやすいでしょう。
has_secure_password
にvalidations: false
オプションをつけてデフォルトのpresence
validationを向こうにした後に、他の属性と同様にlength
のvalidationをつけてみましょう。app/models/user.rbclass User < ApplicationRecord ... has_secure_password validations: false ... validates :password, length: { minimum: 6 } ... end
password
のvalidationについて試してみましょう。> user = User.new(name: "john", email: "john@sample.com") => #<User:0x0000563d32287768 id: nil, name: "john", email: "john@sample.com", created_at: nil, updated_at: nil, password_digest: nil> > user.valid? User Exists? (4.9ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "john@sample.com"], ["LIMIT", 1]] => false > user.errors.full_messages => ["パスワードは6文字以上で入力してください"] > user.password = "a" * 5 => "aaaaa" > user.valid? User Exists? (4.8ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "john@sample.com"], ["LIMIT", 1]] => false > user.errors.full_messages => ["パスワードは6文字以上で入力してください"] > user.password = "a" * 6 => "aaaaaa" > user.valid? User Exists? (3.5ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "john@sample.com"], ["LIMIT", 1]] => trueということで、
password
のlength
validationが正しく挙動していることがわかりました。Userを作成
最後にこのバリデーションの中でちゃんとUserを作成できることを確認しておきましょう!
> User.create(name: "John Smith", email: "john@sample.com", password: "password") (1.9ms) BEGIN User Exists? (7.4ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2 [["email", "john@sample.com"], ["LIMIT", 1]] User Create (30.2ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "John Smith"], ["email", "john@sample.com"], ["created_at", "2020-02-09 16:40:36.252829"], ["updated_at", "2020-02-09 16:40:36.252829"], ["password_digest", "$2a$12$JHC/AEBGXyffzL9..2ThOuxDRlRCSP2RxtFxZxDzeOfsQIX6BGqym"]] (3.0ms) COMMIT => #<User:0x000055f6f7e390b0 id: 2, name: "John Smith", email: "john@sample.com", created_at: Sun, 09 Feb 2020 16:40:36 JST +09:00, updated_at: Sun, 09 Feb 2020 16:40:36 JST +09:00, password_digest: [FILTERED]>validationにひっかからないUserであればちゃんと作成できることが確認できましたね!
ユーザー情報を確認するViewを作ってみる
ここまででUserモデルがほぼ完成しました。この情報をUIで見れるようにViewを作ってみましょう!
Scaffoldを思い出してください。ユーザーの詳細情報を見るためのページは
/users/:id
のURLにアクセスして閲覧することができ、show
アクションにルーティングされていました。今回もそれにそってユーザーのページを作っていきます。
ユーザー詳細ページを作成する
ユーザー詳細ページは、
/users/:id
のパスにアクセスした時に、そのid
のユーザーの詳細情報が表示されるページにしたいと思います。
この通りになるように、ファイルの編集や作成を行っていきます。いままでrails g ~
コマンドでファイルを作成してきましたが、Railsの規則に則っていれば普通にファイルを作成しても動きます。Routing
まずは、
/users/:id
のルーティングを生成します。以前、Scaffoldの時にresources
メソッドを使ってUsersコントローラーに対するルーティングを定義しました。/users/:id
はその時のshow
アクションへのルーティングと同じです。
resources
メソッドはonly
オプションをつけることで特定のアクションへのルーティングのみを定義してくれます。今回はこのオプションを使ってルーティングを定義します。config/routes.rbRails.application.routes.draw do root 'static_pages#home' resources :users, only: [:show] endこれでルーティングの設定は完了です。試しに
rails routes
コマンドでルーティングを確認してみてもいいかもしれません。# rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home user GET /users/:id users#show ...確かに
GET /users/:id
がusers#show
にルーティングされています。Controller
次にUsersコントローラーを作成していきます。コントローラーは複数形の名称にするのがルールです。
# touch app/controllers/users_controller.rbapp/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) end end
users
コントローラにshow
アクションがある、というところまでは今までの内容からわかりますね。
show
アクションの中身をみてみます。
params[:id]
は/users/:id
のパスパラメータの:id
を取得しています。例えば/users/1
にアクセスした場合はparams[:id]=1
だし、users/2
にアクセスした場合はparams[:id]=2
です。
User.find()
はModel CRUDの回で話した通り、id
でUserのモデルオブジェクトを取得するメソッドなので、パスのid
のユーザーがこれで取得できるわけです。
あとはViewに引き渡すためにこれをインスタンス変数@user
に代入しています。ではこれを受け取るViewを作っていきます。
View
まず、Viewファイルを格納するディレクトリを作成して、その中に
show.html.erb
ファイルを作ります。
UsersコントローラのためのViewなのでapp/views/users/
ディレクトリ内にファイルを作成していきます。# mkdir app/views/users # touch app/views/users/show.html.erb最初は情報が表示されていればOKとしましょう。特にUIは拘らない。
app/views/users/show.html.erb<div class="container my-5"> <%= @user.name %> <br> <%= @user.email %> </div>
name
と
http://localhost:3000/users/2
にアクセスしてみましょう。
こんなページが表示されていれば成功です!
(id
は実際にDBに格納されているデータ次第ですので、Rails consoleでUser.all
を打つなどして存在するUserのid
を確認してみてくださいね。)後片付け
次回に向けてデータを消します。
$ docker-compose down $ docker-compose run --rm web rails db:migrate:resetDBコンテナが立ち上がった状態だと思うのでdownさせます。
$ docker-compose downまとめ
今回は、
has_secure_password
メソッドを使ってセキュアなパスワードが利用できるようになりました。
コード的にいえばたった1行has_secure_password
を付け加えるだけでパスワードをハッシュ化してセキュアに扱うことができるようになる。これって強力なメソッドですよね。さらにユーザーの情報を表示するページまで作ることができました。
次回はSign up(ユーザー登録)ページを作っていきましょう!では、次回も乞うご期待!ここまでお読みいただきありがとうございました!
Reference
- Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
- 登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK
- 「ハッシュ」とは何なのか、必ず理解させます | ALIS
Links
・ Vol.1 - Introduction -
・ Vol.2 - Hello, Rails on Docker -
・ Vol.3 - Scaffold, RESTful, MVC -
・ Vol.4 - Static pages -
・ Vol.5 - Model and CRUD -
・ Vol.6 - Model validation -
・ Vol.7 - Secure password - ?この記事
- 投稿日:2020-02-12T16:19:40+09:00
docker imagesがSSDの容量を圧迫したのでHDDを増設してそっちに保存したメモ
最初に
- HDDマウントとdockerの保存場所変更を行っています。
- 保存先やUUIDは、各自で変更してください。
OSとdocker のバージョン確認
$ cat /etc/os-release NAME="Ubuntu" VERSION="16.04.6 LTS (Xenial Xerus)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 16.04.6 LTS" VERSION_ID="16.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" VERSION_CODENAME=xenial UBUNTU_CODENAME=xenial$ docker --version Docker version 18.09.7, build 2d0083dHDDを自動マウントしたい
/etc/fstab
を編集するとよいです。マウント先作成
$ sudo mkdir /mnt/hdd4000名前は任意。4TBのHDDなのでhdd4000
自動マウントするためのfstabを編集
- ディスク名のUUID取得
$ sudo blkid ... /dev/sdc: LABEL="hdd4000" UUID="6e1266f3-3da9-4684-a396-xxxxxxxxxxxx" TYPE="ext4" ...
- /etc/fstab を編集
# hdd4TB UUID=6e1266f3-3da9-4684-a396-xxxxxxxxxxxx /mnt/hdd4000 ext4 defaults 1 2を追加しました。オプションの説明は以下を参考。
参考: https://qiita.com/kihoair/items/03635447591358210772
fstab
間違えるとOS起動しなくなるので注意です。(UUID 1文字間違えてハマった;;)dockerのイメージ保存場所変更
引越前にimageを全消し(移行は考えてません)
- docker コンテナを全削除する
docker ps -aq | xargs docker rm
- docker イメージを全削除する
docker images -aq | xargs docker rmi参考:docker images を全削除する https://qiita.com/fist0/items/2fb1c7f894b5bdff79f4
docker imageの場所を変更
/etc/docker/daemon.json
を編集(新規作成){ "data-root": "/mnt/hdd4000/docker/data" }参考:https://qiita.com/elm200/items/43497f76cbdd19c47d8b
docker 再起動
$ sudo service docker stop $ sudo service docker start変更場所にファイルができたので完了です。
- 投稿日:2020-02-12T13:50:41+09:00
Linux 上で Objective-C 2.0 の開発環境を整える
トレンドが Swift に移って久しく,近年は Objective-C に関心を持つ人が減っていますが,Linux 上で Objective-C の開発環境を整える方法についてまとめてみました。
Docker 上の Ubuntu 18.04 および 19.10 で動作確認しています。Dockerfile の
ENV
とRUN
の内容を取り出せば,実機でも動くでしょう。Objective-C 1.0 でよいなら……
昔ながらの Objective-C 1.0 でよいなら,apt で入手できる出来合いのパッケージをインストールすれば,比較的容易に Clang 9 による Objective-C の開発環境を整えられます。
DockerfileFROM ubuntu:19.10 RUN set -x \ && apt update \ && apt upgrade -y \ && DEBIAN_FRONTEND=noninteractive apt install -y tzdata \ && apt install -y clang-9 make gobjc-9 gnustep-devel \ && apt autoremove -y \ && apt clean \ && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* # Set alias RUN echo 'alias clang-objc="clang-9 \$(gnustep-config --objc-flags) \$(gnustep-config --objc-libs) -lgnustep-base -I/usr/lib/gcc/x86_64-linux-gnu/9/include"' > ~/.bashrc CMD ["/bin/bash"]本質部は
$ apt install -y clang-9 make gobjc-9 gnustep-develです。また,
~/.bashrc
にalias clang-objc="clang-9 \$(gnustep-config --objc-flags) \$(gnustep-config --objc-libs) -lgnustep-base -I/usr/lib/gcc/x86_64-linux-gnu/9/include"と定義してあります。これにより,この Docker コンテナ内で
$ clang-objc -o hoge hoge.m $ ./hogeなどとすることで簡単に Objective-C のソース
hoge.m
をコンパイル・実行できます。Objective-C 2.0 のフル機能を使いたいなら……
- Automatic Reference Counting (ARC)
- Blocks
- Dot Notation
- Object Literal
- Object Subscripting
- Fast Enumeration
- Lightweight Generics
- Grand Central Dispatch (GCD)
といった Modern Objective-C の機能をフルに使いたい場合は,GNUstep の libobjc2 をセットアップせねばなりません。これは apt でインストールできないので,ソースからビルドする必要があります。これがなかなか大変です。plaurent 氏の GitHub レポジトリが大変参考になりました。ビルド手順を Dockerfile にまとめると次のようになります。
DockerfileFROM ubuntu:19.10 ENV CC clang-9 ENV CXX clang++-9 ENV CXXFLAGS -std=c++11 ENV RUNTIME_VERSION gnustep-2.0 ENV PKG_CONFIG_PATH /usr/local/lib/pkgconfig ENV LD /usr/bin/ld.gold ENV LDFLAGS "-fuse-ld=/usr/bin/ld.gold -L/usr/local/lib" WORKDIR /GNUstep-build RUN set -x \ && apt update \ && apt upgrade -y \ && apt install -y git sudo clang-9 clang++-9 build-essential wget \ subversion cmake libffi-dev libxml2-dev \ libgnutls28-dev libicu-dev libblocksruntime-dev libkqueue-dev libpthread-workqueue-dev autoconf libtool \ libjpeg-dev libtiff-dev libffi-dev libcairo-dev libx11-dev libxt-dev libxft-dev \ && apt autoremove -y \ && apt clean \ && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* # Build GNUstep make RUN set -x \ # # Checkout tools-make && git clone https://github.com/gnustep/tools-make.git \ # # Build GNUstep make && cd tools-make \ && CC=${CC} ./configure \ --with-layout=gnustep \ --disable-importing-config-file \ --enable-native-objc-exceptions \ --enable-objc-arc \ --enable-install-ld-so-conf \ --with-library-combo=ng-gnu-gnu \ && make -j8 \ && sudo -E make install \ && . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh \ && echo ". /usr/GNUstep/System/Library/Makefiles/GNUstep.sh" >> ~/.bashrc \ && echo "export RUNTIME_VERSION=gnustep-2.0" >> ~/.bashrc \ && echo 'export CXXFLAGS="-std=c++11"' >> ~/.bashrc \ && cd .. \ # # Build libdispatch # # Checkout swift-corelibs-libdispatch && git clone https://github.com/apple/swift-corelibs-libdispatch \ && cd swift-corelibs-libdispatch \ && git checkout swift-5.1.1-RELEASE \ # # Build libdispatch && rm -Rf build \ && mkdir build \ && cd build \ && cmake .. \ -DCMAKE_C_COMPILER=${CC} \ -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_BUILD_TYPE=Release \ -DUSE_GOLD_LINKER=YES \ && make \ && sudo -E make install \ && sudo ldconfig \ && cd ../.. \ # # Build libobjc2 # # Checkout libobjc2 && git clone https://github.com/gnustep/libobjc2.git \ && cd libobjc2 \ && git submodule init \ && git submodule sync \ && git submodule update \ # # Build libobjc2 && rm -Rf build \ && mkdir build \ && cd build \ && cmake .. \ -DCMAKE_C_COMPILER=${CC} \ -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_ASM_COMPILER=${CC} \ -DTESTS=OFF \ && cmake --build . \ && sudo -E make install \ && sudo ldconfig \ && cd ../.. \ # # Build GNUstep make second time && cd tools-make \ && CC=${CC} ./configure \ --with-layout=gnustep \ --disable-importing-config-file \ --enable-native-objc-exceptions \ --enable-objc-arc \ --enable-install-ld-so-conf \ --with-library-combo=ng-gnu-gnu \ && make -j8 \ && sudo -E make install \ && . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh \ && cd .. \ # # Build GNUstep base # # Checkout libs-base && git clone https://github.com/gnustep/libs-base.git \ # # Build GNUstep base && cd libs-base \ && ./configure \ && make -j8 \ && sudo -E make install \ && cd .. # For GUI programming # # Build GNUstep GUI Library RUN set -x \ && . /usr/GNUstep/System/Library/Makefiles/GNUstep.sh \ # # Checkout libs-gui && git clone https://github.com/gnustep/libs-gui.git \ # # Build GNUstep GUI Library && cd libs-gui \ && ./configure \ && make -j8 \ && sudo -E make install \ && cd .. \ # # Build GNUstep GUI Backend # # Checkout libs-back && git clone https://github.com/gnustep/libs-back.git \ # # Build GNUstep GUI Backend && cd libs-back \ && ./configure \ && make -j8 \ && sudo -E make install \ && cd .. WORKDIR /workdir # Clean build directory RUN rm -rf /GNUstep-build # Set alias RUN echo 'alias clang-objc="\${CC} \$(gnustep-config --objc-flags) \$(gnustep-config --objc-libs) -fobjc-arc -lobjc -ldispatch -lgnustep-base"' >> ~/.bashrc CMD ["/bin/bash"]長いビルド手順でしたね……。最後に
~/.bashrc
にalias clang-objc="\${CC} \$(gnustep-config --objc-flags) \$(gnustep-config --objc-libs) -fobjc-arc -lobjc -ldispatch -lgnustep-base"と設定してありますので,この Docker コンテナ内で
$ clang-objc -o hoge hoge.m $ ./hogeなどとすることで簡単に Objective-C 2.0 のソース
hoge.m
をコンパイル・実行できます。Dockerfile およびテストファイル一式
今回作成した Dockerfile およびテスト用 Objective-C ソースの一式は GitHub レポジトリ にアップしておきました。
$ docker run --rm -it -v $(pwd):/workdir doratex/clang9-objc2:latest /bin/bash # cd test # ./test_all.shとすることで,様々な Objective-C 2.0 の機能をテストできます。(ただしテストのうち最後の GUI のテストは X Window System のサーバとつながっていないと動きません。)
Docker イメージ
今回作成した Docker イメージは Docker Hub のレポジトリ にアップしてあります。
$ docker pull doratex/clang9-objc2:ubuntu1910
などとすれば使えます。
- 投稿日:2020-02-12T12:46:52+09:00
Dockerでproxyサーバ
はじめに
Dockerでsquidによるproxyサーバを構築。
特別なことはしてません。対象機器および環境
検証環境
- CentOS8(8.1.1911)
- Docker(19.03.5)
- squid(4.4)
作業内容
firewallでポート許可
8080/tcpで待ち受けるようにサービスを許可しておきます
firewall-cmd --add-port=8080/tcp --zone=public --permanent firewall-cmd --reloadDockerイメージの準備
再利用できるようにイメージをつくっておきます。
Dockerfileと設定ファイルを置くための適当なディレクトリを作成しておきますmkdir -p /opt/docker/proxy cd /opt/docker/proxyDockerfileを作成
/opt/docker/proxy/proxy.dfFROM centos:centos8 ENV TZ='Asia/Tokyo' RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime ; \ dnf -y update ; dnf install -y squid ; \ sed -i -e "s/http_port 3128/http_port 8080/" /etc/squid/squid.conf ; \ systemctl enable squid ; \ dnf -y install rsyslog ; COPY rsyslog.conf /etc CMD [ "/usr/sbin/init" ]syslog転送用の設定
ローカルのログファイルの変更を検知するモジュール
imfile
を利用して、リモートへsyslogを転送します。
転送先は別のエントリで作成した syslogサーバにUDP:514で指定しています。
ネットワークサービス用のDockerネットワークinfraserv-network
に所属させているため、syslog
というホスト名で転送ができるようになっています。/opt/docker/proxy/rsyslog.confmodule(load="imfile") input(type="imfile" file="/var/log/squid/access.log" tag="pseudolog_squid_access_log" facility="local0" severity="notice") :syslogtag, isequal, "pseudolog_squid_access_log" @syslog:514Dockerfileからイメージをビルドしてコンテナ作成
Dockerfileが作成できたら、ビルドします。
docker build --force-rm -t infraserv:proxy . -f ./proxy.df && \ docker run --cap-add sys_admin --security-opt seccomp:unconfined -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ --network infraserv-network -it -d --name proxy --hostname proxy -p 8080:8080 infraserv:proxyもし、dnfでコケたら、以下のコマンドが効くかもしれない。
# firewall-cmd --add-masquerade --permanent # firewall-cmd --reload動作確認
診断くん、などでチェック。
http://taruo.net/e/
- 投稿日:2020-02-12T12:41:06+09:00
Dockerでtftpサーバ
はじめに
Dockerでtftpサーバを構築。
特別なことはしてません。対象機器および環境
検証環境
- CentOS8(8.1.1911)
- Docker(19.03.5)
- tftp-server(5.2)
- xinetd(2.3.15)
作業内容
firewallでポート許可
tftpサービスを待ち受けるようにサービスを許可しておきます
firewall-cmd --add-service=tftp --zone=public --permanent firewall-cmd --reloadDockerイメージの準備
再利用できるようにイメージをつくっておきます。
Dockerfileと設定ファイルを置くための適当なディレクトリを作成しておきますmkdir -p /opt/docker/tftp cd /opt/docker/tftpDockerfileを作成
/opt/docker/tftp/tftp.dfFROM centos:centos8 RUN dnf -y update ; dnf -y install tftp-server xinetd COPY tftp /etc/xinetd.d/tftp CMD [ "/usr/sbin/init" ]xinetdの設定
tftpをxinetd経由で起動するために、設定ファイルを作成しておきます
/opt/docker/tftp/tftpservice tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -c -u root -s /var/lib/tftpboot disable = no per_source = 11 cps = 100 2 flags = IPv4 }Dockerfileからイメージをビルドしてコンテナ作成
Dockerfileが作成できたら、ビルドします。
tftpは最初に69/udpで接続しますが、その後ポート番号をネゴってデータ転送するので、bridgeだとポート転送しにくい。
ので、hostネットワークに接続してしまいます。docker build --force-rm -t infraserv:tftp . -f ./tftp.df && \ docker run --cap-add sys_admin --security-opt seccomp:unconfined -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ --network host -it -d --name tftp --hostname tftp infraserv:tftp動作確認
手元にあったCiscoのルータで確認
Rdc01#copy run tftp://10.254.10.251/rdc01-config Address or name of remote host [10.254.10.251]? Destination filename [rdc01-config]? !! 11944 bytes copied in 1.112 secs (10741 bytes/sec) Rdc01#copy tftp://10.254.10.251/rdc01-config flash: Destination filename [rdc01-config]? Accessing tftp://10.254.10.251/rdc01-config... Loading rdc01-config from 10.254.10.251 (via Vlan10): ! [OK - 11944 bytes] 11944 bytes copied in 0.652 secs (18319 bytes/sec) Rdc01#
- 投稿日:2020-02-12T12:31:54+09:00
Dockerのrsyslogでコンテナ間や他サーバから転送されるログを集約した
はじめに
dockerでいろいろコンテナを立てたら、ログを集約したくなったので、rsyslogでつくりました。
対象機器および環境
検証環境
- CentOS8(8.1.1911)
- Docker(19.03.5)
- rsyslog
ログの保管方法
リモートから飛んできたログたちは、syslogフォーマットの
%hostname%
で個別ファイルに振り分けます。
/var/log/remotelog/
配下に ホスト名ごとにログファイルとして保管します。/var/log/remotelog/ |-- dhcp.log |-- esxi01.prosper2.net.log |-- FWdc01.prosper2.net.log |-- proxy.log |-- radius.log `-- ....送出側のsyslogフォーマットの設定によって、FQDNだったり、ホスト名だけだったり、ちょっとバラバラ。
ちゃんとすればいいんだけれど、やりかたがまだ調べられてません。。。別のエントリで作成した
infraserv-network
に所属させた他のDockerコンテナから飛んできたログは、ちゃんと%hostname%
フィールドにマッチしているみたいで、ホスト名で分けてくれてます。作業内容
firewallでポート許可
radiusサービスを許可しておきます
# firewall-cmd --add-service=syslog --zone=public --permanent # firewall-cmd --reloadDockerイメージの準備
再利用できるようにイメージをつくっておきます。
Dockerfileと設定ファイルを置くための適当なディレクトリを作成しておきますmkdir -p /opt/docker/syslog cd /opt/docker/syslogDockerfileを作成
/opt/docker/syslog/syslog.dfFROM centos:centos8 ENV TZ='Asia/Tokyo' RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime ; \ dnf -y update ; dnf install -y rsyslog cronie logrotate ; \ mkdir /var/log/remotelog COPY rsyslog.conf /etc/rsyslog.conf COPY remotelog /etc/logrotate.d CMD [ "/usr/sbin/init" ]リモートからのログを受け付ける
bridge経由になっているため、コンテナはホスト(172.20.0.1/32)からのみ受け付けとしています
/opt/docker/syslog/rsyslog.conf$template logfile_hostname, "/var/log/remotelog/%hostname%.log" $template logformat_verbose, "%timegenerated%,%timereported%,%hostname%,%syslogtag%,%syslogseverity%,%syslogfacility%,%msg%\n" $ModLoad imudp $UDPServerRun 514 :fromhost-ip, ereregex, "172.20.0.1" -?logfile_hostname;logformat_verbose & stoplogrotateの設定
ログは圧縮して40世代分保管します。
/opt/docker/syslog/remotelog/var/log/remotelog/*.log { daily rotate 40 compress missingok notifempty postrotate /bin/systemctl restart rsyslog endscript }Dockerfileからイメージをビルドしてコンテナ作成
Dockerfileが作成できたら、ビルドします。
--privileges
はなんか評判悪そう(?)なので、推奨されてるぽい方法でコンテナ生成します。docker build --force-rm -t infraserv:syslog . -f ./syslog.df && \ docker run --cap-add sys_admin --security-opt seccomp:unconfined -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ --network infraserv-network -it -d --name syslog --hostname syslog -p 514:514/udp infraserv:syslog docker exec -it syslog /bin/bashもし、dnfでコケたら、以下のコマンドが効くかもしれない。
# firewall-cmd --add-masquerade --permanent # firewall-cmd --reload接続テスト
コンテナ起動後、しばらく置いてからログディレクトリを確認します。
$ sudo docker exec -it syslog /bin/bash [syslog]# ls -1sh /var/log/remotelog/ total 18M 12K dhcp.log 704K esxi01.prosper2.net.log 16M FWdc01.prosper2.net.log 4.0K _gateway.log 576K proxy.log 4.0K radius.log 256K VMinfraserv05.logファイルの中身
# tail -n 1 * ==> dhcp.log <== Feb 11 21:37:20,Feb 11 21:37:20,dhcp,pseudolog_kea_dhcp4_log,5,16, 2020-02-11 21:37:15.253 INFO [kea-dhcp4.dhcpsrv/26] DHCPSRV_MEMFILE_LFC_EXECUTE executing Lease File Cleanup using: /usr/sbin/kea-lfc -4 -x /var/lib/kea/dhcp4.leases.2 -i /var/lib/kea/dhcp4.leases.1 -o /var/lib/kea/dhcp4.leases.output -f /var/lib/kea/dhcp4.leases.completed -p /var/lib/kea/dhcp4.leases.pid -c ignored-path ==> esxi01.prosper2.net.log <== Feb 11 21:56:05,Feb 11 12:55:58,esxi01.prosper2.net,snmpd:,6,3, send_env_notifications: sent 0 of 0 SEL entries as notifications, 0 already sent ==> FWdc01.prosper2.net.log <== Feb 11 21:56:27,Feb 11 21:56:27,FWdc01.prosper2.net,1,2020/02/11,6,1, 21:56:27,001606007877,TRAFFIC,end,2049,2020/02/11 21:56:27,10.254.11.65,10.254.10.241,0.0.0.0,0.0.0.0,any_to_DNS,,,dns,vsys1,zTrust,zTrust,ethernet1/2.11,ethernet1/2.252,LFP_default,2020/02/11 21:56:27,3327,1,54264,53,0,0,0x19,udp,allow,290,78,212,2,2020/02/11 21:55:55,0,any,0,6764778,0x0,10.0.0.0-10.255.255.255,10.0.0.0-10.255.255.255,0,1,1,aged-out,0,0,0,0,,FWdc01,from-policy,,,0,,0,,N/A,0,0,0,0 ==> _gateway.log <== Feb 11 21:06:05,Feb 11 21:06:05,_gateway,VMwlc01:,3,16, *Dot1x_NW_MsgTask_1: Feb 11 21:06:05.056: %DOT1X-3-INVALID_REPLAY_CTR: 1x_eapkey.c:449 Invalid replay counter from client ac:63:be:92:9d:f9 - got 00 00 00 00 00 00 00 1d, expected 00 00 00 00 00 00 00 1e ==> proxy.log <== Feb 11 21:55:57,Feb 11 21:55:57,proxy,pseudolog_squid_access_log,5,16, 1581425757.416 284915 172.20.0.1 TCP_TUNNEL/200 2563 CONNECT www.google-analytics.com:443 - HIER_DIRECT/216.58.197.174 - ==> radius.log <== Feb 11 20:52:12,Feb 11 20:52:12,radius,pseudolog_radius_log,5,16, Tue Feb 11 20:52:12 2020 : Auth: (3) Login OK: [admin] (from client radius_clients port 34) ==> VMinfraserv05.log <== Feb 11 21:55:11,Feb 11 21:55:11,VMinfraserv05,pseudolog_cacti_log,5,16, 2020/02/11 21:55:08 - SNMPAGENT WARNING: No notification receivers configured for event: cactiNotifyDeviceFailedPoll (CACTI-MIB), severity: medium取得できてますね。
さいごに
syslog転送時に hostname フィールドを追加しない機器はホスト名が
_gateway
になってしまう。Cisco機器とか。
CiscoIOSでlogging origin-id hostname
とやっても、メッセージそのものにホスト名が記載されるだけみたいなので、ちょっと使いにくい。
↓こんな感じになってしまう。Feb 11 20:22:16,Feb 11 20:22:16,_gateway,844:,5,23, Rhq01: Feb 11 20:22:16: %IKEV2-5-SA_UP: SA UP出典
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/s1-basic_configuration_of_rsyslog
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/s1-using_rsyslog_modules
- 投稿日:2020-02-12T09:23:08+09:00
dockerコマンドのメモ
DockerHubからimageの取得する
docker pull ubuntuImageを起動する
docker run ubuntubashを使用する
docker run -i -t ubuntu bash
-i
はコンテナの標準入力を有効化、-t
はttyを有効化するためのオプションDockerHubでimageを検索する
docker search <IMAGE NAME>tagを使用する
docker run python:2.7 python --version
DockerfileからDockerImageを作成する
docker build -t hello .
-t
は名前をつける
.
はdocker build 実行時のコンテキストの指定ローカルに存在するDocker Image の一覧を確認する
docker imagesDocker Hubへログインする
docker loginDocker Image を命名する
docker tag <IMAGE NAME> <USER NAME>/<IMAGE NAME>:<TAG>Docker Hub へ Docker Image をアップロードする
docker push <USER NAME>/<IMAGE NAME>:<TAG>実行中のコンテナを確認する
docker container ls -a
-a
全てのコンテナを表示停止したコンテナをすべて削除する
docker container prune1つ以上のコンテナーを削除する
docker container rm <CONTAINER> [CONTAINER...]Dockerネットワークを一覧で表示する
docker network ls
新しいBridgeネットワークを作成する
docker network create <NAME>停止したコンテナを実行する
docker start -a <CONTAINER>
-a
アタッチする実行中コンテナを停止する
docker stop <CONTAINER>コンテナの中にbashで入る
docker exec -it <CONTAINER> bashイメージのビルド履歴を表示する
docker history <IMAGE NAME>
- 投稿日:2020-02-12T08:04:22+09:00
Docker Swarmで学ぶサービスメッシュ
はじめに
本記事はDocker Swarmでクラスタを構築し、サービスメッシュについて学びます。
環境はAWSのELB(Elastic Load Balancing)と、EC2(Amazon EC2)インスタンス2台を使用し、Docker Swarmのクラスタを構築します。
Kubernetesと比較した際にDocker Swarmを導入するメリットは、導入コストが低いことです。Docker SwarmはKubernetesに比べてハードルが低いため、本番環境にコンテナ技術を導入しようとしているシステムには最適だと考えます。
Docker Swarmを通してサービスメッシュの意義を体感しましょう。
Docker Swarm
Docker Swarmは、Docker社が提供するオーケストレーションツールです。
Docker Swarmを使用することで複数のホストを集約し、簡単にコンテナのデプロイとスケールが実現できます。Docker Swarmはマネージャとノードで構成され、Swarmは群れを意味します。
Docker Swarのクラスタを構築するためには、以下の作業が必要です。
- マネージャとノードにDockerをインストールする。
マネージャとノード間で通信ができるように、ファイアウォールで必要な通信を許可する。
ファイアウォールで許可するルール
ポート番号 用途 2377/tcp クラスタ管理用の通信 4789/udp オーバーレイ・ネットワーク 7946/tcp ノード間通信 7946/udp ノード間通信 サービスメッシュ
サービスメッシュはマイクロサービスアーキテクチャを前提とし、アプリケーション間で通信を制御する仕組みを提供します。この制御された通信はメッシュの様に編みがけになっているため、信頼性を向上します。
例として2台構成のホストの場合、通常のアクセスパスは以下になります。
ブラウザでロードバランサーのDNS名にアクセスすると、HTTPリクエストを受け付けたロードバランサーは、ラウンドロビンでバックエンドであるホストの公開ポートにHTTPリクエストを振り分けます。
例えば、片方のホストで何らかの障害が発生し、コンテナがダウンした場合でも以下の経路により、サービスを継続することができます。
要約すると、単純にホストレベルでアプリケーションを分ける構成の場合は、片方のホストに何らかの障害が発生したときにサービスの提供ができなくなります。よって、コンテナ技術を活用し、サービスメッシュにすることで単一障害点をなくすことができます。
Docker Swarm構築
Docker Swarmの構築手順について記載します。
Docker Swarmの構築は、マネージャ、ノードの順に作業を行います。本記事の例ではweb1がマネージャ、web2がノードになり、Nginxのイメージを使用してデプロイします。
前提条件としてDockerは既にインストールされた状態で、上記で解説したファイアウォールも許可されていることとします。また、本記事では最低限の構成としているため、マネージャ1台、ノード1台になります。
マネージャ
まずはじめに、Docker Swarmの初期化を行います。
docker swarm init
コマンドを実行することでSwarmモードが有効になります。複数IPアドレスを持つ場合は、他のノードとの通信で使用するインターフェースのIPアドレスを
advertise-addr
の引数に指定します。
- Docker Swarmの初期化
# docker swarm init --advertise-addr <IPアドレス>
Swarm initialized: current node (zirc78nsch77ox8di6021ux4n) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-459p0pkyqgxgkhaggjhavd419ldujenqttm1mqmwup0qz9m5qv-1kj3jy6ozwrr2fkj1qvas294a <マネージャのIPアドレス>:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
コマンド実行後、出力結果の
docker swarm join --token SWMTKN-1-(略) <マネージャのIPアドレス>:2377
を控えます。
- node確認
# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zirc78nsch77ox8di6021ux4n * web1 Ready Active Leader 18.09.9-ce
マネージャの場合は、MANAGER STATUSにLeaderと出力されます。
- ネットワーク確認
# docker network ls
NETWORK ID NAME DRIVER SCOPE 53703efd3d07 bridge bridge local aacf6f5e0eb4 docker_gwbridge bridge local 1f0d0e4ae3e7 host host local xip5tlqmokpb ingress overlay swarm 2d36f1c8c80f none null local
Swarmの初期化を行うと新たに2つのネットワーク(docker_gwbridge、ingress)が作成されます。
ノード
次にノードをDocker Swarmのクラスタに参加させるため、ノード側で以下のコマンドを実行します。
--token
の引数にしている値は例になります。上記docker swarm init
コマンドの出力結果をコピーしてペーストすれば大丈夫です。なお、マネージャ側で
docker swarm join-token worker
コマンドを実行することで、トークンの再表示もできます。
- クラスタ参加
# docker swarm join --token SWMTKN-1-(略) <マネージャのIPアドレス>:2377
This node joined a swarm as a worker.
マネージャ側で確認のため、再度、
docker node ls
コマンドを実行すると、nodeが認識されていることが確認できます。
- node確認
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zirc78nsch77ox8di6021ux4n * web1 Ready Active Leader 18.09.9-ce n2o22ptdmyhan8qg0ijmo0qn5 web2 Ready Active 18.09.9-ce
Docker Swarmのデプロイ
本記事では管理しやすいdocker-commposeでデプロイします。
また、docker service create
コマンドでもデプロイできます。serviceやstackの説明については割愛します。デプロイ作業はマネージャ側で行います。
任意のディレクトリに移動し、以下のdocker-commpose.yml
ファイルを作成します。
- docker-commpose.yml
version: "3" services: web: image: nginx deploy: replicas: 2 #resources: # limits: # cpus: "0.1" # memory: 100M restart_policy: condition: on-failure ports: - "80:80" networks: - webnet networks: webnet:
docker-commpose.yml
ファイル作成後、以下のコマンドを実行し、デプロイします。
test
は例となるため、任意の名前を指定します。
# docker stack deploy -c docker-commpose.yml test
Updating service test_web (id: egubeieuri00rzmm9imsna93o)
デプロイ後、以下のコマンドでサービスの状態が確認できます。
REPLICASは2となっているので、2つのコンテナが起動しています。
# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS r04mfg1se3nh test_web replicated 2/2 nginx:latest *:80->80/tcpマネージャとノード側で
docker container ps -a
コマンドを実行すると、コンテナが起動しているのが確認できます。
- マネージャ側
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4a26c3ca6df7 nginx:latest "nginx -g 'daemon of…" 3 seconds ago Up 2 seconds 80/tcp test_web.1.mnnz40tdykzd2intwz5hf68bs
- ノード側
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 614c19349bf0 nginx:latest "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 80/tcp test_web.2.6om5oazbavassohd4akucbum2
Docker Swarmの動作確認
Docker Swarmの動作確認を行います。
ブラウザからロードバランサーのDNS名にアクセスを行い、正常に負荷分散されることを確認します。
- ロードバランサーのDNS名にアクセス
コンテナのログを確認すると、ラウンドロビンで負荷分散されているのが確認できます。
CONTAINER IDはdocker container ps -a
のコマンドで確認します。
# docker logs -f <CONTAINER ID>
10.255.0.3 - - [06/Feb/2020:14:20:51 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" "<アクセス元のグローバルIP>"試しにweb2上(ノード側)で稼働しているコンテナを停止します。
# docker stop <CONTAINER ID>
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 423f673b0513 nginx:latest "nginx -g 'daemon of…" 19 hours ago Exited (0) 5 seconds ago test_web.2.kc7yypyasgvjtolsb1zwmhjoy
このときweb2上でコンテナは稼働していません。
ロードバランサーのDNS名にアクセスできることを確認します。例としてブラウザから停止したweb2の公開IPにアクセスします。
Web1(マネージャ)上のコンテナのアクセスログに、停止したweb2(ノード)の公開IPに対するアクセスが確認できます。
10.255.0.3 - - [07/Feb/2020:02:19:01 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" "-"停止したweb2(ノード側)のローカルからも、以下のコマンドを実行することでコンテナにアクセスができます。
# curl localhost 80
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> curl: (7) Couldn't connect to serverweb1(マネージャ)のログでは以下の様に出力されます。
10.255.0.2 - - [07/Feb/2020:02:41:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"
web1(マネージャ)で4789ポートをダンプして見ていると、オーバーレイ・ネットワークの通信を見ることができます。
# tcpdump -nli eth0 port 4789 -Av
Docker Swarmのスケール
既にサービスが起動している状態で、以下のコマンドを実行することでスケールができます。以下のコマンドはコンテナの数を4コンテナに変更しています。
# docker service scale test_web=4
test_web scaled to 4 overall progress: 4 out of 4 tasks 1/4: running [==================================================>] 2/4: running [==================================================>] 3/4: running [==================================================>] 4/4: running [==================================================>] verify: Service convergedスケール後、
docker container ps -a
コマンドを実行すると、コンテナが増えていのが分かります。CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 41962946aa48 nginx:latest "nginx -g 'daemon of…" 3 minutes ago Up 3 minutes 80/tcp test_web.4.pytl36ejcd81ybthisxfo47br 423f673b0513 nginx:latest "nginx -g 'daemon of…" 7 hours ago Up 7 hours 80/tcp test_web.2.kc7yypyasgvjtolsb1zwmhjoy
デプロイ時はサーバ1台ずつに対してアプリケーション資産の入れ替えを行う必要がなく、マネージャ1台で済みます。
Docker Swarmの性質
Docker Swarmは冪等性を持っています。
具体的には、Docker Swarmは指定したreplicas数のコンテナを維持するため、クラスタ化している片方のホストがダウンした場合は、片方のホストでコンテナを起動します。
以下は
docker container ps -a
コマンドの出力になります。
例としてweb1とweb2でそれぞれコンテナが起動しています。
- web1
e5ccbfa9739b nginx:latest "nginx -g 'daemon of…" 3 minutes ago Up 3 minutes 80/tcp test_web.1.mrgkhbd7juer72v6bv0l42fxq
- web2
4820c7bbe9c1 nginx:latest "nginx -g 'daemon of…" 3 minutes ago Up 3 minutes 80/tcp test_web.2.wfe1n11s8940rdl8r1c47o6nc
web2のホストを停止しました。web2のダウンを検知すると、web1上でコンテナを作成します。
0a88f53039a3 nginx:latest "nginx -g 'daemon of…" 5 seconds ago Created test_web.2.p06zas3c3kt9ekjojhhfnl3co e5ccbfa9739b nginx:latest "nginx -g 'daemon of…" 4 minutes ago Up 4 minutes 80/tcp test_web.1.mrgkhbd7juer72v6bv0l42fxq
web1上でコンテナが2台起動しています。
0a88f53039a3 nginx:latest "nginx -g 'daemon of…" 37 seconds ago Up 31 seconds 80/tcp test_web.2.p06zas3c3kt9ekjojhhfnl3co e5ccbfa9739b nginx:latest "nginx -g 'daemon of…" 5 minutes ago Up 5 minutes 80/tcp test_web.1.mrgkhbd7juer72v6bv0l42fxq
Docker Swarm解除
Docker Swarmの解除方法について記載します。
先にマネージャ側で以下のコマンドを実行し、サービスの削除を行いす。
# docker service rm test_web
test_web
次にノード、マネージャの順に作業を行います。
ノード
- ノードの切り離し
# docker swarm leave
Node left the swarm.
マネージャ
ノードのSTATUSがDOWNになったことを確認します。
- node確認
# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zirc78nsch77ox8di6021ux4n * web1 Ready Active Leader 18.09.9-ce n2o22ptdmyhan8qg0ijmo0qn5 web2 Down Active 18.09.9-ce
ノードを削除します。オプションの引数には、ノード名を指定します。
- node削除
# docker node rm --force web2
web2
マネージャからノードが認識されなくなったことを確認します。
- node確認
# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zirc78nsch77ox8di6021ux4n * web1 Ready Active Leader 18.09.9-ce
最後にマネージャ自身を切り離します。
- マネージャの切り離し
# docker swarm leave --force
Node left the swarm.
Docker Swarm解体
Docker Swarmを使用しない場合は、マネージャ側で以下の作業を行います。
ノードが存在しないことを確認します。
- node確認
# docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
Docker Swarmで作成されたネットワークが削除されたことを確認します。docker_gwbridgeのネットワークは残っています。
# docker network ls
NETWORK ID NAME DRIVER SCOPE 987cfc73d87c bridge bridge local aacf6f5e0eb4 docker_gwbridge bridge local 1f0d0e4ae3e7 host host local 2d36f1c8c80f none null local
以下のコマンドを実行し、使用していない全てのリソース削除します。
- リソース削除
# docker system prune
WARNING! This will remove: - all stopped containers - all networks not used by at least one container - all dangling images - all dangling build cache Are you sure you want to continue? [y/N] y Deleted Networks: docker_gwbridge Deleted Images: untagged: nginx@sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f deleted: sha256:2073e0bcb60ee98548d313ead5eacbfe16d9054f8800a32bedd859922a99a6e1 deleted: sha256:a3136fbf38691346715cac8360bcdfca0fff812cede416469653670f04e2cab0 deleted: sha256:99360ffcb2da18fd9ede194efaf5d4b90e7aee99f45737e918113e6833dcf278 deleted: sha256:488dfecc21b1bc607e09368d2791cb784cf8c4ec5c05d2952b045b3e0f8cc01e untagged: nginx@sha256:70821e443be75ea38bdf52a974fd2271babd5875b2b1964f05025981c75a6717 deleted: sha256:5ad3bd0e67a9c542210a21a3c72f56ef6387cf9b7f4c2506d2398d55a2593ed0 deleted: sha256:b69e2ed46519bc33e7c887967e4f61a2ee53aef165b70f75e208937fb42e7b4c deleted: sha256:4cb7f732537bf0f65cd9f8f7b63bbe71abcf9d0df396f58621ef3be0b2487b27 deleted: sha256:556c5fb0d91b726083a8ce42e2faaed99f11bc68d3f70e2c7bbce87e7e0b3e10 Total reclaimed space: 253.4MB
ナレッジ
docker-commposeのバージョン
Docker Swarmを使用する場合に、docker-commposeで使用できるバージョンは3になります。
docker-commposeでビルドする場合の留意事項
docker-commposeでビルド(stack)する場合、イメージが必要になります。
Compose file version 3 referenceより
注:( バージョン3)Composeファイルを使用してSwarmモードでスタックをデプロイする場合、このオプションは無視され ます。このdocker stackコマンドは、ビルド済みのイメージのみを受け入れます。
そのため、Docker registryの環境が必要になります。
ローカルでDockerレジストリをセットアップする方法については、公式の以下URLが参考になります。
例として、以下の様にビルドを指定してデプロイを実行した場合、
version: '3' services: app: build: ./src以下のエラーメッセージが出力されて、デプロイをすることはできません。
failed to create service stackdemo_backend: Error response from daemon: rpc error: code = InvalidArgument desc = ContainerSpec: image reference must be provided
デプロイ時のエラー
例として2台構成のホストで、docker-commpose.ymlファイルのreplicasの値を2にしてデプロイした場合は、基本的に1ホストに対して1コンテナで分散されます。
もし、デプロイ時に片方のホストで2台のコンテナが起動した場合は、何らかのエラーが発生し、片方のホストでコンテナが起動できなかったことが考えられます。エラーはLinuxの場合、シスログから確認することができます。
おわりに
不確実性があり変化の速さが求めれられる現代のアプリケーション開発には、オーケストレーションツールは必須な技術です。
応用としてサーバレスの技術を使用し、CPUやメモリリソース等のしきい値等を設定して、しきい値を超えたらサーバをスケールアウトなどの運用も行うことができます。
参考
- 投稿日:2020-02-12T07:50:07+09:00
Docker Compose と Simpacker で、モダンな Rails 開発環境を構築する
想定読者
- Rails のフロントエンド開発に webpack を利用している(利用しようとしている)
- Rails/webpack 自体の設定については、本記事では必要最低限しか記載しません
- ※ webpacker gem 経由で webpack を利用されている場合
- →本記事では webpacker は利用しません。webpack 自体の設定を直接書くことになります。
- Rails 実行用のコンテナと webpack 実行用のコンテナを分離したい&それぞれのコンテナサイズを小さくしたい
- コンテナの再ビルド時間を減らしたい
- Node.js に依存する処理が Rails コード内に存在しないことを簡単に検知したい
- ただの趣味
- etc.
環境
- Ruby >= 2.5.1 (for Rails 6)
- with Bundler
- Node.js >= 12.x
- with Yarn
- Docker
- with Docker Compose
※ 一部手順を簡略化するため、Ruby および Node.js がローカルにもインストールされていることを前提としています
docker run ruby -v .:/app -w /app
などを使えばローカルインストールせずとも構築できるとは思いますが未確認です手順
必要なパッケージのインストール
Rails new の実行
cd path/to/workspace gem install rails rails new <my-new-rails-project> --database=postgresql --skip-sprockets --skip-javascript --skip-turbolinks --skip-bundle --skip-webpack-install
<my-new-rails-project>
,--database=
あたりの指定は適宜読み替えてください- css(sass) の管理も webpack に任せる前提となっています。css(sass) の管理を Rails で行いたい場合は
--skip-sprockets
オプションは指定しないでくださいSimpacker gem のインストール
cd path/to/workspace/<my-new-rails-project> echo "gem 'simpacker'" >> Gemfile bundle install bundle exec rails simpacker:installwebpack-dev-server のインストール
cd path/to/workspace/<my-new-rails-project> yarn add -D webpack-dev-serverDockerfile の作成
for Rails
# <my-new-rails-project>/build/Dockerfile.rails FROM ruby:2.7.0 as rails-dev RUN apt-get install -y locales \ && echo 'ja_JP.UTF-8 UTF-8' >> /etc/locale.gen \ && locale-gen \ && update-locale LANG=ja_JP.UTF-8 ENV LANG=ja_JP.UTF-8 RUN mkdir /app WORKDIR /app ADD Gemfile /app/Gemfile ADD Gemfile.lock /app/Gemfile.lock RUN bundle install CMD ["bundle" "exec" "rails" "server"]for webpack
# <my-new-rails-project>/build/Dockerfile.rails FROM node:12 as webpack RUN mkdir /app WORKDIR /app ADD package.json /app/package.json ADD yarn.lock /app/yarn.lock RUN yarn install CMD ["yarn" "run" "webpack-dev-server" "--config" "webpack.config.js"]docker-compose.yml
# <my-new-rails-project>/docker-compose.yml version: '3.7' services: rails: build: context: . dockerfile: build/Dockerfile.rails target: rails-dev tty: true stdin_open: true ports: - "3000:3000" volumes: - .:/app - bundle:/usr/local/bundle depends_on: - db - webpack webpack: build: context: . dockerfile: build/Dockerfile.webpack target: webpack ports: - "3035:3035" volumes: - .:/app - node_modules:/app/node_modules db: image: postgres:12 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres volumes: - pg_data:/var/lib/postgresql/data volumes: bundle: {} node_modules: {} pg_data: {}Rails/webpack それぞれの設定を変更
Rails
config/puma.rb
docker コンテナ外からアクセスするために、listen address を
127.0.0.1
から0.0.0.0
に変更します# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # -port ENV.fetch('PORT') { 3000 } +port ENV.fetch('PORT') { 3000 }, '0.0.0.0' # Specifies the `environment` that Puma will run in. #config/database.yml
db
コンテナに接続する例です(適宜読み替えてください)# For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + username: postgres + password: postgres + host: db development: <<: *default
webpack.config.js
See also: https://github.com/hokaccha/simpacker/blob/master/example/webpack-dev-server/README.md
output: { path: path.resolve(__dirname, "public/packs"), - publicPath: "/packs/", + publicPath: isProd ? "/packs/" : "//localhost:3035/packs/", filename: isProd ? "[name]-[hash].js" : "[name].js" }, ... }, - plugins: [new WebpackAssetsManifest({ publicPath: true })] + plugins: [new WebpackAssetsManifest({ publicPath: true, writeToDisk: true })] + devServer: { + host: "0.0.0.0", + port: 3035, + hot: true, + headers: { + "Access-Control-Allow-Origin": "*" + } + } }動作確認
Rails controller/view の作成
config/routes.rb
Rails.application.routes.draw do root 'home#index' endapp/controllers/home_controller.rb
class HomeController < ApplicationController def index; end endapp/views/layouts/application.html.slim
doctype html html[lang="ja"] head meta[charset="UTF-8"] title MyNewRailsProject = csrf_meta_tags = csp_meta_tag = javascript_packs_tag 'application' body = yieldapp/views/home/index.html.slim
h1 home#indexRails server の起動
docker-compose build docker-compose up -d open http://localhost:3000 # for macOS参考
- 投稿日:2020-02-12T07:15:20+09:00
Golang x Beego x Docker x CircleCI x npmで開発環境をサクッと作ってみよう
DockerとCircleCIなどを組み込みつつGolangのBeego開発環境を構築します。
本稿では以下を前提とします。前提となる知識
・terminalのコマンド操作
・viまたはエディタの操作
・Docker,docker-composeの知識
・gitやgithubの基本的な操作前提となる条件
・OSはmacOSを前提とします。どうしてもWindowsなどの場合はVagrantでLinuxの仮想環境を立てるなどして自力で対応してみてください。
・バージョン管理のツールはGithubを用います。この記事で書いていること
・Beegoの0からの環境構築
・Dockerとdocker-composeでコンテナ環境構築
・CircleCIの0からの設定
・フロントエンド環境の0からの構築この記事に書いてないこと
・Go言語特有の実装方法やtipsなどBeego環境のセットアップ
Goのインストールの確認
以下のコマンドでGoがローカルに入っているか確認しましょう。
go version
not foundと表示される場合は公式サイトからパッケージのダウンロードをするかbrewでインストールしましょう。
インストール後はGOPATHの設定が必要です。
手順としては大体以下ですが、環境によって異なることがあるので公式を確認しましょう。
- GOPATHとなるディレクトリを作成しておく
mkdir ~/go/
- ~/.bash_profileを開く
vim ~/.bash_profile
- 以下を追記する
export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin
- 保存後に反映
source ~/.bash_profileBeegoのインストール
Goのインストールが完了してgoコマンドが使えるようになったことを確認できたらBeegoをインストールしましょう。
公式サイトを参考に必要なツールをインストールする。go get -u github.com/astaxie/beego go get -u github.com/beego/bee正しく実行されると
$GOPATH/bin
の配下にバイナリファイルが格納されます。プロジェクトを作成する
- ソースコード格納用のディレクトリの作成(任意)
mkdir $GOPATH/src
- プロジェクトを作成
$ cd $GOPATH/src $ bee new beego-app $ cd beego-app $ ls conf controllers main.go models routers static tests views
- プロジェクトを起動
bee run「アプリケーション“beego-app”へのネットワーク受信接続を許可しますか?」とアラートが表示されると思うが、許可をクリックして http://localhost:8080/ にアクセスして以下のような画面が表示されることを確認する。
ここまでで以下のような構成のプロジェクトが作成されています。
それぞれの役割を詳しく確認したい場合は公式ドキュメントを見てみましょう。. ├── beego-app ├── conf │ └── app.conf ├── controllers │ └── default.go ├── main.go ├── models ├── routers │ └── router.go ├── static │ ├── css │ ├── img │ └── js │ └── reload.min.js ├── tests │ └── default_test.go └── views └── index.tplDockerとdocker-composeでコンテナを立ち上げる
ホスト側でのBeego環境はできましたが、他開発者との共有を簡単に行うことができるようにDockerとdocker-composeを使ってコンテナ環境を立ち上げましょう。
docker-compose.ymlの作成
以下のファイルをプロジェクト直下に配置する
$ touch $GOPATH/src/beego-app/docker-compose.ymldocker-compose.ymlversion: '3' services: app: container_name: beego-app build: context: docker dockerfile: Dockerfile volumes: - .:/go/src/beego-app ports: - 10080:10080portが他コンテナやサービスにバッティングしてしまう場合は、そのポートをlsofコマンドで確認してkillするかportsのところを任意に書き換えてください。
buildで記載されているcontext直下のDockerfileをビルドします。docker-compose について詳しく知りたい場合
http://docs.docker.jp/compose/compose-file.htmlDockerfileの作成
dockerというディレクトリを作成してDockerfileを追加します。
Dockerfileについてはこちらmkdir $GOPATH/src/beego-app/docker touch $GOPATH/src/beego-app/docker/Dockerfile# @see::https://hub.docker.com/_/amazonlinux FROM amazonlinux:2 # システムアップデート RUN yum update -y # gitのインストール RUN yum install -y git # @see::https://fedoraproject.org/wiki/EPEL RUN amazon-linux-extras install -y epel # amazon-linux-extrasでインストールできる最新のgolang RUN amazon-linux-extras list | grep golang RUN amazon-linux-extras install -y golang1.11 RUN go version # beegoのインストール ENV GOPATH /go ENV PATH $PATH:$GOPATH/bin RUN go get -u github.com/beego/bee RUN go get -u github.com/astaxie/beego # カレントディレクトリをコンテナに追加する COPY . /go/src/beego-app # 作業ディレクトリを指定する WORKDIR /go/src/beego-app # コンテナ実行時にコンパイルと実行を行う CMD bee runイメージはAWS EC2での運用を想定してamazonlinux:2を用いている。
amazonlinuxベースのコンテナ上にgoとbeegoをインストールし、ホスト側をコンテナ側にマウントし最後にbeegoを実行しています。コンテナを起動する
コンテナを立ち上げる前に上記のDockerfileのportをmain.goのbeego.Runの引数に渡します。
main.gopackage main import ( _ "beego-app/routers" "github.com/astaxie/beego" ) func main() { beego.Run(":10080") }Dockerfileをビルドしてコンテナを起動します。
docker-compose.ymlのディレクトリで以下のコマンドを実行します。$ docker-compose up -d Creating network "beego-app_default" with the default driver Building app Step 1/14 : FROM amazonlinux:2 2: Pulling from library/amazonlinux正常に起動できているかpsコマンドで確認してみましょう。
$ docker-compose ps Name Command State Ports ----------------------------------------------------------------- beego-app /bin/sh -c bee run Up 0.0.0.0:10080->10080/tcpコンテナの中に入って見てみましょう。
$ docker exec -it beego-app bash bash-4.2# ls beego-app conf controllers docker docker-compose.yml main.go models routers static tests touch views bash-4.2# pwd /go/src/beego-appもし、うまくいかなくてクリーンな状態からやり直したい場合、
docker-compose down --rmi all --volumes
で該当のコンテナ、ネットワーク、ボリューム、イメージだけを削除するか、
もし他のコンテナやイメージもリセットしてしまって良い場合はdockerのアプリケーションを起動してpreferencesから「Reset disk image」で完全にリセットしてしまう方法もあります。上記うまく行っていたらコンテナの実行ログを見てみましょう。
$ docker logs -f beego-app ______ | ___ \ | |_/ / ___ ___ | ___ \ / _ \ / _ \ | |_/ /| __/| __/ \____/ \___| \___| v1.10.0 2020/02/09 10:21:09 INFO ▶ 0001 Using 'beego-app' as 'appname' 2020/02/09 10:21:10 INFO ▶ 0002 Initializing watcher... beego-app/controllers beego-app/routers beego-app 2020/02/09 10:21:12 SUCCESS ▶ 0003 Built Successfully! 2020/02/09 10:21:12 INFO ▶ 0004 Restarting 'beego-app'... 2020/02/09 10:21:12 SUCCESS ▶ 0005 './beego-app' is running... 2020/02/09 10:21:12.975 [I] [asm_amd64.s:1357] http server Running on http://:10080
http server Running on http://:10080
というところに着目して、10080番ポートにリッスンされていることが確認できたので以下にアクセスして確認してみます。CircleCIでCI環境を構築する
最近ではgithub actionsなども出てきているが、とはいえCircleCIを採用している現場もまだまだ多いとおもうので、ここではCircleCIを用いてCI「Continuous Integration(継続的インテグレーション)」環境を構築する。
config.ymlの作成
プロジェクト直下に
.circleci
というディレクトリを作成し、.circleci直下にconfig.ymlを置く。$ mkdir $GOPATH/src/beego-app/.circleci $ touch $GOPATH/src/beego-app/.circleci/config.ymlconfig.ymlを以下のように作成する
config.yml# @see::https://circleci.com/docs/ja/2.0/configuration-reference/ version: 2.1 # 実行処理は 1 つ以上の名前の付いたジョブで構成され、それらのジョブの指定は jobs マップで行います。 jobs: # CircleCI上のテスト test: docker: - image: circleci/golang:latest steps: - checkout - run: echo "this is jobs" # Workflow は、ジョブの集まりとその実行順序の定義に関するルールを決めるものです。 workflows: build-test-deploy: jobs: # CircleCI上のテスト - test細かい定義は公式を確認してください。
今回はとりあえず最低限の定義のみ記載します。実運用ではCircleCI上でテストコードを実行したり、特定のブランチ(masterやstagingなど)のときにデプロイを行い自動化するようなCD「Continuous Delivery(継続的デリバリー)」を実現したりします。
上記ではworkflowsからtestというjobsが実行され、jobsのtestで指定されているdockerイメージ上でstepsに記載されているコマンドが実行されます。
CircleCIにリポジトリを登録する
まずは上記のソースコードを各自のgithub上にリポジトリを作成します。
git?github?な方はこちらや他の記事などもググって参考にしながら進めてみてください。
リポジトリが作成できたらローカルで作成したソースコードをプッシュしましょう。リポジトリの準備ができたらCircleCIに連携しましょう。
CircleCIのアカウントがない場合は https://circleci.com/ からgithubアカウントでサインアップしましょう。ログインできたらAdd Projectsを見つけて該当のリポジトリの「Set Up Projects」を実行しましょう。
既に.circleci/config.ymlを作成しているのでそのままStart Buildingしましょう
STATUSがRUNNINGからSUCCESSになれば成功です
これでプッシュされるたびにconfig.ymlに記載されている内容がcircleci上で実行されます。
フロントエンド環境を構築する
npm(Node Package Manager)でフロントエンドのパッケージを一括管理します。
npmが使えるかどうかは以下のコマンドで確認します。
npm -v && node -v
npmがない場合はまずnode.jsをインストールします。
node.jsをインストールすると一緒についてきます。
node.jsは公式から直接ダウンロードするか、homebrewを使ってダウンロードする方法があります。参考
https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09初期化
プロジェクトのルートディレクトリで以下のコマンドを実行します。
npm initすると以下のようにコマンドラインでいくつか質問されると思います。
特にこだわりがなければ全てenterでいいです。package name: (beego-app) version: (1.0.0) description: entry point: (index.js) test command: git repository: (https://github.com/kqxgy385/cuddly-octo-meme.git) keywords: author: license: (ISC) Is this OK? (yes)するとpackage.jsonというファイルが生成されると思います。
npmでインストールしたパッケージのバージョン情報がpackage.jsonに格納されます。以下のような内容になっていると思います。
package.json{ "name": "beego-app", "version": "1.0.0", "description": "", "main": "index.js", "directories": { "test": "tests" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/kqxgy385/cuddly-octo-meme.git" }, "author": "", "license": "ISC", "bugs": { "url": "https://github.com/kqxgy385/cuddly-octo-meme/issues" }, "homepage": "https://github.com/kqxgy385/cuddly-octo-meme#readme" }先ほどのコマンドラインで回答した内容が反映されるようになっています。
作り直したい場合は一度package.jsonを削除してもう一度npm initしてみましょう。scriptsというところでコマンドを定義しておくことが可能で、デフォルトではtestというechoしてexitするだけのスクリプトが定義されています。
ためしにnpm run test
と実行してみましょう。
今後ここにjsやcssなどのbuildのコマンドを定義して利用します。パッケージの復元
package.jsonが置いてあるプロジェクトルートで以下のコマンドを実行します。
npm installするとpackage.jsonに記載されている依存関係がインストールされ、package-lock.jsonというファイルが生成されます。
パッケージのインストール
必要パッケージのインストール方法を確認します。
以下のコマンドを実行してみます。npm install webpackするとnode_modulesというディレクトリが生成され、またpackage.jsonに以下のように追記されていると思います。
package.json"dependencies": { "webpack": "^4.41.6" }これでプロジェクト内でwebpackを利用することができます。
必要なパッケージはnpm installでインストールしていきます。
node_modulesは一般的にgit管理するものではないのでgitignoreに入れておきましょう。webpackでフロントエンドをバンドルできるようにしよう
ここから先は細かい説明は省略します。
package.jsonのscriptsとdependenciesを以下にします。package.json"scripts": { "dev": "webpack-dev-server --config webpack.config.js", "webpack": "webpack --config webpack.config.js" }, "dependencies": { "css-loader": "^3.4.0", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^5.0.2", "html-webpack-plugin": "^3.2.0", "node-sass": "^4.13.0", "sass-loader": "^8.0.0", "style-loader": "^1.1.2", "vue": "^2.6.11", "vue-loader": "^15.8.3", "vue-template-compiler": "^2.6.11", "webpack": "^4.41.5", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.10.1", "write-file-webpack-plugin": "^4.5.1" }プロジェクト直下にwebpack.config.jsというファイルを作成し、内容を以下にしてみましょう。
webpackについては公式をお勧めします。webpack.config.jsconst path = require('path'); const projectRoot = path.resolve(__dirname); const HtmlWebpackPlugin = require('html-webpack-plugin'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); const WriteFileWebPackPlugin = require('write-file-webpack-plugin'); module.exports = { // エントリーポイントを指定する entry: './static/js/entry/index.js', // bundleファイルをwebpackがどこにどのような名前で出力すればいいのかを指定する output: { filename: '[name].js', path: path.join(projectRoot, 'static/js/dist') }, // webpack-dev-serverのオプションを選択する devServer: { // 使用するホストを指定する host: 'localhost', // リクエストをリッスンするポートを指定する port: '8000', // サーバーに提供するコンテンツを指定する contentBase: path.join(__dirname, "static/js/dist"), }, // @see::https://webpack.js.org/configuration/devtool/ devtool: "cheap-module-eval-source-map", // ローダーの設定 module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, { test: /\.scss$/, use: ["style-loader", "css-loader", "sass-loader"] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'file-loader' } ] }, ] }, // プラグインの設定 plugins: [ new VueLoaderPlugin(), new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'static/index.html') }), new WriteFileWebPackPlugin(), ] };バンドルされたファイルが
static/js/dist
に生成されるように設定されています。ここまでできたらもう一度npm installします。
$ npm installここまででプロジェクトの構成は以下のようになっているかと思います。
. ├── README.md ├── conf │ └── app.conf ├── controllers │ └── default.go ├── docker │ └── Dockerfile ├── docker-compose.yml ├── main.go ├── models ├── package-lock.json ├── package.json ├── routers │ └── router.go ├── static │ ├── css │ ├── img │ └── js │ └── reload.min.js ├── tests │ └── default_test.go ├── touch └── views └── index.tplstatic直下にindex.htmlというファイルを生成し、内容を以下にしてみましょう。
<!DOCTYPE html> <html lang="js"> <head> <title>beego-app</title> </head> <body> <div id="app" v-cloak></div> </body> </html>jsというディレクトリの直下にentryというディレクトリとdistというディレクトリを作っておきます。
entryの直下にApp.vueというファイルを生成し、内容を以下にします。<template> <div id="app" class="top"> <header> <div class="title"> <a href="/">BEEGO-APP</a> </div> </header> </div> </template> <script> export default { name: "app", }; </script> <style lang="scss" scoped> .top { position: absolute; height: 1500px; width: 100%; background-color: #e8f0ff; top: 0; left: 0; header { display: flex; position: fixed; background-color: rgba(255, 255, 255, 0.9); height: 62px; width: 100%; z-index: 999; .title { display: block; position: relative; left: 10px; background-color: #d6e4ff; a { display: block; margin: 22px 0; color: #999999; cursor: pointer; text-decoration: none; &:hover { color: #da6b64; } } } } } </style>さらにentry直下にindex.jsというファイルを生成し、内容を以下にします。
index.jsimport Vue from 'vue/dist/vue.esm.js' import App from './App.vue' new Vue({ el: '#app', template: '<App/>', components: { App } });アプリケーションのデフォルトのアクセス先を変更するためrouters/router.goを以下に書き換えましょう。
router.gopackage routers import ( "github.com/astaxie/beego" ) func init() { beego.DelStaticPath("/static") beego.SetStaticPath("//", "static/js/dist") }ここまでできたらまずは以下のコマンドを実行してみましょう。
$ npm run webpack先ほどpackage.jsonのscriptsで定義したwebpackを実行するコマンドのエイリアスです。
上記コマンドを実行して http://localhost:10080/ にアクセスして以下のような画面になっていれば成功です。
うまく行ってない場合はdocker-composeの再起動なども試してみましょう。ここまでできたら次に以下のコマンドを試してみましょう。
$ npm run dev先ほどpackage.jsonのscriptsで定義したwebpack-dev-serverを実行するコマンドのエイリアスです。
先ほどのwebpack.config.jsのdevServerのportを8000番にしたことにより http://localhost:8000 にアクセスできるようになります。
http://localhost:10080/ の時と同じ画面が見れていたら成功です。今度はApp.vueの内容を適当に書き換えてみましょう。
npm run devを起動している最中はホットリロードが効いているはずなので、変更が即時で反映されていればwebpack.config.jsで設定した内容が反映されていることになります。ここまでで構成は以下のようになります。
. ├── README.md ├── beego-app ├── conf │ └── app.conf ├── controllers │ └── default.go ├── docker │ └── Dockerfile ├── docker-compose.yml ├── main.go ├── models ├── package-lock.json ├── package.json ├── routers │ └── router.go ├── static │ ├── css │ ├── img │ ├── index.html │ └── js │ ├── dist │ │ ├── index.html │ │ └── main.js │ ├── entry │ │ ├── App.vue │ │ └── index.js │ └── reload.min.js ├── tests │ └── default_test.go ├── touch ├── views │ └── index.tpl └── webpack.config.js次は?
デバッガツールdelveの導入、テストコード実行方法、MySQLコンテナを立ち上げてマイグレーションする方法などを追記します。そのうち。
参考
Getting started
https://beego.me/quickstart
Beego を触ってみる (環境構築)
https://qiita.com/macococo/items/e5ace2550418ccced9ac
Setting GOPATH
https://github.com/golang/go/wiki/SettingGOPATH
Compose ファイル・リファレンス
http://docs.docker.jp/compose/compose-file.html
npm入門
https://qiita.com/maitake9116/items/7825d90c09f3e2f87dea
webpack documentation
https://webpack.js.org/concepts/
- 投稿日:2020-02-12T01:10:31+09:00
Linux VMでVSCode + Dockerの開発環境をつくる
VSCodeのRemote(Container) プラグインが便利だったので、VM上に開発環境を構築してみた。
Windows VM上には素直にDockerをインストールできない(ゲストOS上ではHyper Vオプションが無効)。
そこで、Linux VMでリモートデスクトップを使えるようにして、開発環境を構築してみた。
1. VM準備
- Cent OS 7でVMを作成する。
(Cent OS 8で後続の手順で環境構築すると、セットアップ直後はRDPでつながるが、再起動後にVMにSSHもRDPも接続できなくなる問題が発生したのでやり直した)
2. Remote Desktopをセットアップ
- VMにSSH接続して、Rootユーザーに切り替え。
sudo su -
以下サイトを参考に、RDPのパッケージをインストールする。WindowsのRDPを使ってクラウド上のLinuxインスタンスに接続する - Qiita
RDP用ユーザーを作成。必要に応じてsudoリストに追加。
$ useradd sampleuser $ passwd sampleuser $ usermod -aG wheel sampleuser
- (お好みで)デフォルトの見た目をGNOMEクラシックからGNOMEに変更
echo 'DESKTOP="GNOME"' >> /etc/sysconfig/desktop systemctl restart gdm.service3. リモートデスクトップでVMに接続
リモートデスクトップアプリを使ってVMに接続する。
4. Visual Studio Code をインストール
- 公式サイトからrmpファイルをダウンロードしてyumでインストール
cd ~/path/to/download/ sudo yum install code-1.42.0-1580986751.el7.x86_64.rpm
- Remote(Conteiner)プラグインをインストールする VSCode上で「Remote(Conteiner)」プラグインを検索して、インストールする。
5. Dockerのインストール
- 以下のサイトを参考にDockerをインストールする
- Dockerグループにユーザーを追加する
$ usermod -aG docker sampleuser6. VS CodeでDocker実行
- 「リモートエクスプローラー」タブ内の「+」ボタンをクリック
- 「Open Folder in Container」 を選択し、ブランクフォルダーを選択
- 「Python 3」コンテナーを選択して実行
- Python 3 コードが実行できるコンテナーが起動する