<?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: Joe Tan</title>
    <description>The latest articles on DEV Community by Joe Tan (@joetancy).</description>
    <link>https://dev.to/joetancy</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%2F442969%2F6c6f3507-a186-4d25-961e-b68cf1a68f6f.jpeg</url>
      <title>DEV Community: Joe Tan</title>
      <link>https://dev.to/joetancy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joetancy"/>
    <language>en</language>
    <item>
      <title>AWS Cognito with React reCaptcha v2</title>
      <dc:creator>Joe Tan</dc:creator>
      <pubDate>Tue, 25 Aug 2020 02:02:49 +0000</pubDate>
      <link>https://dev.to/joetancy/aws-cognito-with-react-recaptcha-v2-3bn2</link>
      <guid>https://dev.to/joetancy/aws-cognito-with-react-recaptcha-v2-3bn2</guid>
      <description>&lt;h2&gt;
  
  
  AWS Cognito
&lt;/h2&gt;

&lt;p&gt;Cognito is a managed service for user management provided by AWS. Though it seems complete at first, there are a few features that are not available, e.g. captcha, password rotations, password expiry.&lt;/p&gt;

&lt;p&gt;They do however provide Lambda triggers on some of their actions. We can extend the functionalities by writing functions that will trigger when Cognito perform such actions, like pre-authentication and post-authentication.&lt;/p&gt;

&lt;p&gt;A common requirement when it comes to sign-up/login flows is captcha, which prevents bots from signing up or logging in.&lt;/p&gt;

&lt;p&gt;We will be using AWS Amplify for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Lambda
&lt;/h2&gt;

&lt;p&gt;Lambda is a way to run the serverless code on AWS. No provisioning of compute instance is required to run such codes.&lt;/p&gt;

&lt;h2&gt;
  
  
  reCaptcha v2
&lt;/h2&gt;

&lt;p&gt;Recaptcha is a captcha service by Google. You do need a Google account to get the site-key and secret-key for reCaptcha to work correctly. We will be using reCaptcha v2.&lt;/p&gt;

&lt;p&gt;Upon signing up, take note of the site-key, which will be on the client-side, and the secret-key, which will be on the server-side.&lt;/p&gt;

&lt;p&gt;We will be using the react-google-recaptcha for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing reCaptcha for React
&lt;/h2&gt;

&lt;p&gt;Install the reCaptcha library to your project dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react-google-recaptcha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render the reCaptcha&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReCAPTCHA&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-google-recaptcha&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Captcha value: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReCAPTCHA&lt;/span&gt;
  &lt;span class="nx"&gt;sitekey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR SITE KEY HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this, we can get the reCaptcha token, now we need to send it together with the user credentials to AWS Cognito for verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing the token to AWS Cognito
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws-amplify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;captcha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where username and password are user input credentials, the last parameter is called &lt;a href="https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#signin" rel="noopener noreferrer"&gt;clientMetadata&lt;/a&gt; which is not stored by AWS in any way, and only used in the triggers in Lambda.&lt;/p&gt;

&lt;p&gt;You can see that we've added the token value with the key "captcha", you will see how we use this value next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Lambda function
&lt;/h2&gt;

&lt;p&gt;Login to your AWS Lambda and create a new function with NodeJS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fytrq08cr5vvj2wgcvpyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fytrq08cr5vvj2wgcvpyt.png" alt="New Lambda Function"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;recaptcha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validationData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing validation data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;recaptcha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validationData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;captcha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;remoteip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verifyResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.google.com/recaptcha/api/siteverify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verifyResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Recaptcha verification failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also have to add your reCaptcha secret-key into the environment variables in the Lambda page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxd44f7wcf9ayn3bxsojw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxd44f7wcf9ayn3bxsojw.png" alt="Lambda Env Var"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding this code in Lambda, add this Lambda function to your pre-authentication trigger of your AWS Cognito User Pools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5sfrk2huo2d5iuniomfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5sfrk2huo2d5iuniomfn.png" alt="Cognito Trigger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have your triggers and functions ready, try a login flow in your application, you'll realise that you'll receive an error 400.&lt;/p&gt;

&lt;p&gt;That's because Lambda needs the dependencies for your function, in which this case is Axios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload your codes
&lt;/h2&gt;

&lt;p&gt;Lambda allows you to zip up your codes with dependencies and upload them. What we'll have to do here is to copy that code above into a .js file, install &lt;a href="https://www.npmjs.com/package/axios" rel="noopener noreferrer"&gt;Axios&lt;/a&gt; into node_modules, zip it up and upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally!
&lt;/h2&gt;

&lt;p&gt;And you're done! You've just altered the authentication flow of AWS Cognito slightly to include a captcha with Lambda!&lt;/p&gt;

