MVCモデル

記事作成の経緯

Railsポートフォリオを作成している中で、そもそもMVCモデルを理解してないため、開発するときやエラーがあった際にどこから手をつければいいのか分からないことが多い。

そのため、そもそもMVCモデルが何なのかを理解し、どういった構成でプログラムが作られているのか理解するため、自分なりにまとめてみる。

MVCモデルとは

プログラムをModel,View,Controllerの3つの役割に分けた構成のこと
それぞれの役割は

  • Model
    プログラムで扱われるデータを管理する

  • View
    画面の表示、画面からの入力を受け付ける

  • Controller
    ModelとViewを制御する

具体例

ECサイトで商品をカゴに入れる処理をした場合の処理の流れ

  1. View
    商品をカゴに入れる入力を受け付ける

  2. Controller
    Viewの操作を受け取り、Modelに商品をカゴに入れるよう指示する

  3. Model
    カゴに商品が追加される

MVCモデルによる利点

  • プログラムの構成を把握しやすくなる
    特定のモデルに基づき開発をすることで、プログラムを初めて見る人がどこに何の役割をもつプログラムがあるか分かりやすくなる

  • 分業しやすい
    デザイナーはView,プログラマーはControllerなど担当者に合った機能を任せることが出来る

  • 仕様変更しやすい
    それぞれの機能が独立しているため、仕様変更の際に特定の箇所だけを修正するだけでいい

所感

いざ自分の言葉で説明すると自分の思っていたよりも理解していないことが分かった。
ただまとめると考えが整理されるため、理解が甘いことはまとめてみることを習慣にする。
また、ただその技術のことを理解するのではなく、その技術がある理由まで考えると納得して使うことが出来る。

参考

【Rails】バージョンを指定してプロジェクトを作成する

  • インストール済みのrailsのバージョンを確認する
$ gem list -e rails

*** LOCAL GEMS ***

rails (6.0.1, 6.0.0, 5.2.1)
  • インストール済みのバージョンを指定してrails newする
# 5.2.1を指定する場合
$ rails _5.2.1_ new app_name
  • 指定したバージョンでプロジェクトが作成されていることを確認する
$ cd app_name
$ rails -v
Rails 5.2.1

なお、バージョン指定がない場合はインストールされている最新バーションでプロジェクトが作成される。 (今回の場合は6.0.1で作成される)

  • 補足
    railsの指定バージョンをインストールする方法
# 4.1.1をインストールする場合
$ gem i -v 4.1.1 rails

gitでリモートにpushするとerror: failed to push some refs toが表示される

環境

  • macOS 10.14.6
  • git 2.23.0

事象

ローカルブランチにfeature/#7_testを作成し、コミット後にリモートへpushした際に以下エラーが発生

$ git push origin feature/#7_test
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 335 bytes | 335.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/seiya2130/git_tutorial.git
 ! [remote rejected] feature/#7_test -> feature/#7_test (cannot lock ref 'refs/heads/feature/#7_test': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/#7_test')
error: failed to push some refs to 'https://github.com/seiya2130/git_tutorial.git'

原因

  • リモート追跡ブランチにremotes/origin/featureが残っていたため

ブランチ名で/(スラッシュ)が使われている場合、スラッシュ内で同名の単語があるとpush出来ない。

git branch -aでブランチを確認すると、リモート追跡ブランチにremotes/origin/featureがあった。

$ git branch -a
* feature/#7_test
  feature/test
  master
  remotes/origin/HEAD -> origin/master
  remotes/origin/feature
  remotes/origin/master
  remotes/origin/test

今回作成したブランチであるfeature/#7_testfeatureの部分が一致してしまい、pushが出来なかった

(同ディレクトリの中に同名フォルダが作れないようなイメージ)

対応

  • 不要なリモート追跡ブランチを削除し、pushする
    1. git remote prune orignでリモートブランチを削除する
    2. git push origin feature/#7_testで再度pushする

参考

Docker/Kubernetes実践コンテナ入門 復習(2)

