iOSライブラリ管理ツール「CocoaPods」について

CocoaPodsとは

iOS/Mac向けのアプリを作成する際のライブラリ管理をしてくれるもの。Rubyで作られている。 これによって、プロジェクトに必要なライブラリの管理を簡潔にできる。

PodfileとPodfile.lockの違い

  • Podfile・・・プロジェクトファイルが存在するディレクトリを指定して、pod initを行うとPodfileファイルが自動生成される。ここにそのプロジェクトでインストールすべきライブラリが記述される。新規にライブラリを追加したいときは、ここに追記してpod installすればいい。

  • Podfile.lock・・・インストールすべきライブラリのバージョンを固定して、開発者別にことなるライブラリをインストールすることに生じるコンフリクトを防ぐ。pod installの後に作成される。

pod installとpod updateの違い

  • installはPodfile.lockを見て、インストールする
  • updateはPodfile.lockを無視してインストールする。さらにPodfile.lockを更新する

基本は、pod installになるだろう。

作業中、もしあるライブラリで勝手にPodLock.fileが変わったら、バージョンがズレたライブラリは一旦アンインストールしてバージョンを指定してインストールすればいい。

例えば

Podfile.lockでCOCOAPODS: 1.10.1 -=> 1.12.1となり、意図しない差分が出たとき、以下のようにすればいい。

gem uninstall cocoapads
gem install cocoa -v 1.10.1

この後pod installする。

AWS ECSにおける重要用語

ECSにおける単語の説明

クラスタ

複数のEC2インスタンスで構成されている。ECSはクラスター全体でのCPUやメモリの使用量を把握するようにしている。

コンテナインスタンス

ECSでは、クラスター管理下にあるEC2インスタンスをコンテナインスタンスと呼ぶ。

タスク定義(タスクとは別)

アプリケーションがどのようなDockerコンテナで構成されるかをタスク定義に記述する。タスク定義された1つ1つがアプリケーションである。docker-compose.ymlに似ている。

アプリケーション全体の構成などを1つのタスク定義にまとめることもできるが、合理的ではない。タスク定義はそれ単位で、EC2インスタンス上で起動するからである。タスクには、Elastic searchのインデックス更新や支払い期限通知のメール送信などがあるが、それらも1つずつが別のEC2インスタンス上のコンテナで起動している。アプリケーションサーバーを起動する「bundle exec rails s」も1つのタスクとして扱われる。

タスク定義には、以下のような項目がある。

  • 利用するDockerイメージ
  • 開始時、コンテナ内部で使う環境変数
  • 開始のために実行するコマンド(bundle exec rails sなど)
  • コンテナでのCPUやメモリの使用量

これらを更新すると、履歴が残る。

タスクとサービス

タスク定義に書いたアプリケーションを起動させる手段として、タスクとサービスの2つがある。

  • タスク・・・バッチ処理や一時的な処理のために使う。大量のデータ更新のタスクとか。タスクの終了後、それが動いていたコンテナはkillされる。
  • サービス・・・長期的に動作する必要がある処理のために使う。サーバーを起動させるタスクとか。

コンテナとコンテナオーケストレーション

参考サイト AWS Fargateとは?Amazon ECSとの関係性やメリット・デメリットを解説|コラム|クラウドソリューション|サービス|法人のお客さま|NTT東日本

コンテナ

そもそもアプリケーションが実行されるには、ソースコードの他にもgemのようなライブラリやパッケージ、ミドルウェアなどが必要になる。それらにはバージョンの依存性があって、開発者が各自で実行環境を整えようとすると、環境の違いなどから各々の不整合などが起きやすい。

そこで、ソースコードやライブラリ、ミドルウェアなどをまとめコンテナに詰め込み、このコンテナで運用することで開発環境も本番環境も同じ環境にすることができる。各自の開発者の環境の違いも影響しなくなる。

ローカル・本番・ステージングによって異なる値、例えばDBのユーザー名やパスワード、外部APIのURLなどは外部から環境変数として渡すのがよいとされている。それぞれの環境にenvファイルを置いて、そこに書き込むなどがあるだろう。

なお、1つのDockerの管理するスコープとしては単一のホストマシン上となる。ゆえに、複数のホストマシンにまたがるような配置などの場合は別の仕組みとして実装しなければならない。

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

複数のホストマシンにまたがるコンテナの配置やコンテナのアップデート、ロードバランサーへの紐付けなどを管理する。ECSは代表的なツールである。「あのEC2インスタンス上でコンテナを実行したい」「このコンテナとあのコンテナをロードバランサーにつなぐ」といった指示を出すことができる。

Fargateの登場

