ログファイルからをバッチ処理を行う非コンテナアプリケーションをECSでサイドカーパターンとService Discoveryを使ってコンテナ内ロギングをする
概要
Dockerコンテナでアプリケーション構築するメリットは皆さんご周知ではあると思いますが、EC2でアプリケーションを公開していてECSなどのコンテナ基盤に乗り換えた時に、EBSやEFS等のlinuxファイルシステムに依存している部分をコンテナ上でどうするかという問題に直面します。
今回はその問題のうち、アクセスログファイル等を集計してDBに入れたいというありがちな問題をService DiscoveryとFluentdコンテナのサイドカーパターンで解決する手法を実践します。
そもそもなぜコンテナ内のファイルシステムに保持してはいけないか
Dockerfile が定義するイメージによって生成されるコンテナは、できる限り "はかないもの"(ephemeral)と考えておくべきです。 "はかない" という語を使うのは、コンテナが停止、破棄されて、すぐに新たなものが作り出されるからです。 最小限の構成や設定があれば稼動できます。
とあり、更にGCPのコンテナ運用のベストプラクティスによると、
初めてコンテナを試している場合、従来のサーバーのようにコンテナを扱わないでください。たとえば、実行中のコンテナ内でアプリケーションを更新したり、脆弱性が発生したときに実行中のコンテナにパッチを適用したりしたくなるかもしれません。
コンテナは基本的に、このような処理に対応するように設計されていません。コンテナは、ステートレスかつ不変になるように設計されています。
コンテナは基本的に、このような処理に対応するように設計されていません。コンテナは、ステートレスかつ不変になるように設計されています。 とあり、コンテナ内では状態を持たない = ステートレス であることがかなり推奨されています。 コンテナ内で作られたファイルをコンテナ内で持ってしまうと、コンテナが破棄され次世代のコンテナが立ち上がった際に生成したファイルが無いので実質欠損するという事態が起こりえます。 これを回避するためにデータストアに格納することが推奨されていますが、今回はDockerの永続化Volumeを使ってデータを退避させます。
コンテナ基盤を使って運用するときの普通のロギング
ECS、kubernetesなどのコンテナ基盤を使う場合、Dockerの標準ログドライバーを使うことが推奨されています。
主に、docker logs
やkubectl logs
で見れる標準出力のログをどこかに集約させるという手法です。
大体各種クラウドにはコンテナ基盤に付随してロギングを集約させるマネージドサービスが搭載されていると思うのでそれを使ってデータストアに入れるパターが王道だと思います。
ただ、これらはアプリケーション側でログ出力の整備を行わなければ成立しません。今回はその整備にコストがかかる場合、既存のロギングシステムを残しつつ、コンテナ環境でどう再現するかの手法です。
構成図
コンポーネント
- ECS
- サービス検出(Service Discovery)
- nginx, app, batch
- Fluentd公式イメージ
- RDBやその他データストア
App Serviceの構築
メインのアプリケーションコンテナは複数コンテナ存在し、Fluentdのログコンテナは単一コンテナとしてログを集約させます。 App Serviceは通常通りnginx containerからunix socketsを介してapp containerに接続します。これに関してはこちらの記事を参照して構築していきます。 https://qiita.com/na-o-ys/items/1a863419e1f6c3063ace App Serviceに関してはもう構築できている前提で話を進めていきます。
Log Serviceの構築
Log Serviceですがこちらは別サービスになっているのでscalingはせず、単一サービスとして構築します。 まず、Log Service用のタスクはport mappingは指定せず、Dockerfileでコンテナ側でのみportを開いてください。
"portMappings": [], "networkMode": "awsvpc",
単一サービスですのでタスクの数は1、最小ヘルス率は0、最大率は100としてタスクの重複を許さないようにします。
それと、今回はタスクのnetworkmodeはawsvpc
に設定します。
続いてサービス検出の設定ですが、名前空間名は好みで変えても良いですが、慣習としてxxx.local
xxx.internal
という名前空間が使われやすいです。
サービスの検出名も好みで良いですが、分かりやすくfluentdのコンテナ名にします。
private DNSレコードは今回はAレコードを作成するようにします。
注意点としてタスクのnetworkmodeがawsvpc
じゃない場合Aレコードが作成できないと思います。
代替としてSRVレコードが用意されていますがこちらは動的ポートマッピングを使用する為、既存のログプラグインで対応できない可能性があります。
awsvpc
はENIをアタッチされてるのでAレコードからportを指定して接続ができるようになります。
ENIをアタッチする関係上インスタンスを制限されるデメリットもありますが、ネットワークパフォーマンスの観点からもECS全体でawsvpc
が推奨されます。
以上でサービスを構築するとService Discoveryによるprivate DNSでのコンテナアクセスが可能になります。
タスク上でport mappingせずともdnsとportを指定して通信ができるようになったかと思います
root@21454022290b:/# dig fluentd.local ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.amzn2.0.4 <<>> fluentd.local ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;fluentd.local. IN A ;; ANSWER SECTION: fluentd.local. 10 IN A 172.31.0.54 ;; Query time: 1 msec ;; SERVER: 172.31.0.2#53(172.31.0.2) ;; WHEN: 木 7月 09 20:15:59 UTC 2020 ;; MSG SIZE rcvd: 60
ログプラグインでもportを指定して接続ができるようになっているかと思います。
host: fluentd.local port: 24224
これでログ集約サーバーの出来上がりです。
サイドカーパターンでログファイルを処理する
fluentdにより生成されたログファイルを用いてbatch containerで処理したい場合、サイドカーパターンでvolumeを共有して永続化する必要があります。
まずfluentdのDockerfileでvolumeのpathを指定してあげます。
VOLUME /fluentd/log/xxx
注意点はコンテナ内の実行ユーザーによってはvolumeディレクトリに書き込めない場合があるので、適宜書き込み権限を追加してください。
続いて、batchをサイドカーパターンでvolume共有したタスクを用意します。
[ { "name": "fluentd", "image": "xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-fluentd:e6767fd9", "cpu": 400, "memoryReservation": 400, "essential": true }, { "name": "batch", "image": "xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-batch:e6767fd9", "cpu": 400, "memoryReservation": 400, "essential": true, "volumesFrom": [ { "readOnly": false, "sourceContainer": "fluentd" } ], "dependsOn": [ { "containerName": "fluentd", "condition": "START" } ] } ]
ポイントはvolumesFrom
を指定してあげて書き込み処理をしたい場合はreadOnly: false
にすることです。
念のため、もしfluentd containerの起動が遅れた状態でにバッチ処理が走らないようにdependsOn
で起動を待つ指定もしておきます。
また、batchコンテナ内のユーザーにも書き込み権限を追加するようにしてください。
今回自分が実践したbatchはcronで回すタイプだったのでcron -f
で定期実行していますが、何かしらのトリガーで無事ログファイルのbatch処理が正常に走れば完成です。
オブジェクト指向設計実践ガイドを読んだ所感
Sandi Metsのオブジェクト指向設計実践ガイドを読みました。
翻訳された書籍なので英文特有の言い回しだったり、冗長的に思える文もあったのですがじっくり理解しながら完読しました。
本文の構成は最初は一つのクラス単位の解説から始まっていき、章を進めていくにごとに他のクラスが登場したりして順序よく段階的に進められていきます。
最初は単一責任について述べ、その次にクラス間の連携をした際に発生する依存性をどうやって管理するかであったり、そのあとはクラス内のインターフェースの管理方法だったり、継承を用いたデザインパターンを紹介したり等、随所に設計原則やデザインパターンの解説が埋め込まれています。
原則やデザインパターンから実装を説明するのでは無く実装から原則やデザインパターンに当てはめていくといった文章構成になっています。(原則の名前すら出てこないで解説される時もあるので逆に原則を説明したいといった時は他の書籍を読んで把握していくといいと思います)
僕は一番関心を持ったのはRubyの動的型付けを生かしたダックタイピングによる依存関係の管理(ポリモーフィズム)と継承の際のテンプレートデザインパターンです。
オブジェクト指向による強力な設計が記載されてる反面、これを上手くRailsのプロジェクトに全て適応出来るかどうかと言うのはちょっと一発本番では難しいと思ってます。もう少し実際に程よく大きなRailsプロジェクトのコードを書くときに少しずつ実践したいです。
正直、今Rubyを仕事で使っている人の中でも上手く設計原則やデザインパターンを完璧に扱えているかと言うとそんな気はしないのでやっぱりこういう書籍を読んで自主的に動いていかないとダメですね。
AWSでwebサービスを構築する上で最低限知っておきたいネットワークの基礎知識
AWSではネットワークの知識は欠かせません。
インターネットで世界基準で定められてる通信規約としてOSI参照モデルとTCP/IPプロトコル・スイートという規約があり、これを網羅して学習すればPC間でどうやって通信しているのか、ネットワークの構造は理解できます。
今回はTCP/IPプロトコル・スイートの中でwebサービスを構築するにあたり、知っておかないと苦労するものを説明します。
OSI参照モデルとTCP/IPプロトコル・スイートの詳しい解説はこの記事ではしませんが、その中で何を主軸に置いて勉強すればいいのかは分かるかと思います。
オレンジ色に塗られている部分がAWSで特に意識する部分です。
TCP/IPのアプリケーション層ではWebサーバーやWebプログラム担当範囲でAWSに任せる担当ではありません。(唯一どのプロトコルをWebサーバーに投げるかというのを意識する必要があるのでプロトコル名だけは知る必要があります)
ネットワークインターフェース層はハードウェアに責任を負わせる部分でAWS側でよしなになってくれるので知っておく必要はありません。
AWSのサービス毎に説明します。
VPC
AWSアカウント内に自分だけのネットワークを構築するサービスです。 主にインターネット層での知識が必要になります。 VPC本体やサブネットの領域の割り当て、ルートテーブル、インターネットゲートウェイ・NATゲートウェイのルーティングなど、一番ネットワークの知識が要求されるサービスです。 IPとサブネットマスクの知識、CIDR表記等を知らないと構築するのは難しいです。
Route53
DNSの登録や管理をするサービスです。 こちらも主にインターネット層の知識が必要になります。 DNSの登録、DNSレコードセット、DNSのマウントなどIPの知識と共に、DNSレコードの意味を理解してないと難しいかと思います。
ELB、ALB
ロードバランサー(負荷分散システム)を提供するサービスです。 Webサービスの場合ALB(Application Load Balancer)を使うことになると思います。 こちらはインターネット層とトランスポート層とプロトコル名の理解が必要になります。 リスナーからターゲットのポートを指定したりなど特にトランスポート層の知識が必要になります。 (ECSなどのコンテナへ接続したい場合、動的ポートマッピングという少し特殊な設定をしたりします)
EC2、RDSなどの各インスタンス
ネットワーク内でいうPC本体を提供するサービスです。 RDSはサービスとして抽象化されていますが実体はPC内のソフトウェアなのでIPアドレス自体は持っています。 webサーバー等でALBからのリクエストを受け付けるのでトランスポート層とプロトコル名の理解が必要になります。 SSHでインスタンスに接続したりもします。
以上です。
AWSのサービスを使うにあたり、ネットワークの知識が足りてないと構築に手も足も出ない反面、知っているとすんなりサービスを理解できたりするのでやはり何かネットワークを体系的に学べる書籍等で勉強してから構築した方がいいかと思います。
0からネットワークを理解するなら以下のスラスラわかるネットワーク&TCP/IPのきほんがイラスト付きでわかりやすいと思うので是非読んでみてください。(自分はこれだけでは物足りなかった&もっと深掘りをしたいと思ったので次回はマスタリングTCP/IPを購入予定です)
- 作者: リブロワークス
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2018/03/17
- メディア: Kindle版
- この商品を含むブログを見る
- 作者: 竹下隆史,村山公保,荒井透,苅田幸雄
- 出版社/メーカー: オーム社
- 発売日: 2012/02/25
- メディア: 単行本(ソフトカバー)
- 購入: 4人 クリック: 34回
- この商品を含むブログ (37件) を見る
Rubyチートシート
先日、Rubyの復習や深掘りをしたかった為、「プロを目指す人のためのRuby入門」を読み返しました。
読み返して見ると初回に読んだ時では理解し難い部分がすんなり理解できたり、あまり触れることが無く忘れていたメソッドや記法を改めて再認識できたので読み返すのもありですね。
ただ読み返すだけだとつまらないので自分なりに重要なところを纏めたチートシートを作って見ました。
そのまま引用してる部分も多いですが、そこはご容赦ください。
ファイルとして保存してあるので今後はこれで修正改善しながら見たらすぐ思い返せるようなノートに仕上げていきたいですね。
「プロを目指す人のためのRuby入門」はRubyを学ぶなら読んで損は無い良書なのでまだ読んでない方は是非読んでみてください。
全てがオブジェクト 文字列、配列はもちろん、数値、nil、true、falseもオブジェクト メソッドの呼び出し オブジェクトのメソッドを呼び出し object.method(引数1, 引数2, 引数3) 引数のカッコ省略 object.method 引数1, 引数2, 引数3 引数なし object.method 文の区切り 改行、セミコロンが文の区切り。 1.to_s nil.to_s; 10.to_s(16) カッコが締められてない、バックスラッシュで文はまだ続く 10.to_s( 16 ) 10.to_x \ 16 リテラル 数値 123 文字列 'Hello' %q(Hello) %s(Hello)←シンボル 文字列(変数展開可) "Hello" %(Hello) シンボル :hello :'hello' :'123' 配列 [1, 2, 3] %w(1 2 3) %W(1 2 3)←変数展開可能 配列(シンボル) [:Ruby, :Python, :PHP] %i(Ruby Python PHP) ハッシュ {'japan' => 'yen', 'us' => 'dollar', 'india' => 'rupee'} ハッシュ(シンボル) {japan: :yen, us: :dollar, india: :rupee} 正規表現 /[\w\d]+/ バックスラッシュでエスケープ 変数宣言と配列操作 変数宣言 s = 'hello' 同時代入 a, b = 1, 2 配列へ追加 ary << 3 配列展開 [1, 2, *ary] #=> [1, 2, 1, 2, 3] 変数の種類 ローカル変数 name スコープ内のみ参照可能 定数 NAME クラス内だとどこでも参照可能 クラス外は Class::NAME Module::NAME の形で参照可能 Rubyでは書き換え可能なので.freezeメソッドを使うかマジックコメントを使う インスタンス変数 @name インスタンスメソッドのみ参照可能 クラスインスタンス変数 @name クラス直下とクラスメソッドのみのみ参照可能 クラス変数 @@name クラス全体とそのクラスの親子メソッド全てのみ参照可能 グローバル変数 $name どこからでも参照可能 組み込み変数、定数 $ Rubyが定義した変数、元から持っている定数 環境変数 ENV['name'] OS、マシンが持っている環境変数 命名規則 スネークケース 変数名、メソッド名、ファイル名 キャメルケース クラス名、モジュール名 すべて大文字 定数 比較演算子 ==, !=, <, >, <=, >= 真偽値と条件分岐 基本形if if 条件式 && 条件式 || 条件式 trueの処理 elsif 条件式 trueの処理 else falseの処理 end 一行で書く(Guard句) trueの処理 if 条件式 三項演算子 条件式 ? trueの処理 : falseの処理 true falseだけ返したいとき !!条件式 ifの逆、unless unless 条件式 falseの処理 end case文 case 対象 when 条件 trueの処理 end 範囲(Range) 1..5 'a'..'e' ...を使うと5が範囲に含まれない(1以上5未満) 1...5 繰り返し処理 each map select find inject 配列に対して times upto downto step 数値に対して ループ処理 loop do #breakされるまで break #処理から抜け出す end while 条件式 #真だったら実行 next #次の周回へ redo #今の周回をやり直す end until 条件式 #偽だったら続行 end for 変数 in 配列やハッシュ #eachメソッドと一緒 使わぬように end 大域脱出 catch :done do throw :done end クラス サンプル class User DEFAULT_PRICE = 100 @pet = 'cat' attr_accessor :name, :price def initialize(name, price) #newの際にこれが呼ばれる デフォルトでprivateメソッド # 初期化処理 @name = name #newの引数をインスタンス変数に代入 @price = price end def hello #インスタンスメソッド "Hello, I am #{@name}." end def self.this_class #クラスメソッド "Userクラス" end end クラスの定義 class User end オブジェクトの作成 user = User.new('Alice', 100) インスタンスメソッドの定義 def hello #インスタンスメソッド "Hello, I am #{@name}." end 以上のように普通にメソッドの定義を行うとインスタンスメソッドになる インスタンスメソッドの呼び出し user.hello #=> "Hello, I am Alice." アクセサメソッド attr_accessorがアクセサメソッド、以下の二つを併せ持つ attr_writer セッターメソッド def name=(value) @name = value end user.name = 'Alice' 以上のようにインスタンス変数に代入するメソッド attr_reader ゲッターメソッド def name @name end user.name #=> "Alice" 以上のようにインスタンス変数を外部から参照するメソッド クラスメソッドの定義 def self.this_class "Userクラス" end メソッド名にself.をつけるとクラスメソッドになる class User class << self # ここにクラスメソッドを定義(selfなし) end end 以上のようにすることでself.をつけなくても定義が可能 クラスメソッドの呼び出し User.this_class クラス名から呼びだす メソッド名の表記法 インスタンスメソッドの表記法 "User#hello" クラスメソッドの表記法 "User.this_class" "User::this_class" 定数の呼び出し クラス内であれば DEFAULT_PRICE クラス外であれば User::DEFAULT_PRICE selfキーワード クラス直下だとクラス自身 User クラスメソッド内もクラス自身 User インスタンスメソッド内だとそのクラスのインスタンスを表す <User:0x007fbffc094070> なのでインスタンスメソッド内ではセッターメソッドの呼び出し時のみつける クラス内の定数やメソッド呼び出し クラス直下から呼び出す場合 定数 DEFAULT_PRICE クラスメソッド self.this_class インスタンスメソッド 呼び出せない クラスインスタンス変数 @pet クラスメソッドから呼び出す場合 定数 DEFAULT_PRICE クラスメソッド self.this_class インスタンスメソッド 呼び出せない クラスインスタンス変数 @pet インスタンスメソッドから呼び出す場合 定数 DEFAULT_PRICE クラスメソッド User.this_class インスタンスメソッド hello クラスインスタンス変数 呼び出せない クラスの継承 class DVD < Product; end 継承する場合is_a関係を意識する(AはBである) メソッドのオーバーライド スーパークラスのメソッドと同名のメソッドを定義することでオーバーライドできる superでスーパークラスの同盟のメソッドを呼び出せる メソッドの公開レベル キーワードを記述した下のメソッドに適用される public クラス内外から自由に呼び出せる initialize以外はデフォルトでpublic private クラス外からでは呼び出せない(レシーバ付きで呼び出せない) インスタンスメソッドはprivate :hello のように引数を渡せば後から設定可能 クラスメソッドをprivateにしたい場合 ①class << self 構文の中でprivateキーワードを使う ②private_class_method :hello 構文を使い設定(定義した後) protected クラス外からでは呼び出せないがクラス内であればレシーバ付きで呼び出せる protected :hello で後から設定可能 エイリアスメソッド メソッドを定義した後、 alias greeeting hello alias エイリアスにしたいメソッド 元のメソッド メソッドの削除 undef hello 特異メソッド 指定したオブジェクトのみ呼び出せるメソッド def alice.shuffle # 処理 end モジュール モジュールの定義 module Greeter; end モジュールの活用方法5つ ①インスタンスメソッドとしてミックスイン ②クラスメソッドとしてミックスイン ③名前空間 ④関数や定数の集まりとして定義 ⑤設定値の保持 ①②ミックスイン module Greeter def hello 'hello' end end インスタンスメソッドとしてミックスイン include Greeter 特異メソッド(クラスメソッド)としてミックスイン extend Greeter メソッドの優先度を変えつつインスタンスメソッドとしてミックスイン prepend Greeter ミックスイン先の同名メソッドよりモジュールのメソッドが先に呼ばれるようになる メソッドの探索順位はancestorsメソッドで確認 クラスと同じでprivate, protectedその他機能が有効 ③名前空間 module Clock class Second; end end もしくは module Clock; end class Clock::Second; end モジュール外から該当モジュールにに属するクラスの呼び出し Clock::Second.new モジュール内から Second.new モジュールに属してないトップレベルの同名クラスの呼び出し ::Second.new ④関数や定数の集まりとして定義 module Loggable def self.log # 処理 end end もしくは module Loggable class << self def log # 処理 end end end モジュールの特異メソッドとして呼び出し Loggable.log モジュールの特異メソッドとして機能させつつ、ミックスインとしても使う module Loggable class << self def log # 処理 end end module_fuction :log end モジュールに定数を定義 module Loggable PREFIX = '[LOG]'.freeze end ⑤設定値の保持 gemなど、設定値を一元管理する為にだけ使用するパターン module AwesomeApi @base_url = '' @debug_mode = false class << self attr_accessor :base_url, :debug_mode end end 設定値の保存 AwesomeApi.base_url = 'http://example.com' AwesomeApi.debug_mode = true 設定値の呼び出し AwesomeApi.base_url AwesomeApi.debug_mode 例外処理 例外の補足 begin 例外が発生するかもしれない処理 rescue => e retry #処理をやり直す 例外が起こった場合の処理 else 例外が発生しなかった場合の処理 ensure 例外が有無に関わらず実行する処理 end rescue => eとすることでeに例外オブジェクトが入る e.class 例外のクラス e.message 例外のメッセージ e.callback 例外が起こった時のバックトレース 処理をやり直す retry 無限ループに注意 else あまり使われない 理由としてはbegin内でカバーできる為 ただし、else節は補足されないという点が違う ensure 終了する前に必ず実行したい処理がある時に使う returnは絶対に使わないこと(例外を握り潰す) メソッド内ではbegin, endを省略可能 def method 例外が発生するかもしれない処理 rescue => e retry #処理をやり直す 例外が起こった場合の処理 end 例外を発生させる raise ArgumentError, "引数が無効です #{argument}" 第一引数に例外クラス、第二引数にメッセージ 独自の例外クラスを作る class NoCountryError < StandardError end 必ず、継承元をStandardErrorにすること
ECSでEC2インスタンスを選択する場合はEC2インスタンスタイプに配慮すること
ECSではFargateとEC2の二つの起動タイプがある。
FaegateはともかくとしてEC2を選択する場合はEC2インスタンスタイプのCPU及びメモリといったリソースを十分考慮しながら設計する必要がある。
ECSではタスク定義で動かすコンテナが使えるメモリを割り当てられるが(ハード/ソフト制限)、ここで定義されるリソースはEC2インスタンスのリソースの範囲を超えてはならない。
今回は無料枠で使えるt2.microインスタンスタイプで説明する。
t2.microインスタンスタイプはメモリが1GiBである(1GiB = 1024MiB)
つまりコンテナには1024MiBを超えるメモリを割くことができない。
じゃあ1024MiB割り当てればいいと思うかもしれないが、ローリングアップデートの事も考えなければならない。
ローリングアップデートでは2つのタスクが共存する瞬間があるのでその間2倍のメモリを使うことになる。
なので二分の一で512MiG割り当てればいいと思うかもしれないがこれも違く、ギリギリのメモリリソースでタスクを実行しようとすると、安定せずデプロイが失敗する可能性がある。
なのである程度余裕を持たせて設計する必要がある。
自分はt2.microインスタンスに300MiGのコンテナを割り当てることでデプロイが安定した。
t2.microインスタンス(1024MiG) > コンテナ(300MiG) + ローリングアップデート用のコンテナ(300MiG) + 余白
これのタチの悪いところはわかりやすくアナウンスされないところだ。
run task cli を叩いてもRESOURCE:MEMORY
しかアナウンスされずどこのメモリが足りないかわからなかった。
Dockerのコマンドを理解する
概要
Dockerのコマンドが何をしているかを自分なりに簡潔に解説します。
対象者
- Dockerの概念はなんとなく理解できたけど自分で環境構築ができない方
- とりあえずコマンドは知ってるけど詳しく何をやっているかわからない方
なぜ書こうと思ったのか
自分はDockerで開発環境で構築できたが学習の際、技術記事を見て回ったがDockerの概念を説明する記事やDockerで開発環境を構築するチュートリアル的な記事は数あれど、具体的にDockerのコマンドに注力して解説してる記事が少なかったので初学者の助けになればと思い寄稿しようと思いました。 また、難しい概念抜きにしてをコマンド一つ一つを簡潔に理解することによって学習が捗ったので今回は「簡潔に」をテーマとして書いていきます。
注意点
解説記事によってはdocker buildだったりdocker runとして解説している記事がありますが、厳密にはdocker image build docker container runです。
image、containerを記載することで何に対して実行しているコマンドなのかを理解できる為、今回は省略せずに解説します。
解説
docker images
現在自分のマシンが持っているDockerイメージの一覧を表示する
docker image pull (イメージ名)
DockerHubにあるイメージを自分のマシン上にダウンロードする
docker image build (-t イメージ名:タグ名) (Dockerfileのディレクトリのパス)
Dockerfileを元にイメージを作成する -tオプションを付けることで自分の好きな名前をつけられます さらに-fオプションを付けることでファイル名がDockerfileでないファイルを指定できます。 (-f ファイル名)とすることでそのファイル名を指定します。
docker container run
イメージからコンテナを作成、実行する
docker container ls (-a)
実行中のコンテナの一覧を表示する -aで終了したコンテナを含む一覧を表示する
docker container stop (コンテナIDまたはコンテナ名)
実行しているコンテナを終了する
docker container restart (コンテナIDまたはコンテナ名)
コンテナの再起動
docker container rm (コンテナIDまたはコンテナ名)
コンテナの破棄
docker container logs
Dockerコンテナの標準出力を表示
docker container exec (コンテナIDまたはコンテナ名) (コンテナ内で実行するコマンド)
実行中のコンテナでのコマンド実行
docker container cp (コンテナIDまたはコンテナ名):(コンテナ内のコピー元) (ホストのコピー先)
ファイルのコピー、コンテナ間でのファイルのやりとりのために使用
ActiveAdminのスタイルが他ページまで影響してしまう。
Active Adminという管理画面作成用のgemを入れるとき、Active AdminのCSSが他のページにまで影響してしまうという問題が起こった。
以上の方法で回避。
何をしているかというと
まずadminというフォルダにActiveAdmin関係のフォルダを用意
*= require_tree . // ディレクトリ内のすべてのファイルを読み込み ↓ *= requiire_directory . // ディレクトリ直下のファイルのみ読み込み
に書き換え
ActiveAdmin側の設定でadminフォルダ内のファイルを読み込むように設定
ということだそうだ
アセットパイプライン周りの知識が薄いと感じたのでそれはまたあとで復習することにしよう。