Dockerコンテナのデプロイ

コンテナでアプリケーションを実行する

  • Dockerイメージ
    • Dockerコンテナを構成するファイルシステム、実行するアプリケーションをまとめた、コンテナを作成するテンプレートとなるもの
  • Dockerコンテナ
    • Dockerイメージから作成され、具現化されたファイルシステムとアプリケーションが実行されている状態

簡単なアプリケーションとDockerイメージを作る

  • DockerfileにはDocker独自のDSL(ドメイン固有言語)で構成を定義する
  • FROMやRUNはインストラクション(命令)と呼ばれる

  • FROM

    • Dockerイメージのベースイメージを指定
    • 取得するイメージはDocker Hubというホスティングサービスに公開されているもの
    • タグを指定することで特定のバージョンのイメージを識別する
  • RUN

    • Dockerイメージビルド時にDockerコンテナ内で実行するコマンド
  • COPY

    • Dockerを動作させているホストマシンのファイルやディレクトリをDockerコンテナ内にコピーする
  • CMD

    • Dockerコンテナとして実行する際に、コンテナ内で実行するプロセスを指定
    • RUNでアプリケーションの更新や配置、CMDでアプリケーションそのものを動かす

Dockerイメージをビルドする

  • Dockerイメージをdocker image buildによりビルドする
    • docker image build -t イメージ名[:タグ名] Dockerfileディレクトリパス
  • -tオプションとイメージ名なしだとハッシュ値で管理ことになるため、必ずつける
  • イメージ名の衝突回避のため、名前空間をつけることを推奨
    • example/test

ENTRYPOINTでコマンドの実行の仕方を工夫する

  • ENTRYPOINTはCMDと同じくコンテナ内で実行するプロセスを指定可能
  • CMDの引数がENTRYPOINTで実行するファイルへの引数となる
  • コンテナの用途を制限したい場合に使用する

Dockerコンテナを実行する

  • docker container run Dokerイメージ
  • -dオプションでバックグラウンド実行

ポートフォワーディング

  • ホストマシンのポートをコンテナポートに紐付け、コンテナの外からきた通信をコンテナポートに転送する(コンテナポートは通常ホストからアクセス不可のため)
  • -p ホスト側ポート:コンテナポート

Dockerイメージの操作

  • Dockerの基本操作はイメージに関する操作かコンテナに関する操作
  • DockerイメージはDockerコンテナを作成するテンプレート
  • DockerfileからDockerイメージを構築することをDockeイメージをビルドするという

docker image build イメージのビルド

  • Dockerfileを元にDockerイメージを作成する
  • -tオプションはイメージ名・タグ名子弟のため必須
  • -fオプションはデフォルトのDockerfile以外のファイルを使う
  • --pullオプションはFROMで指定したイメージをレジストリから取得する(取得ずみでもベースイメージを再取得する)

docker search イメージの検索

  • Docker hubではリポジトリでDockerイメージを管理している
  • docker search オプション 検索キーワードで登録リポジトリを検索可能
    • 表示はSTARSの降順
    • --limit オプションで表示数制限

docker image pull イメージの取得

  • Dockerレジストリからイメージを取得
  • docker image pull リポジトリ[:タグ名]
  • タグを省略した場合、デフォルトのタグが利用される

docker image ls イメージの一覧

  • ホストに保持されているイメージの一覧を表示する
  • docker image ls リポジトリ[:タグ名]
  • docker pull/docker image buildしたイメージ
  • コンテナIDとイメージIDは別物

docker image tag イメージのタグ付け

  • Dockerイメージの特定のバージョンにタグ付けする

    Dockerイメージのバージョン

  • Dockerイメージのバージョン=イメージID(バージョン番号)

イメージIDへのタグ付け

  • タグはイメージIDを持つDockerイメージを識別するためのもの
  • タグを指定しない場合はlatestのタグがつく
  • ビルド後のイメージにもタグ付け可能
    • docker image tag 元イメージ名 新イメージ名