ここである問題が発生する。コンテナとそのホストマシン両方を管理しなければならないという問題である。この二重管理の問題を解決すべく、Fargateがある。FargateはAmazon Elastic Container Service (ECS) と Amazon Elastic Kubernetes Service (EKS) で動作する、ホストマシンを意識せずにコンテナを実行できる環境である。Fargateを利用すれば、コンテナとホストマシンの2重管理が不要になる。また、ローカルで利用したコンテナをそのまま本番環境に適用できる。

AWS FargateとAmazon ECSの違いと関係性

ここで気になることがある。ECS, Fargateはどう違うのかという疑問である。双方は連携している。ECSでコンテナを実行する方法として、Fargateを使うというのがある。

ECSではコンテナを起動する手段として、

  • EC2
  • Fargate

の2つがある。EC2では、ホストマシン上でコンテナが起動するので、コンテナのOSやDocker Engineの管理する必要がある。Fargateではそれが不要。

Fargateのメリット

  • ホストマシンOSやミドルウェアの構築が不要・・・ホストマシンOSやミドルウェアのアップデート・設定などに気を使う必要がなくなる。コンテナだけに集中することができる。

  • EC2インスタンスクラスターの管理が不要。・・・EC2インスタンスクラスターの管理が不要になる。実行時に必要なCPUやメモリの組み合わせだけ意識すればいい。

  • オートスケーリング・・・サーバーを自社運用していると、ユーザーからのアクセスが増えた時に、自分たちでサーバーの増築などをしなければならない。fargateでは自動的にコンテナ数を増やしてくれる。

Fargateのデメリット

  • パブリックIPの固定割り当てができない・・・FargateではEC2インスタンスへのIPが自動割り当てのため、パブリックIPアドレスの固定割り当てができない。これは外部アクセスのIP許可などでは不便である。

  • sshが使えない・・・sshコマンドを使ったコンテナアクセスが使えない。EC2を意識しないようにするためである。

AWSのlambdaとECS taskについて

参考サイト

AWS Batch, Lambda, ECS Task 比較:バッチやジョブにはどれを使う? - Timers Tech Blog

Lambda も Batch も ECS Task も、何かのジョブを単発/定期でサーバー無しで実行するための手段として似ている。これらの特徴やメリット/デメリットの比較してみる。

AWS lambda

コードだけアップロードして、実行トリガーを組めばその通りに動くFaas(Function as a Service)。簡単なスクレイピングシステムなどを運用したいときなどに使えそうである。管理を必要とせず、高可用性を担保できる。


メリットとして
  • コードのアップロードが簡単
  • 実行環境の設定もメモリ割り当てや同時実行数などを設定するだけで済む
  • トリガーの種類が多く、S3に画像がアップロードされたなどをプッシュ通知するなどできる
  • cronのような定期実行のできる
デメリットとして
  • 実行時間は15分が上限。長期間のバッチ処理は不可能。

ECS Task

ECSはそもそもコンテナ化されたアプリケーションを簡単にデプロイ、管理、スケールするサービス。その中でタスクを単一実行することができる。サービススケジューラ (長期実行タスクおよびアプリケーション用に)、タスクを手動で実行する機能 (バッチジョブまたは単一実行タスク用)、および Amazon ECS でクラスターにタスクを配置する機能がある。


  • ECS運用環境では環境整備済みなので、タスク実行は比較的簡単に設定&実行可能
  • (AWS Batchと同じく) コンテナ定義および実行環境は柔軟に設定可能
  • タスク数も自由に設定可能なので、大量のタスクを一斉に実行するといった事も容易に可能

結論としては・・・

ECSクラスタを運用している&依存関係のない単一のジョブ => ECS Task
1ユーザーごとに実行する、比較的小さなジョブ => Lambda

ActiveSupport::Concernモジュール

参照元

ActiveSupport::Concern でハッピーなモジュールライフを送る | TECHSCORE BLOG

Active SupportはRuby on Railsコンポーネントであり、Ruby言語の拡張、ユーティリティ、その他横断的な作業を担っている。言語レベルで基本部分を底上げして豊かなものにし、Railsアプリケーションの開発とRuby on Railsそれ自体の開発を合理化する。

ActiveSupport::ConcernモジュールはActiveSupportの一部である。 あらかじめモジュールにActiveSupport::Concernをextendしておくことによって、特異メソッド(クラスメソッド)の追加機能を簡単に使えるようになる。

例えば、ひとつのモジュールに特異メソッド(クラスメソッド)とインスタンスメソッドを設定したい時がある。この場合、Loggerモジュールをincludeすると、クラスメソッドとしてlog_of_class_methodが、インスタンスメソッドとしてlog_of_instance_methodが使える。

module Logger
  def self.included(base)
    base.extend(ClassMethods)
  end
 
  module ClassMethods
    def log_of_class_method
      puts 'This is class method!!'
    end
  end
 
  def log_of_instance_method
    puts 'This is instance method!!'
  end