&lt;p&gt;There are many ways to make use of the triggers to achieve your needs, explore the other triggers and customise them with Lambda!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>cognito</category>
      <category>captcha</category>
      <category>serverless</category>
      <category>react</category>
    </item>
    <item>
      <title>A brief introduction to microservices</title>
      <dc:creator>Joe Tan</dc:creator>
      <pubDate>Wed, 29 Jul 2020 11:52:47 +0000</pubDate>
      <link>https://dev.to/joetancy/a-brief-introduction-to-microservices-1d5n</link>
      <guid>https://dev.to/joetancy/a-brief-introduction-to-microservices-1d5n</guid>
      <description>&lt;p&gt;Microservices architecture is really popular these days.&lt;br&gt;
Running a collection of single-purpose programs benefits the whole application. This article gives you a brief overview of microservices architecture.&lt;/p&gt;

&lt;p&gt;This makes the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loosely coupled&lt;/li&gt;
&lt;li&gt;Easily maintainable&lt;/li&gt;
&lt;li&gt;Independently deployable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They usually communicate with each other with APIs through HTTP.&lt;br&gt;
Think of microservices as many workers with really specific job scope that comes together to form the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application
&lt;/h2&gt;

&lt;p&gt;First, we'll have to write our application. There are a few frameworks that are suitable for writing microservices in many languages, so pick any you're comfortable with.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spring.io/projects/spring-boot"&gt;Spring Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://sparkjava.com/"&gt;Spark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Python

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flask.palletsprojects.com/en/1.1.x/"&gt;Flask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bottlepy.org/docs/dev/"&gt;Bottle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common attribute in frameworks is that they are slim and lightweight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Containers
&lt;/h2&gt;