docker image push イメージの公開

  • DockerイメージをDoceker Hubに登録する
  • docker image push リポジトリ名:[タグ]
  • 公開リポジトリのため、パスワードなどの機密情報は含めないようにする

Dockerコンテナの操作

Dockerのライフサイクル

  • コンテナは実行中、停止、破棄の状態がある
  • 作成されたコンテナは同じイメージを利用していても個別に状態を持つ

実行中

  • Dockerイメージからコンテナが作成され、CMDやENTRYPONTで定義したアプリケーションの実行を開始する
  • アプリケーションが実行中ならコンテナは実行中にある

停止

  • 明示的に停止するかコンテナのアプリが終了した場合に自動停止する
  • ディスクにコンテナの状態は残るため、再実行可能

破棄

  • 停止したコンテナは明示的に破棄しない限りディスクに残り続けるため、不要なコンテナは破棄する
  • 一度作成されたコンテナは開始時間などが異なるため、同じ状態のコンテナは作成不可

docker container run コンテナの作成と実行

  • イメージからコンテンを作成・実行する
  • docker container run イメージ名/イメージID コマンド コマンド引数
  • コンテナに名前をつけることで開発時の検証でコンテナIDやコンテナ名を頻繁に確認せずに済む
    • docker container run --name コンテナ名 イメージ名

docker contailer ls コンテナの一覧

  • 実行中および終了したコンテナの一覧を表示
  • docker container ls
  • -qオプションでコンテナIDだけ取得
  • -filterオプションでイメージ名指定など特定のコンテナだけ取得
  • -aオプションで終了したコンテナも含め取得

docker container stop コンテナの停止

  • 実行しているコンテナを終了する
  • docker container stop コンテナIDまたはコンテナ名

docker container restart コンテナの再起動

  • 停止したコンテンを再起動する
  • docker container restart コンテナIDまたはコンテナ名

docker container rm コンテナの破棄

  • 停止したコンテナを削除する
  • docker container rm コンテナIDまたはコンテナ名
  • -fオプションで実行中のコンテンを強制削除が可能
  • docker container run --rmで停止後に自動削除する

docker container logs 標準出力の取得

  • Dockerコンテナの標準出力を表示
  • コンテナ内のアプリケーションがファイル出力したログは確認できない
  • docker container log コンテナIDまたはコンテナ名

docker container exec 実行中コンテナでコマンド実行

  • 実行中コンテナで任意のコマンド実行
  • docker container exec コンテナID/コンテナ名 コンテナ内で実行するコマンド

docker container cp ファイルのコピー

  • コンテナ同士、ホストとコンテナでファイルをコピーする
  • 主にデバッグで使用する
  • docker container cp コピー元 コピー先

運用管理向けコマンド

prune 破棄

  • 実行していないコンテナやイメージを一括削除する
  • docker container prune
  • docker image prune

docker container stats 利用状況の取得

  • コンテナ単位のシステムリソースの利用状況を表示

Docker Composeでマルチコンテナを実行する

docker-composeによるコンテナの実行

  • yaml形式の設定ファイルで複数コンテナの実行を管理できる
  • Dockerイメージのビルドも行い、実行もできる
  • イメージを頻繁に更新する開発時には--buildオプションをつけることでイメージのビルドが必ず実行される

Docker/Kubernetes実践コンテナ入門 復習(1)

Dockerの基礎

Dockerとは

  • コンテナ仮想化技術を実現するために実行される常駐アプリケーションとそれを操作するためのコマンドフロントインターフェース
  • ローカルで環境のセットアップが出来ていれば、コマンド一つで環境構築が可能
  • 仮想マシンより高速でローカル・サーバー間で環境を簡単に再現出来る

Dockerの基礎概念

コンテナ型仮想化技術

  • コンテナ型仮想化技術はDocker登場前はLXC(Linux Container)が有名だった
  • コンテナ型仮想化技術では仮想化ソフトなしでOSのリソースを隔離し仮想OSとするためオーバヘッドが少ない
  • 仮想化ソフトを利用する場合はホストOS型の仮想化と呼び、オーバヘッドが大きくなりがち

