<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bryan Burgers</title>
    <description>The latest articles on DEV Community by Bryan Burgers (@bryanburgers).</description>
    <link>https://dev.to/bryanburgers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F226014%2F2ef0ef55-b5ae-4d5a-998c-83359f2010ec.png</url>
      <title>DEV Community: Bryan Burgers</title>
      <link>https://dev.to/bryanburgers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bryanburgers"/>
    <language>en</language>
    <item>
      <title>Deploying WASM to Fastly's Edge</title>
      <dc:creator>Bryan Burgers</dc:creator>
      <pubDate>Sun, 08 Sep 2019 21:01:42 +0000</pubDate>
      <link>https://dev.to/bryanburgers/deploying-wasm-to-fastly-s-edge-il2</link>
      <guid>https://dev.to/bryanburgers/deploying-wasm-to-fastly-s-edge-il2</guid>
      <description>&lt;p&gt;Not so long ago, &lt;a href="https://www.fastly.com/blog/edge-programming-rust-web-assembly"&gt;Fastly introduced a new platform for edge programming&lt;/a&gt;. Fastly's vision is to use wasm to sandbox and run applications, which means that any language that can compile to wasm can run on their edge servers.&lt;/p&gt;

&lt;p&gt;The idea of edge functions is by no means new. Amazon does it with Lambda, CloudFlare has Workers, Google Cloud and Azure both call theirs Functions.&lt;/p&gt;

&lt;p&gt;To the best of my knowledge, Fastly's offering is unique in its use of wasm, and this has enabled them to have &lt;a href="https://www.fastly.com/blog/lucet-performance-and-lifecycle"&gt;really fast boot and response times&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Count me interested. Even though Fastly only has a limited preview right now (called Terrarium), I wanted to start digging in and start playing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;A great place to start playing with Terrarium is in their &lt;a href="https://www.fastlylabs.com/#Terrarium"&gt;web editor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The web editor has plenty of useful examples, and is a great place to try out some code and see it running in Terrarium. Poke around in all of the example projects, they're pretty cool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing out of the web editor
&lt;/h2&gt;

&lt;p&gt;Eventually, you might get to the point where the web editor isn't powerful enough. For me, it was when I wanted to bring in an image manipulation library. The web editor doesn't let you define your own depenencies, so I was stuck.&lt;/p&gt;

&lt;p&gt;I toyed with the idea of copying all of the source from &lt;a href="https://crates.io/crates/image"&gt;image-rs&lt;/a&gt; into the web editor, but including all of that source, and all of the transitive dependencies' source, would have been too much of a burden.&lt;/p&gt;

&lt;p&gt;The claim of &lt;a href="https://github.com/fastly/lucet"&gt;lucet&lt;/a&gt; (the engine behind Terrarium) is that it takes wasm files and runs them. Well, we can compile wasm locally, so we should be able to build the project locally and run it, right?&lt;/p&gt;

&lt;p&gt;We can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the project
&lt;/h2&gt;

&lt;p&gt;So let's do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo new &lt;span class="nt"&gt;--lib&lt;/span&gt; terrarium-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first problem we run into is that Terrarium needs to know what function to execute. And it has certain lifecycle expectations. So we need to be able to hook into its lifecycle.&lt;/p&gt;

&lt;p&gt;The way to do this is via their &lt;a href="https://github.com/fastly/terrarium-rust-guest"&gt;rust-guest&lt;/a&gt; library. I haven't seen it on crates.io yet, but they have generously made it available on GitHub.&lt;/p&gt;

&lt;p&gt;So now we can set up our &lt;code&gt;Cargo.toml&lt;/code&gt; file with everything we need to build our module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[lib]&lt;/span&gt;
&lt;span class="py"&gt;crate-type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["cdylib"]&lt;/span&gt;

&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="nn"&gt;http_guest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;git&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/fastly/terrarium-rust-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"^0.22.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Write the code
&lt;/h2&gt;

&lt;p&gt;That's all well and good, but we need some actual code. Here's a bit that takes any request (ignoring everything about the request, including the URL), generates a small image and responds with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;http_guest&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;guest_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;image&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;DynamicImage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/// The entrypoint on Terrarium: called for every HTTP request, and&lt;/span&gt;
&lt;span class="c"&gt;/// expected to return an HTTP response.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;user_entrypoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c"&gt;// Turn the image into bytes&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;
        &lt;span class="nf"&gt;.write_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;image&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ImageOutputFormat&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PNG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c"&gt;// Return the response&lt;/span&gt;
    &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"content-type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/// Create a new image to serve.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;generate_image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DynamicImage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DynamicImage&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new_rgb8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="nf"&gt;.as_mut_rgb8&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.enumerate_pixels_mut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.for_each&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.abs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Tell Terrarium about the entrypoint.&lt;/span&gt;
