-
LocalStack
đź’» A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline
-
InfluxDB
Power Real-Time Data Analytics at Scale. Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.
-
serverless-application-model
The AWS Serverless Application Model (AWS SAM) transform is a AWS CloudFormation macro that transforms SAM templates into CloudFormation templates.
-
aws-lambda-go-api-proxy
lambda-go-api-proxy makes it easy to port APIs written with Go frameworks such as Gin (https://gin-gonic.github.io/gin/ ) to AWS Lambda and Amazon API Gateway.
-
s3_website
Manage an S3 website: sync, deliver via CloudFront, benefit from advanced S3 website features.
-
SaaSHub
SaaSHub - Software Alternatives and Reviews. SaaSHub helps you find the best software and product alternatives
In this article we wanted to share an overview of a recent project to build a logistics platform from scratch using AWS cloud, Go and serverless. Yes, there is already a great abundance of blog posts focusing on all of these individual technologies. What we find often lacks is how to glue all of those together, which is exactly what we describe in this post. Here is our full code supporting this blog post.
In order to provide a seamless local development environment AWS provides a cool framework named AWS SAM. It allows you to run AWS Lambdas locally, and, most importantly, with an option to easily create the relevant Service events like API Gateway. So our solution for running things locally and for testing involved Docker with SAM template and of course Localstack for simulating other AWS resources that we were using, such as AWS SES, AWS S3 and AWS SecretManager.
From an outside networking point of view, we decided to go with cloudflare as a DNS service. The main benefit of using cloudflare is it’s DDoS protection. The experiences that we had previously with cloudflare were very good, so it was logical to stay with cloudflare. Most of all, adding and maintaining DNS records, we found to be user friendly even for one’s without a networking background. With this feature on, one thing less to think about while designing a solution. Last awesomeness is that Cloudflare solutions/features (such as automatically setting up SSL certificates for our (sub)domains) are completely free.
We ran into an issue while setting up Stage property. At first we tried to simply add value as reference to Parameter Stage: !Ref TargetStage, but we got a strange error saying >“Invalid stage identifier specified”. After some digging we found a github topic with the same problem. The problem lies in that creating a Stage resource is outside of the SAM template and with just referencing it to name will fail, because the resource ApiDomainMappings it’s being created before resource Stage. Thanks to fellows on github, this suggestion worked. So we changed Stage property to: Stage: !Ref ApiDetails.Stage.
As you can see, we defined that any path and method can trigger our lambda over API Gateway that we had previously created. With this approach and with using this solution with the Go Echo framework, we reduced the number of lambdas (also with this approach we solved the problem with a hard limit of total size that all lambdas can have). Using the aws-lambda-go-api-proxy with echo framework we defined a REST controller that is managing real paths and methods that our lambda consumes.
resource "aws_cloudfront_distribution" "frontend" { enabled = true aliases = ["${var.subdomain_name}.${var.domain_name}"] is_ipv6_enabled = true // cheapest: https://github.com/laurilehmijoki/s3_website/issues/150 price_class = "PriceClass_100" default_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD"] target_origin_id = var.frontend_s3_origin_id viewer_protocol_policy = "redirect-to-https" default_ttl = 0 max_ttl = 0 forwarded_values { query_string = false cookies { forward = "none" } } } origin { domain_name = var.frontennd_s3_origin_domain_name origin_id = var.frontend_s3_origin_id custom_origin_config { http_port = 80 https_port = 443 origin_keepalive_timeout = 5 origin_protocol_policy = "http-only" // setting defined after terraform import. can try with https-only origin_read_timeout = 30 origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"] } } restrictions { geo_restriction { restriction_type = "none" } } viewer_certificate { acm_certificate_arn = aws_acm_certificate_validation.default.certificate_arn cloudfront_default_certificate = false minimum_protocol_version = "TLSv1.2_2019" ssl_support_method = "sni-only" } } resource "cloudflare_record" "frontend_service" { name = "${var.subdomain_name}.${var.domain_name}" value = aws_cloudfront_distribution.frontend.domain_name type = "CNAME" proxied = true zone_id = lookup(data.cloudflare_zones.default.zones[0], "id") }
workflow: variables: AWS_DEFAULT_REGION: "eu-west-1" WORKSPACE: "dev" TF_ENVIRONMENT: "terraform" stages: - terraform-apply terraform-apply: image: google/cloud-sdk:slim stage: terraform-apply before_script: - apt-get install -y unzip make jq - curl https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip --output /tmp/terraform.zip - unzip /tmp/terraform.zip -d /tmp - chmod +x /tmp/terraform - mv /tmp/terraform /usr/local/bin/ - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip" - unzip -q awscliv2.zip - ./aws/install - aws sts get-caller-identity - curl --location "https://github.com/aws/aws-sam-cli/releases/download/v1.18.1/aws-sam-cli-linux-x86_64.zip" -o "awssamcli.zip" - unzip -q awssamcli.zip - ./install - sam --version - curl --location https://github.com/terraform-linters/tflint/releases/download/v0.21.0/tflint_linux_amd64.zip -o /tmp/tflint.zip - unzip /tmp/tflint.zip -d /tmp - chmod +x /tmp/tflint - mv /tmp/tflint /usr/local/bin/ script: - echo yes | make tf-apply
workflow: variables: AWS_DEFAULT_REGION: "eu-west-1" WORKSPACE: "dev" TF_ENVIRONMENT: "terraform" stages: - terraform-apply terraform-apply: image: google/cloud-sdk:slim stage: terraform-apply before_script: - apt-get install -y unzip make jq - curl https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip --output /tmp/terraform.zip - unzip /tmp/terraform.zip -d /tmp - chmod +x /tmp/terraform - mv /tmp/terraform /usr/local/bin/ - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip" - unzip -q awscliv2.zip - ./aws/install - aws sts get-caller-identity - curl --location "https://github.com/aws/aws-sam-cli/releases/download/v1.18.1/aws-sam-cli-linux-x86_64.zip" -o "awssamcli.zip" - unzip -q awssamcli.zip - ./install - sam --version - curl --location https://github.com/terraform-linters/tflint/releases/download/v0.21.0/tflint_linux_amd64.zip -o /tmp/tflint.zip - unzip /tmp/tflint.zip -d /tmp - chmod +x /tmp/tflint - mv /tmp/tflint /usr/local/bin/ script: - echo yes | make tf-apply