アプリケーションにフォーカスしたDocker

  • LXCでは別のLXCホストで実行しようとしてもLXCの設定差異によって動作しない場合があったため、アプリケーションのデプロイ・運用の観点で機能不足だった
  • Dockerはコンテナの情報をコードで管理することで取得・配布が容易で再現性が保ちやすいなど、アプリケーションのデプロイにフォーカスした機能を持っている
  • Dockerはコンテナに実行環境とアプリケーションを同梱しているため、実行環境の依存問題を解決出来る

Dockerを利用する意義

環境際問題からの脱却

  • サーバーの環境差異によって同じ挙動にならないことがあるため、環境際を限りなく排除する必要がある

Infrastructure Code Immutable Infrastructure

  • Infrastructure Code
    • コードベースでインフラを管理する
    • 手作業を介する余地を減らすことで、同じ構成のサーバーを再現しやすくする
    • ただし冪等性(何度実行しても同じ結果が保証される)を保ち続けることは難しい
  • Immutable Infrastructure
    • ある地点のサーバーの状態を保存し複製可能にする考え方
    • 正しくセットアップされた状態を常に使うことが出来る
    • 既存のインフラをアップデートするのではなく、新しく作り直すため、冪等性を気にする必要がない

アプリケーションとインフラをセットで構築する

  • 旧来はインフラとアプリのデプロイは分断された作業だったため、環境差異が生まれやすかった
  • コンテナはOS(インフラ)とアプリをセットでビルドできるため、環境差異が生まれにくい
  • 作成したDockerイメージは保存、再利用が可能なためポータビリティが高い

アプリケーションの構成管理のしやすさ

  • 一定の規模のシステムは複数のアプリやミドルウェアが組み合わさっているため、システム全体の構成管理が必要

Dockerのコンテナオーケストレーションシステム

  • 複数コンテナを利用したアプリの管理のためにDocker Composeというツールがある
  • yamlファイルで実行するコンテナを定義したり、依存関係を定義して起動順を制御する
  • Docker Swarmは複数のサーバーをまたいで複数のコンテナを管理できる(コンテナオーケストレーション)

本番環境に導入してこそのDocker

  • オーバヘッドの少なさ、スケールアウトのしやすさから世界中のプロダクションで利用されている
  • クラウドプラットフォーム(AWS,GCP)でもコンテナを運用するツールが整備されている

新しい開発スタイルへ

  • Dockerの普及でインフラがコードレベルで簡単に修正できるようになった
  • インフラエンジニアとサーバーサイドエンジニアの垣根がなくなりつつある
  • 現代的な開発のためにフロントエンドやスマホアプリエンジニアにも必要な技術になりつつある

入門docker 復習(8)

プロダクションでの活用

プロダクションへの導入

  1. ローカル環境のDocker化

    • チームの開発環境を統一する
  2. テスト/CIへの導入

  3. ステージングへの導入
    • 本番前に動作確認する
  4. 本番への導入

Tips

docker-compose

環境変数への読み込み

  • docker-composeの起動時に渡す
    • docker-compose up -e MYSQL_PASSWORD=mypassword
  • docker-compose.yamlへ記述
version: '3.7'

services:
  app:
    build: .
+   environment:
+     - MYSQL_PASSWORD=mypassword  
  • シェル変数から読み込み
version: '3.7'

services:
  app:
    build: .
    environment:
-     - MYSQL_PASSWORD=mypassword
+     - MYSQL_PASSWORD=${MYSQL_PASSWORD}
$ export MYSQL_PASSWORD=mypassword
$ docker-compose up
  • ファイルから読み込む
version: '3.7'

services:
  app:
    build: .
-   environment:
-     - MYSQL_PASSWORD=mypassword
+   env_file:
+     - .env
#.env
MYSQL_PASSWORD=mypassword
$ docker-compose up

ホストとコンテナ間のファイル共有の速度向上