&lt;p&gt;Microservices usually runs in containers and a container orchestration platform.&lt;br&gt;
One of the more popular containerisation and orchestration platforms would be &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;, and &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Containers are self-contained images that include all dependencies that your service needs to run. These include your OS, web server, and your code that runs on the webserver. This image is built by Docker and uploaded to an image repository of your choice.&lt;br&gt;
(See &lt;a href="https://hub.docker.com/"&gt;Dockerhub&lt;/a&gt; or &lt;a href="https://aws.amazon.com/ecr/"&gt;AWS ECR&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Having multiple services means multiple container images to run. Kubernetes makes running these images easier by automating the deployment and scaling of these containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container Orchestration
&lt;/h2&gt;

&lt;p&gt;By putting multiple pods together, it forms a cluster. Kubernetes runs clusters of pods. Pods consist of various containers.&lt;/p&gt;

&lt;p&gt;Putting this in context, for example, you have an e-commerce application, designed in a microservices architecture.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cart&lt;/li&gt;
&lt;li&gt;Products&lt;/li&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;li&gt;Tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these is a container image running in the pods of a Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;The scalability of Kubernetes comes in when you specify e.g. "Cart" with very high traffic, to be able to scale to 5 more replicas. Kubernetes will measure the resource usage of "Cart", and if it hits a certain percentage, it spins up more instance of this "Cart" container in the same pod to share the load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the application running in containers, which runs in the pods of Kubernetes, we now have a collection of services that runs specific jobs that can communicate with one another within the service cluster.&lt;/p&gt;

&lt;p&gt;There will be a guide on how to containerise your service, deploy it, and run in Kubernetes.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>microservices</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>PHP-FPM with Apache2</title>
      <dc:creator>Joe Tan</dc:creator>
      <pubDate>Wed, 29 Jul 2020 11:51:47 +0000</pubDate>
      <link>https://dev.to/joetancy/php-fpm-with-apache2-2mk0</link>
      <guid>https://dev.to/joetancy/php-fpm-with-apache2-2mk0</guid>
      <description>&lt;p&gt;Processing PHP is slow and clunky on Apache Modules, therefore people move to NGINX for higher HTTP response concurrency.&lt;/p&gt;

&lt;p&gt;Apache has something similar called mpm_events, to use this we need to disable the Apache PHP module.&lt;/p&gt;

&lt;p&gt;Below are the steps for a complete change from Apache PHP module to PHP-FPM for processing, and optimising Apache to use mpm_events instead of mpm_prefork.&lt;/p&gt;

&lt;p&gt;First, we need to install PHP-FPM, configure Apache to route .php processing to PHP-FPM, then optimise the number of PHP-FPM threads. After which we will change Apache from mpm_prefork to mpm_events for higher concurrency processing.&lt;/p&gt;

&lt;p&gt;This guide assumes you are operating on Ubuntu 18.04 LTS&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing PHP-FPM
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python-software-properties 
&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository ppa:ondrej/php
apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;php7.3 php7.3-fpm php7.3-curl php7.3-mysql php7.3-xmlrpc php7.3-bcmath php7.3-mbstring php7.3-xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we have to check if PHP-FPM is running as a daemon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status php7.3-fpm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You should be able to see something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;php7.3-fpm.service - The PHP 7.3 FastCGI Process Manager Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/lib/systemd/system/php7.3-fpm.service&lt;span class="p"&gt;;&lt;/span&gt;
enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Tue 2019-07-23 03:28:26 UTC&lt;span class="p"&gt;;&lt;/span&gt; 17min ago
Docs: man:php-fpm7.3&lt;span class="o"&gt;(&lt;/span&gt;8&lt;span class="o"&gt;)&lt;/span&gt;
Main PID: 30011 &lt;span class="o"&gt;(&lt;/span&gt;php-fpm7.3&lt;span class="o"&gt;)&lt;/span&gt;
Status: &lt;span class="s2"&gt;"Processes active: 38, idle: 3, Requests: 20367, slow:
0, Traffic: 17.2req/sec"&lt;/span&gt;

Tasks: 102 &lt;span class="o"&gt;(&lt;/span&gt;limit: 4915&lt;span class="o"&gt;)&lt;/span&gt;
CGroup: /system.slice/php7.3-fpm.service
        ├─10217 php-fpm: pool www 
        ├─10277 php-fpm: pool www 
        ├─10278 php-fpm: pool www 
        └─30011 php-fpm: master process
&lt;span class="o"&gt;(&lt;/span&gt;/etc/php/7.3/fpm/php-fpm.conf&lt;span class="o"&gt;)&lt;/span&gt;

Jul 23 03:28:26 systemd[1]: Starting The PHP 7.3 FastCGI Process Manager...
Jul 23 03:28:26 systemd[1]: Started The PHP 7.3 FastCGI Process Manager.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring Apache2
&lt;/h3&gt;

&lt;p&gt;Enable these modules so that Apache can route PHP processing to PHP-FPM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;a2enmod actions &lt;span class="nb"&gt;alias &lt;/span&gt;proxy_fcgi setenvif
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Edit the Apache configuration file to route the processing. (Also edit for 000-default-ssl.conf if needed)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/apache2/sites-available/000-default.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add these lines into this file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;FilesMatch &lt;span class="se"&gt;\.&lt;/span&gt;php&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; 
    SetHandler
&lt;span class="s2"&gt;"proxy:unix:/run/php/php7.3-fpm.sock|fcgi://localhost/"&lt;/span&gt; 
&amp;lt;/FilesMatch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure your .sock is in the correct path&lt;/p&gt;

&lt;p&gt;Restart Apache to test if your website still works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You may have to run these commands to enable PHP-FPM with Apache&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;a2enmod proxy_fcgi setenvif 
a2enconf php7.3-fpm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Changing mpm module
&lt;/h3&gt;

&lt;p&gt;Now we change the mpm module from prefork to events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;a2dismod php7.3 mpm_prefork 
a2enmod mpm_event
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Check if Server MPM is changed to events&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apachectl &lt;span class="nt"&gt;-V&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;MPM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You should see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Server MPM: event
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimising Apache2 mpm_event
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/apache2/mods-enabled/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;nano mpm_event.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&amp;lt;IfModule mpm_event_module&amp;gt; 
    KeepAlive On
    KeepAliveTimeout 5 
    MaxKeepAliveRequests 128

    ServerLimit 10
    StartServers 4
    ThreadLimit 128 
    ThreadsPerChild 128 
    MinSpareThreads 256 
    MaxSpareThreads 512 
    MaxRequestWorkers 1280 
    MaxConnectionsPerChild 2048
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Optimising PHP-FPM
&lt;/h3&gt;

&lt;p&gt;Now that we have increased the concurrency of Apache2, we now have to increase the number of PHP processing servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/php/7.3/fpm/pool.d/ 
nano ​www.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Make sure the following is entered&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pm &lt;span class="o"&gt;=&lt;/span&gt; dynamic
pm.max_children &lt;span class="o"&gt;=&lt;/span&gt; 100 
pm.start_servers &lt;span class="o"&gt;=&lt;/span&gt; 20 
pm.min_spare_servers &lt;span class="o"&gt;=&lt;/span&gt; 10 
pm.max_spare_servers &lt;span class="o"&gt;=&lt;/span&gt; 30 
pm.process_idle_timeout &lt;span class="o"&gt;=&lt;/span&gt; 10s&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Restart both process
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart php7.3-fpm 
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And you're done! Congratulations! PHP processing is now handled by PHP-FPM!&lt;/p&gt;

</description>
      <category>php</category>
      <category>wordpress</category>
      <category>apache</category>
      <category>optimisation</category>
    </item>
  </channel>
</rss>
