<?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: Christopher Lai</title>
    <description>The latest articles on DEV Community by Christopher Lai (@christopherlai).</description>
    <link>https://dev.to/christopherlai</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%2F113934%2Ffdce9043-1065-47da-931f-aab79a076371.png</url>
      <title>DEV Community: Christopher Lai</title>
      <link>https://dev.to/christopherlai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/christopherlai"/>
    <language>en</language>
    <item>
      <title>Consider AWS Batch for Your Next Background Jobs</title>
      <dc:creator>Christopher Lai</dc:creator>
      <pubDate>Sun, 30 Jun 2019 21:29:37 +0000</pubDate>
      <link>https://dev.to/christopherlai/consider-aws-batch-for-your-next-background-jobs-4725</link>
      <guid>https://dev.to/christopherlai/consider-aws-batch-for-your-next-background-jobs-4725</guid>
      <description>&lt;p&gt;A colleague and I are currently in the process of updating an aging service in our stack. The service is pretty well isolated — it takes a bit of input, does a few units of work, then puts the results in a specific S3 bucket with a key provided as part of the input.&lt;/p&gt;

&lt;p&gt;Normally I would reach for SQS + EC2 with a homegrown background worker or a community library like shoryuken. However, having a few dozen servers in production already, I wanted a solution that wouldn’t include additional infrastructure I would need to manage.&lt;/p&gt;

&lt;p&gt;When I run in to an infrastructure related challenge nowadays, I do a quick search in the AWS console to see what turns up. Sure enough, AWS has a service for background jobs called Batch.&lt;/p&gt;

&lt;p&gt;At first glance, it wasn't entirely clear how Batch worked. I Googled a few different keyword arrangements, none of which turned up anything particularly useful; a few articles here and there, but nothing like an in-depth tutorial that covered our particular use case.&lt;/p&gt;

&lt;p&gt;After going through the Getting Started Guide, I found that Batch was very simple to set up. Most of the overhead was getting over what a traditional background worker setup looks like.&lt;/p&gt;

&lt;p&gt;There are a few characteristics that, collectively, make Batch work well for background jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compute Environment
&lt;/h2&gt;

&lt;p&gt;Batch jobs are run in a Compute Environment. This is just an ECS cluster that Batch creates and manages for you. These are the nodes/instances that will run your job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job Definition
&lt;/h2&gt;

&lt;p&gt;Jobs are defined using a Job Definition, which allows you to customize the number of CPUs, memory, and retries, as well as set environment variables and other options, like what default Docker Image you want to use.&lt;/p&gt;

&lt;p&gt;We knew we wanted to use Docker Images from the beginning. Our job has a large amount of runtime dependencies, and we thought it best to packages these into an atomic unit. Batch is a great fit, since Batch supports Docker Images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job Queue
&lt;/h2&gt;

&lt;p&gt;Unlike other background job libraries, Batch has its own queueing system — it doesn't rely on SQS or Redis.&lt;/p&gt;

&lt;p&gt;Job Queues are tied to a Compute Environment and can have different priorities. Jobs are submitted to Job Queues, which get run by the Compute Environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job
&lt;/h2&gt;

&lt;p&gt;Jobs are submitted to a Job Queue using a Job Definition. Default arguments set in the Job Definition can be overwritten when submitting a job.&lt;/p&gt;

&lt;p&gt;There are a few ways to submit jobs. We submit our jobs in our codebase using the the Batch gem provided by AWS.&lt;/p&gt;

&lt;p&gt;There's still a lot more for me to learn about Batch, but I wanted to share my experience using it so far. Feel free to leave a comment if you have any questions.&lt;/p&gt;

</description>
      <category>backgroundjob</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Deploying a Phoenix Project on AWS</title>
      <dc:creator>Christopher Lai</dc:creator>
      <pubDate>Wed, 12 Jun 2019 04:34:40 +0000</pubDate>
      <link>https://dev.to/christopherlai/deploying-a-phoenix-project-on-aws-5d4</link>
      <guid>https://dev.to/christopherlai/deploying-a-phoenix-project-on-aws-5d4</guid>
      <description>&lt;p&gt;This is a quick rundown of how we currently deploy a Phoenix project on AWS. It won’t include any code or screenshots — just a high-level overview.&lt;/p&gt;

&lt;p&gt;While we use Distillery to build our release, I will not be covering those details here. I recommend reviewing the documentation for Distillery on Hex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;This is the basic flow of how a merge into &lt;code&gt;master&lt;/code&gt; makes it to &lt;code&gt;EC2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GitHub&lt;/code&gt; &amp;gt; &lt;code&gt;AWS CodePipeline&lt;/code&gt; &amp;gt; &lt;code&gt;AWS CodeBuild&lt;/code&gt; &amp;gt; &lt;code&gt;AWS CodeDeploy&lt;/code&gt; &amp;gt; &lt;code&gt;AWS EC2&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub + AWS CodePipeline
&lt;/h2&gt;

&lt;p&gt;AWS CodePipeline is triggered when a Pull Request is merged into &lt;code&gt;master&lt;/code&gt;. This is done using GitHub Webhooks setup via CodePipeline. The setup is pretty simple and AWS has some great documentation on getting started.&lt;/p&gt;

&lt;p&gt;CodePipeline then hands the code off to CodeBuild to build our release.&lt;/p&gt;

&lt;h2&gt;
  
  
  CodeBuild
&lt;/h2&gt;

&lt;p&gt;We build our release using a custom Docker image on CodeBuild. The default Docker image provided by CodeBuild can be used, but we found that building a custom image was a better fit for our needs. Our custom image is very simple and consists of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu 18.04&lt;/li&gt;
&lt;li&gt;NodeJS 10LTS&lt;/li&gt;
&lt;li&gt;Erlang&lt;/li&gt;
&lt;li&gt;Elixir&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The release is then passed back to CodePipeline via the artifact configuration option for CodeBuild.&lt;/p&gt;

&lt;p&gt;CodePipeline then triggers a deploy using CodeDeploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: Your Git history is not available when a build is triggered by CodePipeline.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CodeDeploy
&lt;/h2&gt;

&lt;p&gt;CodeDeploy is used to push the release generated by CodeBuild in the previous step directly to our EC2 instances. This is done by a CodeDeploy agent running on each of our EC2 instances. The agent polls for available deployments and deploys them automatically if one is available.&lt;/p&gt;

&lt;p&gt;All of our instances run a custom AMI that has the CodeDeploy agent pre-installed. We build our Custom AMIs using Packer and Ansible. Our EC2 instances are managed with an Auto Scaling Group using a custom Launch Configuration.&lt;/p&gt;

&lt;p&gt;The entire process is simple and fast. It takes about 3-5 minutes to go from merged to fully deployed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Production credentials
&lt;/h2&gt;

&lt;p&gt;Our goal was to treat our EC2 instances as cattle and not pets. This meant that we needed an automated and secure way of passing production credentials and secrets to our EC2 instances. We didn’t want to store a text file or have environment variables on each EC2 instance. We settled on AWS Secrets Manager instead.&lt;/p&gt;

&lt;p&gt;I wrote a custom Distillery Config Provider that fetches credentials from Secrets Manager when the Phoenix release is started. Secrets Manager returns TOML to the custom Config Provider, then the TOML is then parsed, and the configurations are set using the Elixir &lt;code&gt;Application&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;I would be happy to write up additional details or answer any questions.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>aws</category>
      <category>deploy</category>
    </item>
  </channel>
</rss>