end

extend ActiveSupport::Concernを使うと、上の記述をもう少し簡潔にできる。

module Logger
  extend ActiveSupport::Concern
  
  module ClassMethods
    def log_of_class_method
      puts 'This is class method!!'
    end
  end
 
  def log_of_instance_method
    puts 'This is instance method!!'
  end
end


scopeをモジュールに設定した時も同じ。 「def self.included(base) ... end」とする部分を「included do ... end」とできる。

included に渡したブロックが LogicalDeleteScopes の include 元のコンテキスト(つまり Article クラスのコンテキスト)で実行される。

module LogicalDeleteScopes
  extend ActiveSupport::Concern
  included do
    scope :without_deleted, lambda{ where(deleted_at: nil) }
  end
end
 
class Article < ActiveRecord::Base
  include LogicalDeleteScopes
end

モジュールと名前空間

モジュールには名前空間を分けて、名前の衝突を防ぐ機能がある。

例えば、「ポイント履歴」と「活動履歴」という意味で2つのHistoryクラスが作成されたとする。

class History
 def initialize(payment, used_point, user_id)
    @payment = payment
    @used_point = used_point
    @user_id = user_id
 end
end
class History
 def initialize(action, user_id)
    @action = action
    @user_id = user_id
 end
end

この状態で、Historyクラスからインスタンスを生成しようにもどっちのHistoryなのか判断できない。そこで、moduleを使って名前空間を分ける。以下のようにすると、名前の衝突はなくなる。

module Point
   class History
     def initialize(payment, used_point, user_id)
       @payment = payment
       @used_point = used_point
       @user_id = user_id
     end
  end
end
module Action
   class History
     def initialize(action, user_id)
       @action = action
       @user_id = user_id
     end
  end
end

モジュールに属すクラスを生成するときは「モジュール名::クラス名」で生成。

Point::History.new(payment, 20, 101)
Action::History.new("buy", 101)

より大きなプロジェクトでは、単に衝突だけではなく、グループやカテゴリーを分けるのにも使われる。例えば以下は「ActiveRecordディレクトリのAssociationsディレクトリのAliasTrackerクラス」を意味している。

module ActiveRecord
   module Associations
      class AliasTracker
          ・・・・

LDAP((Lightweight Directory Access Protocol))

参考サイト

qiita.com

LDAPは正式名称はLightweight Directory Access Protocolという。ディレクトリデータベースへアクセスするためのプロトコル。「ディレクトリサービスへとアクセスするためのプロトコル」である。

ディレクトリサービスとはネットワークに接続したサーバー、プリンター、アプリケーションなどの資源(リソース)の所在・属性・設定などの情報を効率的に収集し、記録・管理するサービスのことである。また、その機能を提供するコンピューターやソフトウェアを「ディレクトリサーバー」という。ネットワーク上の資源の情報を一元管理するので、大規模なネットワークでの使用が多い。

ディレクトリサービスは、資源名、ホスト名、IPアドレス、アクセス権限、アイデンティティ情報などのディレクトリ情報に基づいてユーザーやアプリケーションから資源へのアクセスをコントロールするのが目的である。

ディレクトリサービスにアクセスするための通信プロトコルとして、LDAPが標準で用いられている。LDAPを実装すれば1台のクライアントから複数のディレクトリサーバーにアクセスすることが可能だ。

有名なソフトウェアにSun Microsystemsの「NIS(Network Information Service)」、Appleの「Open Directory」、マイクロソフトの「Active Directory」など。

LDAPの主な機能

  • Linuxのシステムアカウント情報の一元化 => 多数のLinuxクライアントがある場合、1台1台にIDパスワード情報を入れることなく、LDAPサーバ1台だけに登録すれば、どのLinuxクライアントからも同じIDとパスワードでログインできる
  • Linuxサーバの各種アプリでのIDパスワード統一化 => ログインが必要なWebアプリサーバのIDパスワード情報を統一化することができ、発展形として、シングルサインオンも実装することができる
  • 社員情報の共有 => LDAPサーバに氏名やメールアドレス等の情報を格納し、別のLinuxサーバにCybozu等のグループウェアサーバをインストールし利用することで共有することができる。 また、グループウェアサーバー側にアカウント設定を行うことなく、LDAPサーバーに登録するのみでアカウントの生成等も行うことができる

LDAPの具体的な機能と仕組み

クライアントはLDAPサーバに接続、属性(個人名や部署名など)で構成するエントリ(関連属性のまとまり)の検索、追加、削除の操作を行う。

DIT(Directory Information Tree)というツリー構造のデータ形式で情報を管理されている。 ツリーにはエントリという単位で情報が登録され、一つのエントリにはLDAP識別名が一意に定められている。