&lt;span class="nd"&gt;guest_app!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_entrypoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;OK, OK, cut me some slack. This may not be the most compelling example, but it's something trivial enough to fit in a blog post, but complicated enough that it can't be done on the web interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile the code
&lt;/h2&gt;

&lt;p&gt;With our code all ready, let's get a wasm file. If you've never compiled to wasm before (which I hadn't), you'll need to use &lt;code&gt;rustup&lt;/code&gt; to download the wasm target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;rustup target &lt;span class="nb"&gt;install &lt;/span&gt;wasm32-unknown-unknown
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And once we have that, we can build the project! Surprisingly straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--target&lt;/span&gt; wasm32-unknown-unknown
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If everything goes well, we should end up with a .wasm file in &lt;code&gt;target/wasm32-unknown-unknown&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Launch it!
&lt;/h2&gt;

&lt;p&gt;If you poke around in the Terrarium web editor in the build.ts file, it looks like Terrarium always expects the module at &lt;code&gt;module.wasm&lt;/code&gt;. So we can upload our module to that location, manually disable the &lt;code&gt;build.ts&lt;/code&gt; so we don't overwrite it, and hit "Build &amp;amp; Deploy".&lt;/p&gt;

&lt;p&gt;But it turns out there's an even easier way where we don't have to do any manual steps in the web editor.&lt;/p&gt;

&lt;p&gt;Fastly also provides a command line tool called &lt;a href="https://github.com/fastly/terrctl"&gt;terrctl&lt;/a&gt; that will launch an application from a &lt;code&gt;module.wasm&lt;/code&gt; for us! Download the right application for your architecture and invoke &lt;code&gt;terrctl&lt;/code&gt; to launch on Terrarium.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;target/wasm32-unknown-unknown/release/&lt;span class="k"&gt;*&lt;/span&gt;.wasm module.wasm
&lt;span class="nv"&gt;$ &lt;/span&gt;terrctl module.wasm
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Preparing upload of directory &lt;span class="o"&gt;[&lt;/span&gt;module.wasm]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Guessed programming language: wasm
&lt;span class="o"&gt;[&lt;/span&gt;NOTICE] Upload &lt;span class="k"&gt;in &lt;/span&gt;progress...
&lt;span class="o"&gt;[&lt;/span&gt;NOTICE] Upload &lt;span class="k"&gt;done&lt;/span&gt;, compilation &lt;span class="k"&gt;in &lt;/span&gt;progress...
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Upload &lt;span class="nb"&gt;complete&lt;/span&gt;, waiting &lt;span class="k"&gt;for &lt;/span&gt;build...
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Building...
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Generating machine code...
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Codegen complete...
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Deploy &lt;span class="nb"&gt;complete&lt;/span&gt;: https://involved-mental-write-window.fastly-terrarium.com/
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Instance is deployed
&lt;span class="o"&gt;[&lt;/span&gt;NOTICE] Instance is running and reachable over HTTPS
&lt;span class="o"&gt;[&lt;/span&gt;NOTICE] New instance deployed at &lt;span class="o"&gt;[&lt;/span&gt;https://involved-mental-write-window.fastly-terrarium.com]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The output of this command tells us the URL of our brand new WASM-on-the-Edge module! Open the URL and we should see a dynamically generated image. Woohoo!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future
&lt;/h2&gt;

&lt;p&gt;I really love this. I think it could be a huge step forward for serverless functions. I can't wait to see Fastly productize more.&lt;/p&gt;

&lt;p&gt;Right now, there are some limitations. The function that you deploy only lives for a handful of minutes, which means we can't currently create anything but short-lived toys here.&lt;/p&gt;

&lt;p&gt;There's also no way to set up secrets. If you look at their GitHub example, they hardcode the API token right into the app. I can see a future where they will allow us to set up environment variables or use some other mechanism to separate secrets and configuration from code.&lt;/p&gt;

&lt;p&gt;But I think this product really has a future, so I assume Fastly will build the ecosystem around it soon enough. I look forward to that day. WASM on the edge has a bright future!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
    </item>
  </channel>
</rss>
