Upgrade to Pro — share decks privately, control downloads, hide ads and more …

マルチテナントアーキテクチャ x Elixir / Phoenix

Cddce6ee5ec153c8dade038f6f75ff04?s=47 yujikawa
February 23, 2018

マルチテナントアーキテクチャ x Elixir / Phoenix

マルチテナントアーキテクチャ x Elixir / Phoenix

Cddce6ee5ec153c8dade038f6f75ff04?s=128

yujikawa

February 23, 2018
Tweet

Transcript

  1. ϚϧνςφϯτΞʔΩςΫνϟ ✖ &MJYJS 1IPFOJY 4BB4ͷ࠷લઢ GVLVPLBFY Ώ͔͡Θ!ZVKJLBXB@QZ

  2. w ໊લ w ઒্༞࢘ Ώ͔͡Θ  w ॴଐ w ΧϥϏφςΫϊϩδʔ

    w ৬छ w όοΫΤϯυΤϯδχΞ w 5XJUUFS w !ZVKJLBXB@QZ w ීஈͷ͓࢓ࣄ w &MJYJS1IPFOJYΛ࢖ͬͨ8FC։ൃ w ޷͖ͳݴޠ w &MJYJS w 1ZUIPO w ࠷ۙͷ׆ಈ w 1Z$PO,ZVTZVͷϝϯόʔͱͯ͠׆ಈத ࣗݾ঺հ
  3. ໨࣍ w &MJYJSͱ1IPFOJYʹ͍ͭͯ w ࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w Ϛϧνςφϯτͱ͸ʁ w

    &MJYJS1IPFOJYͰϚϧνςφϯτΛ͢Δʹ͸ʁ w ։ൃ؀ڥʹ͍ͭͯ w ࣮૷ฤBQBSUNFOUFY w ·ͱΊ
  4. w ؔ਺ܕݴޠ w &SMBOH7. #&". ্Ͱಈ͘ w όʔδϣϯ͸ w 8FCϑϨʔϜϫʔΫʢ3BJMT΍%KBOHPΈ͍ͨͳײ͡ʣ

    w 3BJMTͷTDB⒎PME͕Ͱ͖Δ &MJYJSͱ1IPFOJYʹ͍ͭͯ
  5. ࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ͜Ε·Ͱʢ݄͝Ζ·Ͱʣ w 1ZUIPOΛ࢖ͬͨγεςϜ։ൃ w ͜Ε͔Βʢ݄͔Βʣ w &MJYJS1IPFOJYΛ࢖ͬͨγεςϜ։ൃ w

    ؔ਺ܕݴޠͷอकੑɾฒྻॲཧͳͲͷߴ଎ੑʹັྗΛײ͡બఆɺγεςϜͷί Ξ෦෼͸&MJYJSΛ࢖͏ɻ͍͟ͱͳΕ͹&SMQPSUΛ࢖͍ɺ1ZUIPO౳ଞͷݴޠͱͷ ૊Έ߹Θͤ΋Մೳ w ࢀߟɿʮ&MJYJSʴ,FSBTʹखܰʹߴ଎ͳʮσʔλαΠΤϯεϓϥοτϑΥʔ Ϝʯʙ'MPXͰͷϚϧνίΞ׆༻ࣄྫʙʯIUUQTRJJUBDPNQJBDFSF JUFNTDBGCDFECD⒎
  6. ࠷ۙͷฐࣾͷ&MJYJSࣄ৘ w ͜Ε·Ͱ࢖ͬͯΈͯͷײ૝ w ϙδςΟϒ 㱼ʆ  w 1IPFOJYͰ3BJMTฒΈͷര଎։ൃ͕Ͱ͖Δ w

    5%%ʢςετۦಈ։ൃʣ͕͠΍͍͢ w ίʔυ͕ಡΈ΍͍͢ʢอक͠΍͍͢ʣ w ॲཧ଎౓͕଎͍ʢ1ZUIPOͩͱؾʹͳΔ͕࣌͋Δʣ w ڧྗͳύλʔϯϚονͰίʔυྔ͕গͳ͘ࡁΜͩ w ωΨςΟϒ ʀ㱼ʀ  w ৭ʑͳαʔϏεͷެࣜͷϥΠϒϥϦ͸·ͩগͳ͍ w υΩϡϝϯτ΋গͳ͍ʢ೔ຊޠ͸ಛʹʣ ॻ͖΍͍͢ɾಡΈ΍͍͢ɾύΠϓॲཧָ͕͍͠
  7. ࠷ۙͷੈͷதͷ&MJYJSࣄ৘

  8. ࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ($1ʢ(PPMHF$MPVE1MBUGPSNʣͰ&MJYJS͕࢖͑ΔΑ ͏ʹͳΓ·ͨ͠ʂԼهͷ63-Ͱ͸1IPFOJYΛ࢖͏·Ͱͷ νϡʔτϦΞϧ͕ܝࡌ͞Ε͍ͯ·͢ɻڵຯͷ͋Δํ͸ͥͻ ৮ͬͯݟ͍ͯͩ͘͞ɻ w νϡʔτϦΞϧɿIUUQTDMPVEHPPHMFDPNDPNNVOJUZ UVUPSJBMTFMJYJSQIPFOJYPOHPPHMFBQQFOHJOF

  9. ࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ༸ॻ͕࣍ʑͱൢച༧ఆ ൃച ൃച ˞࣌఺ͷ৘ใ ൃച &MJYJS'PSVNݟͯΔͱ҆͘ങ͑ΔՄೳੑ͋Γʂ
 IUUQTFMJYJSGPSVNDPNUGVODUJPOBMXFCEFWFMPQNFOUXJUI FMJYJSPUQBOEQIPFOJYQSBHQSPH

  10. ࠷ۙͷੈͷதͷ&MJYJSࣄ৘ w ༸ॻ͕࣍ʑͱൢച༧ఆ ൃച ˞࣌఺ͷ৘ใ ൃച ଓʑͱຊ͕ग़൛͞ΕɺੈքతϒʔϜ౸དྷʂʁ

  11. Ϛϧνςφϯτͱ͸ʁ w Ϛϧνςφϯτͱ͸ʜ w ̍ͭͷγεςϜʹෳ਺ͷςφϯτΛಉډ͍ͤͯ͞Δํࣜ ͷ͜ͱ w اۀ΍νʔϜͰ࢖͏4BB4͕Πϝʔδ͠΍͍͢ͱ͜Ζ ʢ#BDLMPHɺ+*3"ɺ2JJUBνʔϜͳͲʣ w

    ϚϧνςφϯτԽʹ͸͍͔ͭ͘ͷ෼཭ͷछྨ͕͋Δ
  12. Ϛϧνςφϯτͱ͸ w ᶃར༻ऀ͝ͱʹݸผΞϓϦͱݸผͷσʔλϕʔε "ࣾ #ࣾ $ࣾ "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ ӡ༻ίετ͕ߴ͘εέʔϧ͠ʹ͍͘

  13. Ϛϧνςφϯτͱ͸ "ࣾ #ࣾ $ࣾ w ᶄશར༻ऀ͕ಉҰΞϓϦͱݸผͷσʔλϕʔε "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ ֤%#ͷ؅ཧ͸݈ࡏ͠ӡ༻ίετ͕ߴ͍

  14. Ϛϧνςφϯτͱ͸ w ᶅશར༻ऀ͕ಉҰΞϓϦͱಉҰσʔλϕʔε %# ӡ༻ίετ΋௿͘εέʔϧ͠΍͍͢ ͜ͷΞʔΩςΫνϟ͕Ұ൪Ϛϧνςφϯγʔͱ͞Ε͍ͯΔ "ࣾͷࣾһ #ࣾͷࣾһ $ࣾͷࣾһ

  15. Ϛϧνςφϯτͱ͸ w ϚϧνςφϯτԽʹඞཁͳཁૉ w ΞϓϦέʔγϣϯ͕ϚϧνςφϯγʔΛαϙʔτ͢Δ͜ͱ w ΞϓϦέʔγϣϯ͕͋Δఔ౓ͷࣗಈαΠϯΞοϓػೳΛඋ͍͑ͯΔ͜ͱ w ొ࿥՝ۚϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ͜ͱ w

    ΞϓϦέʔγϣϯΛޮ཰తʹεέʔϦϯάͰ͖Δ͜ͱ w ΞϓϦέʔγϣϯͱςφϯτΛ؂ࢹɺߏ੒ɺ؅ཧ͢ΔͨΊͷػೳ͕༻ҙ͞Ε͍ͯΔ͜ͱ w ҰҙͷϢʔβʔ*%͓ΑͼೝূΛαϙʔτ͢ΔϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ͜ͱ w ςφϯτ͝ͱͷΧελϚΠζΛ͋Δఔ౓Մೳʹ͢ΔͨΊͷϝΧχζϜ͕༻ҙ͞Ε͍ͯΔ ͜ͱ Ҿ༻ɿʮ8FCΞϓϦέʔγϣϯΛϚϧνςφϯτܕ4BB4ιϦϡʔγϣϯʹม׵͢Δʯ IUUQTXXXJCNDPNEFWFMPQFSXPSLTKQDMPVEMJCSBSZDMNVMUJUFOBOUTBBT ஫໨ &MJYJSͰ Ͳ͏΍Δʁ
  16. &MJYJS1IPFOJYͰ Ϛϧνςφϯτʹ͢Δʹ͸ʁ w 044ͷϥΠϒϥϦ͕ଘࡏ͠·͢ w BQBSUNFOUFY  EPXOMPBET  w

    IUUQTIFYQNQBDLBHFTBQBSUNFOUFY w 5SJQMFY  EPXOMPBET  w IUUQTIFYQNQBDLBHFTUSJQMFY ˞࣌఺ͷσʔλ ஫໨ ࠓճ͸ ͜Ε࢖͏Αʂ 5SJQMFYͷ࢖͍ํ͸2JJUBʹॻ͖·ͨ͠ IUUQTRJJUBDPNZVKJLBXBJUFNTCCDFBFEDD
  17. ։ൃ؀ڥʹ͍ͭͯ w &MJYJS &SMBOH051  w 1IPFOJY w 1PTUHSF42-

  18. ࣮૷ฤ BQBSUNFOUFYͷ࣮૷ํ๏

  19. ࣮૷ฤBQBSUNFOUFY w 1IPFOJYͷϓϩδΣΫτΛ࡞੒ $ mix phx.new tenant_app ………লུ $ cd

    tenant_app/ $ mix ecto.create $ mix phx.server $ [info] Running TenantAppWeb.Endpoint with Cowboy using http://0.0.0.0:4000 IUUQʹΞΫηεͯ͠Έ·͠ΐ͏
  20. ࣮૷ฤBQBSUNFOUFY ͜ͷը໘͕දࣔ͞ΕΕ͹ͻͱ·ͣ0,

  21. ࣮૷ฤBQBSUNFOUFY w BQBSUNFOUFYΛNJYFYTʹ௥Ճ defp deps do [ {:phoenix, "~> 1.3.0"},

    {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.2"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 2.10"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:apartmentex, github: "Dania02525/apartmentex"}, {:cowboy, "~> 1.0"} ] end ࣌఺͸)FYʹ্͕͍ͬͯΔϓϩάϥϜʹ ෆ۩߹͕͋ΓHJUIVC͔ΒΠϯετʔϧ͢ΔΑ͏ʹมߋͨ͠
  22. ࣮૷ฤBQBSUNFOUFY w ϥΠϒϥϦΛΠϯετʔϧ $ mix deps.get && mix deps.compile

  23. ࣮૷ฤBQBSUNFOUFY w ςφϯτςʔϒϧͷ࡞੒ w αϒυϝΠϯଐੑΛ࣋ͨͤͨDPNQBOJFTςʔϒϧΛ࡞੒ʢί ϚϯυͰҰൃʣ $ mix phx.gen.context Accounts

    Company companies sub_domain:string ͜ͷίϚϯυ͸ςʔϒϧ࡞੒༻ͷϚΠάϨʔγϣϯϑΝΠϧ΍ .7$Ͱ͍͏.෦෼·ͰࣗಈͰ࡞੒ͯ͘͠Ε·͢ɻ
  24. ࣮૷ฤBQBSUNFOUFY w Ϣʔβ৘ใϓϩάϥϜͷ࡞੒ w ؆୯ͷͨΊϢʔβͷ໊લ͚ͩΛొ࿥͢ΔΞϓϦΛ࡞੒ $ mix phx.gen.html Accounts User

    users name:string ͜ͷίϚϯυ͸ςʔϒϧ࡞੒༻ͷϚΠάϨʔγϣϯϑΝΠϧ΍ .7$Ͱ͍͏.7$શͯࣗಈͰ࡞੒ͯ͘͠Ε·͢ɻ
  25. ࣮૷ฤBQBSUNFOUFY w ςφϯτΞϓϦ༻ʹςʔϒϧϚΠάϨʔγϣϯϑΥϧμΛ࡞੒ w BQBSUNFOUFY͕࢖͑ΔΑ͏ʹϑΥϧμͷ࡞੒͠ɺઌ΄Ͳ࡞ͬ ͨϢʔβ৘ใͷϚΠάϨʔγϣϯϑΝΠϧ͚ͩΛҠಈͤ͞·͢ɻ $ mkdir priv/repo/tenant_migrations $

    mv priv/repo/migrations/20180213211936_create_users.exs priv/ repo/tenant_migrations
  26. ࣮૷ฤBQBSUNFOUFY w ϧʔςΟϯάΛ௥Ճ MJCUFOBOU@BQQ@XFCSPVUFSFY  w Ϣʔβ৘ใͷϧʔςΟϯάΛઃఆ͠·͢ scope "/", TenantAppWeb

    do pipe_through :browser # Use the default browser stack get "/", PageController, :index resources "/users", UserController end
  27. ࣮૷ฤBQBSUNFOUFY w $PNQBOZϚΠάϨʔγϣϯϑΝΠϧʹVOJRVFJOEFYΛઃ ఆ defmodule TenantApp.Repo.Migrations.CreateCompanies do use Ecto.Migration def

    change do create table(:companies) do add :sub_domain, :string timestamps() end create unique_index(:companies, [:sub_domain]) end end
  28. ࣮૷ฤBQBSUNFOUFY w ϚΠάϨʔγϣϯΛ͠·͢ $ mix ecto.migrate [info] == Running TenantApp.Repo.Migrations.CreateCompanies.change/0

    forward [info] create table companies [info] create index companies_sub_domain_index [info] == Migrated in 0.0s
  29. ࣮૷ฤBQBSUNFOUFY w %#ૢ࡞ͷؔ਺Λมߋ͠·͢ MJCUFOBOU@BQQBDDPVOUTBDDPPVOUTFY def create_company(attrs \\ %{}) do with

    changeset <- Company.changeset(%Company{}, attrs), {:ok, company} <- Repo.insert(changeset), do: Apartmentex.new_tenant(Repo, company.sub_domain) end def create_user(attrs \\ %{}, sub_domain) do with changeset <- User.changeset(%User{}, attrs), do: Apartmentex.insert(Repo, changeset, sub_domain) end def list_users(sub_domain) do Apartmentex.all(Repo, User, sub_domain) end ొ࿥ͱऔಘͷؔ਺ʹαϒυϝΠϯରԠΛ͢Δ
  30. ࣮૷ฤBQBSUNFOUFY w ςετσʔλͷ࡞੒ w ಈ࡞֬ೝͷͨΊʹखಈͰ࡞੒͠·͢ $ iex -S mix iex(1)>

    alias TenantApp.Accounts iex(2)> Accounts.create_company(%{sub_domain: "company-aaa"}) iex(3)> Accounts.create_company(%{sub_domain: "company-zzz"}) iex(4)> Accounts.create_user(%{name: "Yuji Kawakami"}, "company-aaa") iex(5)> Accounts.create_user(%{name: "Taro Tanaka"}, "company-zzz") iex(6)> Accounts.create_user(%{name: "Hanako Takahashi"}, "company-zzz")
  31. ࣮૷ฤBQBSUNFOUFY w 6TFSίϯτϩʔϥͷมߋ MJCUFOBOU@BQQ@XFCDPOUSPMMFSTVTFS@DPOUSPMMFSFY  w Ϣʔβ৘ใͷίϯτϩʔϥΛมߋ͠·͢ def action(conn, _)

    do [sub_domain|_] = String.split(conn.host, ".") apply(__MODULE__, action_name(conn), [conn, conn.params, sub_domain]) end def index(conn, _params, sub_domain) do users = Accounts.list_users(sub_domain) render(conn, "index.html", users: users) end BDUJPOؔ਺ͰίϯτϩʔϥͰఆٛͨؔ͠਺ʹ TVC@EPNBJOΛҾ਺Ͱ౉͢Α͏ʹ͍ͯ͠Δ
  32. ࣮૷ฤBQBSUNFOUFY w ςετ༻ʹIPTUTʹυϝΠϯΛઃఆ͠ɺαʔόىಈ $ vim /etc/hosts 127.0.0.1 company-aaa.dev.local dev 127.0.0.1

    company-zzz.dev.local dev $ mix phx.server Compiling 1 file (.ex) [info] Running TenantAppWeb.Endpoint with Cowboy using http:// 0.0.0.0:4000
  33. ࣮ફฤ%&.0

  34. ࣮ફฤ%&.0

  35. ࣮ફฤ%#ͷ༷ࢠ 1VCMJDʹͳ͍ͬͯΔςʔϒϧ͸DPNQBOJFTͷΈ

  36. ࣮ફฤ%#ͷ༷ࢠ 1PTUHSFTͷεΩʔϚػೳΛ্ख͘࢖͏͜ͱͰ αϒυϝΠϯ͝ͱʹσʔλΛ࣋ͯΔ࢓૊ΈΛ࣮ݱ͍ͯ͠Δ

  37. ·ͱΊ w &MJYJS1IPFOJYͰ΋؆୯ʹϚϧνςφϯτͳΞϓϦ͕࡞ ੒Ͱ͖Δʂ w ࠓճͷϚϧνςφϯτରԠ͸1PTUHSFTͰ͕ͨ͠ɺڵຯ͕ ͋Δਓ͸.Z42-Ͱ΋ࢼͯ͠Έ͍ͯͩ͘͞ɻ w ΋͏ҰͭͷϥΠϒϥϦʔ5SJQMFY΋ࢼͯ͠ɺ͍ͭͷ೔͔· ͨ࿩͕࣌͢དྷΕ͹͍͍ͳ͊ɾɾ

  38. ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