オプション

  • consistend(default)

    • ホストとコンテナ間の一貫性を担保するオプション
    • オーバーヘッドが大きいため、ファイルの更新が発生する場合は非推奨
  • cached

    • ホストの更新を優先する
    • サービスコードのようにホスト側で更新するケース
  • delegated

    • コンテナ側の更新を優先する
    • MYSWLのようにコンテナからホストへの書き込みしかしないケース
    • コンテナ上からライブラリのインストールをするコマンド(composer install,npm install)を使用する場合

標準入力を有効にする

  • デバッグに使用したい場合、明示的に設定可能
  services:
    rails:
      build: .
  +   tty: true
  +   stdin_open: true
      ports:
        - '3000:3000'
      volumes:
        - './:/app:cached'

Multi-Stage Buildのローカル活用

  • 過去のレイヤーを使用したい場合、明示的に設定可能
ersion: '3.7'

services:
  app:
    build:
      context: .
+     target: build
    volumes:
      - ./:/go/app
    command: go run main.go

docker-compose間のnetworkの共有

  • マイクロサービス化によってフロントとバックバックエンドでリポジトリが異なる場合がある
  • ネットワークを共有する必要がある

backend

  • internalとexternalのネットワークを用意する
    • internalはリポジトリ内の内部的な通信ネットワーク(MySQLのようにデータストアを不用意に用意しないために使用)
    • externalはリポジトリ外へ公開するためのネットワーク
version: '3.7'

services:
  api:
    build: .
    ports:
      - 8000:80
+   networks:
+     - internal
+     - external

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
+   networks:
+     - internal

+networks:
+  internal:
+    internal: true
+  external:
+    name: api_network

web

version: '3.7'

services:
  web:
    #XXX APIアクセスはcurlで代用。
    image: amazonlinux:2
    command: curl api:80

+networks:
+  default:
+    external:
+      name: api_network

入門docker 復習(7)

プロダクションでの活用

オーケストレーションツール

オーケストレーションツールとは

  • 複数のDockerを扱うための技術
  • 主に以下の機能をもち、本番のワークロードに必要な機能を備えている
    • Dockerの管理/自動復旧
    • ネットワークの管理
    • オートスケール

代表的なオーケストレーションツール

docker-compose

概要

  • docker-composeはローカルでDockerのオーケストレーションを行うツール
  • DockerのビルドからNetworkやVolumeの管理をコードベースで定義して行う

サンプル

version: '3.7'

services:
  nginx:
    build:
      context: .
      dockerfile: docker/nginx/Dockerfile
    volumes:
      - ./public:/var/www/html/public:ro
    ports:
      - 8080:80
    environment:
      PHP_HOST: app

  app:
    build:
      context: .
      dockerfile: Dockerfile
    env_file:
      - .env.example
    # volumes:
    #   - .:/var/www/html:cached

  mysql:
    image: mysql:5.7
    volumes:
      - ./mysql:/var/lib/mysql:delegated
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    ports:
      - 13306:3306
  • version

    • docker-composeのバーション
    • こだわりがなければ最新を記述
  • services

    • 起動するコンテナの定義
    • ngix,app,mysqlを定義
  • image

    • コンテンを起動するDockerImageを指定
  • build

    • docker buildの実行情報
    • この情報をもとにDockrをビルドし、ビルドしたイメージを使用してコンテナを起動する
    • imageまたはbuildどちらかを記述
  • volumes

    • ボリュームのマウントを行う
  • ports

    • ポートの解放を行う
    • 左にホスト、右にコンテナのポートを指定する
  • environment

  • env_file

    • ファイルに記載された環境変数を読み取り、コンテナに定義する
  • command

    • Dockerfileで定義されているCMDの上書きを行う

docker-composeのコマンド

  • up

    • カレントのdocker-compose.yamlを参照してdocker-composeの起動
      • docker-compose up
  • down

    • カレントのdocker-compose.yamlに紐づいているContainerとNetworkを削除
      • docker-compose down
    • イメージも削除
      • docker-compose down --rmi all
  • rm

    • Volumeを削除
      • docker-compose rm