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

PHPでもサーバーレスしたい

 PHPでもサーバーレスしたい

2017PHPカンファレンス関西-PHPでもサーバーレスしたい

Kaz Watanabe

July 15, 2017
Tweet

More Decks by Kaz Watanabe

Other Decks in Technology

Transcript

  1. 1)1Ͱ΋αʔόʔϨε͍ͨ͠
    1)1ΧϯϑΝϨϯεؔ੢
    ߹ಉձࣾEFDS୅දࣾһ
    ౉ลҰ޺ !LB[@

    View Slide

  2. WHO!?
    ౉ลҰ޺(@kaz_29)
    ߹ಉձࣾ decr ୅දࣾһ
    WebΞϓϦέʔγϣϯͷ։ൃ
    iOSΞϓϦέʔγϣϯͷ։ൃ
    Ϋϥ΢υΠϯϑϥͷߏஙɾӡ༻

    View Slide

  3. ຊ೔ͷ಺༰
    w αʔόʔϨεΞʔΩςΫνϟʔʁ
    w "[VSF'VODUJPOTͷ֓ཁ
    w 1)1Ͱͷ։ൃͷྫ
    w ฐࣾͰͷར༻ྫ

    View Slide

  4. αʔόʔϨεΞʔΩςΫνϟʔʁ

    View Slide

  5. View Slide

  6. r4FSWFSMFTT$POG50,:0

    IUUQUPLZPTFSWFSMFTTDPOGJP
    lαʔόʔϨεΞʔΩςΫνϟ͸ɺ։ൃऀͷ૑଄ੑΛ
    ૉૣ͘8FC΍ϞόΠϧΞϓϦέʔγϣϯͱ࣮ͯ͠ݱ
    ͠ɺεέʔϥϏϦςΟ΍ηΩϡϦςΟɺΠϯϑϥͷอ
    कͱ͍ͬͨଟ਺ͷྗ࢓ࣄ͔Βղ์͞ΕΔͨΊͷ৽ͨͳ
    ύϥμΠϜγϑτͰ͢ɻz

    View Slide

  7. αʔόʔ؀ڥͷมԽ
    w Ϋϥ΢υͷొ৔Ͱॊೈʹੜ੒ɾഁغ͕Ͱ͖Δ༷ʹͳͬͨɻ
    w ελϯυΞϩϯΞϓϦ͔Βͷ୤٫ϚΠΫϩαʔϏεͷོ੝
    w αʔόʔ͕ͳ͘ͳΔͱ͍͏͜ͱͰ͸ͳ͍ɻ։ൃऀ͕αʔόʔʹ͍ͭͯ୔ࢁͷ
    ͜ͱΛߟ͑ͳͯ͘ྑ͘ͳΔͱ͍͏͜ͱɻ
    IUUQTSFBEXSJUFDPNXIZUIFGVUVSFPGTPGUXBSFBOEBQQTJTTFSWFSMFTT

    View Slide

  8. αʔόʔ؀ڥͷมԽ
    IUUQTCMPHTNTEONJDSPTPGUDPNB[VSFTFDVSJUZCFTUQSBDUJDFTGPSVQEBUJOHWJSUVBMNBDIJOFTJONJDSPTPGUB[VSFJBBTEFQMPZNFOUT
    Best Practices for Updating Virtual Machines in Microsoft Azure IaaS Deployments

    View Slide

  9. αʔόʔϨεͱ͸ʁ
    w αʔόʔΛҙࣝ͠ͳ͍Ͱྑ͍
    w ؆୯ʹεέʔϧͰ͖Δ
    w ར༻ྔʹΑΔ՝ۚ

    View Slide

  10. Α͘ޠΒΕΔϢʔεέʔε
    w 8FCΞϓϦέʔγϣϯ
    w ϞόΠϧόοΫΤϯυ
    w *P5όοΫΤϯυ
    w ετϦʔϜϓϩηογϯά΍&5-
    w νϟοτϘοτɺίάχςΟϒαʔϏε
    w όονॲཧ
    w ӡ༻ͷࣗಈԽ

    View Slide

  11. ࣄྫ೔ܦ৽ฉ
    IUUQTBXTBNB[PODPNKQTPMVUJPOTDBTFTUVEJFTOJLLFJ

    View Slide

  12. ࣄྫGBVMUMJOF
    IUUQLMPXIBUFOBCMPHDPNFOUSZ
    1)1ΧϯϑΝϨϯε෱ԬͰGBVMUMJOFʹ͍ͭͯൃද͖ͯ͠·ͨ͠QIQDPOGVL

    View Slide

  13. Α͘ޠΒΕΔϢʔεέʔε
    w 8FCΞϓϦέʔγϣϯ
    w ϞόΠϧόοΫΤϯυ
    w *P5όοΫΤϯυ
    w ετϦʔϜϓϩηογϯά΍&5-
    w νϟοτϘοτɺίάχςΟϒαʔϏε
    w όονॲཧ
    w ӡ༻ͷࣗಈԽ
    ࠷ॳʹࢼ͢ͷʹΦεεϝʂ

    View Slide

  14. Lambda

    View Slide

  15. rIUUQEPDTBXTBNB[PODPNKB@KQMBNCEBMBUFTUEHXFMDPNFIUNM
    lඞཁͳૢ࡞͸ɺ"84-BNCEB͕αϙʔτ͢Δ͍ͣ
    Ε͔ͷݴޠ ݱࡏ͸/PEFKTɺ+BWBɺ$͓Αͼ
    1ZUIPO
    ͰίʔυΛࢦఆ͢Δ͚ͩͰ͢ɻ
    z

    View Slide

  16. lඞཁͳૢ࡞͸ɺ"84-BNCEB͕αϙʔτ͢Δ͍ͣ
    Ε͔ͷݴޠ ݱࡏ͸/PEFKTɺ+BWBɺ
    $͓Αͼ1ZUIPO
    ͰίʔυΛࢦఆ͢Δͩ
    ͚Ͱ͢ɻ
    z
    "84-BNCEB
    rIUUQEPDTBXTBNB[PODPNKB@KQMBNCEBMBUFTUEHXFMDPNFIUNM
    ͸ͳ͍

    View Slide

  17. "[VSF'VODUJPOT

    View Slide

  18. rIUUQTEPDTNJDSPTPGUDPNKBKQB[VSFB[VSFGVODUJPOTGVODUJPOTPWFSWJFX
    l$ɺ'ɺ/PEFKTɺ1ZUIPOɺ1)1ɺ#BUDIɺ
    #BTIɺͦͷଞ࣮ߦՄೳͳݴޠΛ࢖ͬͯؔ਺Λهड़Ͱ
    ͖·͢ɻz
    Ͱॻ͚Δ

    View Slide

  19. "[VSF'VODUJPO

    View Slide

  20. "[VSF'VODUJPOT
    w ΊͬͪΌ͍҆
    w ೖྗɾग़ྗͷ࿈ܞػೳ͕๛෋ τϦΨʔɾόΠϯσΟϯά

    w 7JTVBM4UVEJPΛ࢖ͬͯͷσόοά ϩʔΧϧɾϦϞʔτʣ
    w ΦϯϓϨͰ΋͍͚Δ "[VSF4UBDL

    w ϥϯλΠϜ͕Φʔϓϯ IUUQTHJUIVCDPN"[VSF"[VSF'VODUJPOT

    w (JUIVC͔ΒσϓϩΠͰ͖Δ

    View Slide

  21. τϦΨʔͱόΠϯσΟϯά
    IUUQTEPDTNJDSPTPGUDPNKBKQB[VSFB[VSFGVODUJPOTGVODUJPOTUSJHHFSTCJOEJOHT

    View Slide

  22. -PHJD"QQT

    View Slide

  23. -PHJD"QQ

    View Slide

  24. .JDSPTPGU'MPX
    IUUQTqPXNJDSPTPGUDPN

    View Slide

  25. "[VSF'VODUJPOͷػೳ

    View Slide

  26. "[VSF'VODUJPO

    View Slide

  27. Ϟχλʔ

    View Slide

  28. 'VODUJPO1SPYZ QSFWJFX

    w ෳ਺ͷ'VODUJPOΛ౷߹Ͱ͖Δ
    w "1*.BOBHFNFOUͷ୅ΘΓʹ࢖͑Δ
    w 'VODUJPOҎ֎΁ͷϦΫΤετ΋ઃఆͰ͖Δ
    "[VSF"1*NBOBHFNFOU
    "[VSF'VODUJPOT
    "[VSF'VODUJPOT1SPYZ
    "[VSF'VODUJPOT
    ͪΐͬͱ
    ͓ߴ͍

    View Slide

  29. σϓϩΠϝϯτεϩοτ QSFWJFX

    #MVF(SFFO%FQMPZNFOU͕؆୯ʹͰ͖Δ

    View Slide

  30. $POTPMF

    View Slide

  31. "QQMJDBUJPO*OTJUF QSFWJFX

    ೖΕΔ͔ʜ
    IUUQTB[VSFNJDSPTPGUDPNKBKQVQEBUFTB[VSFGVODUJPOTOPXJOUFHSBUFEXJUIBQQMJDBUJPOJOTJHIUT

    View Slide

  32. %VSBCMF'VODUJPOT Ћ൛

    w ෳ਺ͷ'VODUJPOͷ࿈ܞΛൺֱత؆୯ʹ࣮૷Ͱ͖Δ
    w 'VODUJPODIBJOJOH
    w 'BOPVU'BOJO
    w "TZOD)551"1*T
    IUUQTB[VSFHJUIVCJPB[VSFGVODUJPOTEVSBCMFFYUFOTJPOJOEFYIUNM
    IUUQRJJUBDPN5TVZPTIJ6TIJP!HJUIVCJUFNTFBDCCCGEC

    View Slide

  33. 'VODUJPO$IBJOJOH
    public static async Task Run(DurableOrchestrationContext ctx)
    {
    try
    {
    var x = await ctx.CallFunctionAsync("F1");
    var y = await ctx.CallFunctionAsync("F2", x);
    var z = await ctx.CallFunctionAsync("F3", y);
    return await ctx.CallFunctionAsync("F4", z);
    }
    catch (Exception)
    {
    // error handling/compensation goes here
    }
    }

    View Slide

  34. public static async Task Run(DurableOrchestrationContext ctx)
    {
    var parallelTasks = new List>();
    // get a list of N work items to process in parallel
    object[] workBatch = await ctx.CallFunctionAsync("F1");
    for (int i = 0; i < workBatch.Length; i++)
    {
    Task task = ctx.CallFunctionAsync("F2", workBatch[i]);
    parallelTasks.Add(task);
    }
    await Task.WhenAll(parallelTasks);
    // aggregate all N outputs and send result to F3
    int sum = parallelTasks.Sum(t => t.Result);
    await ctx.CallFunctionAsync("F3", sum);
    }
    'BOPVU 'BOJO

    View Slide

  35. "TZOD)551"1*T
    public static async Task Run(
    HttpRequestMessage req,
    DurableOrchestrationClient starter,
    string functionName,
    TraceWriter log)
    {
    // Function name comes from the request URL.
    // Function input comes from the request content.
    dynamic eventData = await req.Content.ReadAsAsync();
    string instanceId = await starter.StartNewAsync(functionName, eventData);
    log.Info($"Started orchestration with ID = '{instanceId}'.");
    return starter.CreateCheckStatusResponse(req, instanceId);
    }

    View Slide

  36. -JHIUXFJHIU"DUPST
    public static async Task Run(DurableOrchestrationContext ctx)
    {
    int counterState = ctx.GetInput();
    string operation = await ctx.WaitForExternalEvent("operation");
    if (operation == "incr")
    {
    counterState++;
    }
    else if (operation == "decr")
    {
    counterState--;
    }
    ctx.ContinueAsNew(counterState);
    }

    View Slide

  37. )VNBO*OUFSBDUJPOBOE5JNFPVUT
    public static async Task Run(DurableOrchestrationContext ctx)
    {
    await ctx.CallFunctionAsync("RequestApproval");
    using (var timeoutCts = new CancellationTokenSource())
    {
    DateTime dueTime = ctx.CurrentUtcDateTime.AddHours(72);
    Task durableTimeout = ctx.CreateTimer(dueTime, timeoutCts.Token);
    Task approvalEvent = ctx.WaitForExternalEvent("ApprovalEvent");
    if (approvalEvent == await Task.WhenAny(approvalEvent, durableTimeout))
    {
    timeoutCts.Cancel();
    await ctx.CallFunctionAsync("HandleApproval", approvalEvent.Result);
    }
    else
    {
    await ctx.CallFunctionAsync("Escalate");
    }
    }
    }

    View Slide

  38. 'VODUJPOTͷ࡞Γํ

    View Slide

  39. όΠϯσΟϯάͷ࢖͍ํ
    // ೖྗόΠϯσΟϯάͷಡࠐΈ
    $data = file_get_contents(getenv(‘req’));
    // ग़ྗόΠϯσΟϯά΁ͷॻࠐΈ
    file_put_contents(getenv(‘res’), $data);
    var_dump(getenv('res'));
    string(72) “D:
    \local\Temp\Functions\Binding\[UUID]\res”
    ੲջ͔͍͠$(*෩

    View Slide

  40. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  41. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  42. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  43. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  44. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  45. ࡞Γํ
    w 'VODUJPO"QQΛ࡞Δ
    w 'VODUJPO࡞Δ
    w ίʔυΛॻ͘
    w ΞϓϦͷઃఆ
    w ؀ڥม਺Λઃఆ
    w ࣮ߦ͢Δ

    View Slide

  46. Έ͍ͨͳͷ͸ɺ΍ͬͯΈͨܥͰ
    Α͘ॻ͔Ε͍ͯ·͢ɻ

    View Slide

  47. Ͱ΋ʜ

    View Slide

  48. ςετ͸⁉

    View Slide

  49. 1PSUBMͰ௚઀
    ίʔυमਖ਼⁉

    View Slide

  50. View Slide

  51. 'VODUJPOͷσόοάςετ
    w 8JOEPXTͳΒʜ
    w ୯ମςετ΋͍ͨ͠

    View Slide

  52. 'VODUJPOͷσόοάςετ
    ೖɾग़ྗνΣοΫͳΒͰ͖ͦ͏

    View Slide

  53. αϯϓϧ

    View Slide

  54. 0VUHPJOH8FCIPPLT IUUQ5SJHHFS
    IUUQPVUCJOEJOH

    View Slide

  55. 'VODTJPOͷߏ੒

    ᵓᴷᴷIPTUKTPO
    ᵓᴷᴷGVOD
    ᴹᵓᴷᴷGVODUJPOKTPO
    ᴹᵋᴷᴷSVOQIQ
    ᵋᴷᴷGVOD
    ᵓᴷᴷGVODUJPOKTPO
    ᵋᴷᴷSVOQIQ
    EJSFDUPSJFT pMFT
    'VODUJPOຖʹσΟϨΫτϦ
    τϦΨʔɾόΠϯσΟϯάͳͲͷఆٛ
    'VODUJPOͷΤϯτϦϙΠϯτ
    ϥϯλΠϜݻ༗ͷߏ੒
    IUUQTEPDTNJDSPTPGUDPNKBKQB[VSFB[VSFGVODUJPOTGVODUJPOTUSJHHFSTCJOEJOHT

    View Slide

  56. αϯϓϧ'VODUJPOͷߏ੒
    .
    ├── composer.json
    ├── composer.lock
    ├── slackbot
    │ ├── function.json
    │ └── run.php
    ├── src
    │ ├── Functions
    │ │ └── SlackBot.php
    │ └── Lib
    │ └── AzureFunction.php
    ├── tests
    │ ├── Lib
    │ │ └── TestCase.php
    │ └── TestCase
    │ └── Functions
    │ └── SlackBotTest.php
    ├── tmp
    └── vendor
    ├── autoload.php

    'VODUJPOͷσΟϨΫτϦ
    τϦΨʔɾόΠϯσΟϯάͳͲͷఆٛ
    'VODUJPOͷΤϯτϦϙΠϯτ
    'VODUJPOຊମ
    ؆୯ͳϥούʔΫϥε
    ςετΫϥε
    IUUQTHJUIVCDPNLB[QIQDPOLBOTBJB[VSFGVODUJPO

    View Slide

  57. GVODUJPOKTPO
    {
    "bindings": [
    {
    "type": "http",
    "direction": "out",
    "name": "res"
    },
    {
    "type": "httpTrigger",
    "name": "req",
    "authLevel": "function",
    "methods": [
    "post"
    ],
    "direction": "in"
    }
    ],
    "disabled": false
    }

    View Slide

  58. SVOQIQ
    require dirname(__DIR__) .
    DIRECTORY_SEPARATOR . 'vendor' .
    DIRECTORY_SEPARATOR . 'autoload.php';
    use App\Functions\SlackBot;
    $proc = new SlackBot();
    $proc->run();

    View Slide

  59. 4MBDL#PUQIQ
    namespace App\Functions;
    use App\Lib\AzureFunction;
    class SlackBot extends AzureFunction
    {
    public function __construct($req = 'req', $res = 'res')
    {
    $this->init(getenv($req), getenv($res));
    }

    }

    View Slide

  60. 4MBDL#PUQIQ
    public function run()
    {
    $params = $this->httpParams();
    if (!isset($params['user_name']) ||
    $params['user_name'] === 'slackbot') {
    return;
    }
    $response = [
    'text' => '',
    'username' => 'phpconkansai2017demo',
    'icon_emoji' => ':phpkansai:',
    'attachments' => [[
    "color" => '#00BFFF', // blue
    "title" => 'ϝοηʔδΛड৴͠·ͨ͠',
    "fields" => [[

    ]]
    ]]
    ];
    $this->writeResponse(json_encode($response));
    }

    View Slide

  61. 4-BDL#PU5FTUQIQ
    /**
    * @test
    */
    public function ௨ৗͷॻ͖ࠐΈͷςετ()
    {
    $params = [
    'token' => 'DUMMY',
    'user_name' => 'userA',
    'text' => 'Hello Azure Function'
    ];
    $this->makeHttpRequest($params);
    $this->makeResponse();

    View Slide

  62. 4-BDL#PU5FTUQIQ
    $this->slackBot = new SlackBot();
    $this->slackBot->run();
    $result = json_decode($this->getResponse(),
    true);
    $expected = [
    'username' => 'phpconkansai2017demo',
    'icon_emoji' => ':phpkansai:',
    'text' => '',
    'attachments' => [[
    "color" => '#00BFFF',
    "title" => 'ϝοηʔδΛड৴͠·ͨ͠',
    "fields" => [[
    // লུ
    ]]
    ]]
    ];
    $this->assertEquals($expected, $result);
    }

    View Slide

  63. 1)16OJUͰςετ

    View Slide

  64. View Slide

  65. ฐࣾͰͷࣄྫ

    View Slide

  66. ӡ༻πʔϧ
    w J04ΞϓϦͷόοΫΤϯυ
    w 4MBTI$PNNBOEͰεςʔδϯάαʔόͷىಈɾఀࢭ
    w λΠϚʔͰ࣌ʹࣗಈఀࢭ
    w ࣗಈఀࢭͷԆ௕

    View Slide

  67. ߏ੒
    4MBTI$PNNBOE
    IUUQ5SJHHFS
    2VFVF
    "1*࣮ߦ
    ىಈఀࢭ

    "1*࣮ߦ
    ঢ়ଶऔಘ

    UJNFS5SJHHFS
    ݁Ռ௨஌
    ॲཧ։࢝௨஌
    ஗Ԇ2VFVF

    View Slide

  68. ࣾ಺޲͚πʔϧ
    w ݄ॳʹΫϥ΢υܥͷ݄࣍ར༻ྉۚΛ4MBDLʹ௨஌

    View Slide

  69. ·ͱΊ

    View Slide

  70. 'VODUJPOΛ࢖ͬͯΈͯ
    w όονͱ͔ॏ͍ॲཧΛͤ͞Δʹ͸ͱͯ΋ศར
    దࡐదॴ
    w ΞϓϦΛ1)1Ͱॻ͍͍ͯΔͳΒಉ͡ݴޠͰ͔͚Δͷ͸ָ
    w .BDͰ΋ී௨ʹ։ൃͰ͖Δ
    w %VSBCMF'VODUJPOT͸ظ଴େ

    View Slide

  71. ՝୊
    w 4FSWFSMFTT'SBNFXPSLͰσϓϩΠ͍ͨ͠
    w IUUQ5SJHHFS͸ɺैྔ՝ۚϓϥϯͩͱਏ͍
    ࠓճͷྫͩͱɺ4MBDLଆͰλΠϜΞ΢τ͢Δ͜ͱ͕͋Δ

    View Slide

  72. ࠓ೔ͷαϯϓϧ
    IUUQTHJUIVCDPNLB[
    QIQDPOLBOTBJB[VSFGVODUJPO

    View Slide

  73. "[VSF'VODUJPO݁ߏ͍͍Ͱ͢
    IUUQTGVODUJPOTB[VSFDPNUSZ

    View Slide

  74. 'JO

    View Slide