Auto-deploy smoothie
Ayman Bagabas
created 4 years ago
- Use GoReleaser
- Add Dockerfile based on Alpine:latest
- Publish docker images to our private ghcr.io registry
- Run build and test using GH Actions (ci.yml)
- Deploy AWS ECS Docker instance to our AWS infrastructure using GH
Actions (cd.yml)
Note: repository secrets are used to make the auto-deploy work. All
the secrets used are in our Gopass repository. `GITHUB_TOKEN` is a
reserved GH Actions secret with basic permissions like pushing to
organization registries.
Change summary
.github/workflows/cd.yml | 156 ++++++++++++++++++++++++++++++++++++++++++
.github/workflows/ci.yml | 33 ++++++++
.gitignore | 4 +
.goreleaser.yml | 37 +++++++++
Dockerfile | 22 +++++
main.tf | 39 ++++++++++
6 files changed, 291 insertions(+)
Detailed changes
@@ -0,0 +1,156 @@
+name: CD
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+
+jobs:
+ cd:
+ strategy:
+ matrix:
+ go-version: [~1.16]
+ runs-on: ubuntu-latest
+ env:
+ GO111MODULE: "on"
+ CONTAINER_REPO: "ghcr.io/${{ github.repository }}"
+ ENVIRONMENT: development
+ AWS_DEFAULT_REGION: us-east-1
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+
+ steps:
+ - name: Install Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: ${{ matrix.go-version }}
+
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ # Remove this later
+ - name: Clone internal repositories
+ run: |
+ git clone -b release https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/charm-internal ../charm
+ git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/bubbletea-internal ../bubbletea
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v1
+ if: github.event_name == 'push'
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build Docker images using GoReleaser
+ uses: goreleaser/goreleaser-action@master
+ if: github.event_name == 'push'
+ with:
+ version: latest
+ # https://github.com/goreleaser/goreleaser/discussions/1534
+ args: -f .goreleaser.yml --snapshot
+
+ - name: Push Docker images
+ if: github.event_name == 'push'
+ run: |
+ docker push $CONTAINER_REPO:snapshot
+ docker push $CONTAINER_REPO:$GITHUB_SHA-snapshot
+
+ - name: Setup Terraform
+ uses: hashicorp/setup-terraform@v1
+ with:
+ # terraform_version: 0.13.0
+ cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
+
+ - name: Terraform Variables
+ id: tfvars
+ run: |
+ TF_VARS=$(cat <<EOF
+ -var "environment=$ENVIRONMENT" \
+ -var "aws_region=$AWS_DEFAULT_REGION" \
+ -var "app_image=$CONTAINER_REPO:$GITHUB_SHA-snapshot"
+ EOF
+ )
+ echo "::set-output name=vars::$TF_VARS"
+
+ - name: Terraform Format
+ id: fmt
+ run: terraform fmt -check
+
+ - name: Terraform Init
+ id: init
+ run: terraform init
+
+ - name: Terraform Validate
+ id: validate
+ run: terraform validate -no-color
+
+ - name: Terraform Plan
+ id: plan
+ if: github.event_name == 'pull_request'
+ run: terraform plan -no-color ${{ steps.tfvars.outputs.vars }}
+ continue-on-error: true
+
+ - name: Find Comment
+ if: github.event_name == 'pull_request'
+ uses: peter-evans/find-comment@v1.2.0
+ id: fc
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-author: github-actions[bot]
+ body-includes: Terraform Summary
+
+ - name: Update Pull Request
+ uses: actions/github-script@0.9.0
+ if: github.event_name == 'pull_request'
+ env:
+ PLAN: "${{ steps.plan.outputs.stdout }}"
+ COMMENT_ID: "${{ steps.fc.outputs.comment-id }}"
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const output = `## Terraform Summary
+ - Terraform Format and Style 🖌 \`${{ steps.fmt.outcome }}\`
+ - Terraform Initialization ⚙️ \`${{ steps.init.outcome }}\`
+ - Terraform Plan 📖 \`${{ steps.plan.outcome }}\`
+ - Terraform Validation 🤖 \`${{ steps.validate.outcome }}\`
+
+ <details><summary>Show Plan</summary>
+
+ \`\`\`\n
+ ${process.env.PLAN}
+ \`\`\`
+
+ </details>
+
+ *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
+
+ if (process.env.COMMENT_ID) {
+ github.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: process.env.COMMENT_ID,
+ body: output
+ })
+ } else {
+ github.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: output
+ })
+ }
+
+ - name: Terraform Plan Status
+ if: steps.plan.outcome == 'failure'
+ run: exit 1
+
+
+ - name: Terraform Apply
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+ run: terraform apply -auto-approve ${{ steps.tfvars.outputs.vars }}
+
@@ -0,0 +1,33 @@
+name: CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+
+jobs:
+
+ build:
+ strategy:
+ matrix:
+ go-version: [~1.16]
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ # Remove this later
+ - name: Clone internal repositories
+ run: |
+ git clone -b release https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/charm-internal ../charm
+ git clone -b master https://${{ secrets.ACCESS_TOKEN }}@github.com/charmbracelet/bubbletea-internal ../bubbletea
+
+ - name: Set up Go
+ uses: actions/setup-go@v2
+ with:
+ go-version: ${{ matrix.go-version }}
+
+ - name: Build
+ run: go build -v ./...
+
+ - name: Test
+ run: go test -v ./...
@@ -1,3 +1,7 @@
smoothie
.ssh
.repos
+dist
+.terraform*
+*.tfstate*
+*auto.tfvars
@@ -0,0 +1,37 @@
+project_name: smoothie
+
+env:
+ - GO111MODULE=on
+ - CGO_ENABLED=0
+
+before:
+ hooks:
+ - go mod download
+
+builds:
+ - id: "smoothie"
+ binary: "smoothie"
+ ldflags: -s -w -X main.Version={{ .Commit }}-snapshot -X main.CommitSHA={{ .Commit }}
+ goos:
+ - linux
+ goarch:
+ - amd64
+
+dockers:
+ - image_templates:
+ - "ghcr.io/charmbracelet/smoothie:snapshot"
+ - "ghcr.io/charmbracelet/smoothie:{{ .Commit }}-snapshot"
+ ids: [smoothie]
+ goarch: amd64
+ build_flag_templates:
+ - --platform=linux/amd64
+ - --label=org.opencontainers.image.title={{ .ProjectName }}
+ - --label=org.opencontainers.image.description={{ .ProjectName }}
+ - --label=org.opencontainers.image.url=https://github.com/charmbracelet/smoothie
+ - --label=org.opencontainers.image.source=https://github.com/charmbracelet/smoothie
+ - --label=org.opencontainers.image.version={{ .Commit }}-snapshot
+ - --label=org.opencontainers.image.created={{ .Date }}
+ - --label=org.opencontainers.image.revision={{ .FullCommit }}
+ - --label=org.opencontainers.image.licenses=MIT
+ dockerfile: Dockerfile
+ use: buildx
@@ -0,0 +1,22 @@
+FROM alpine:latest
+
+RUN apk update && apk add --update nfs-utils git && rm -rf /var/cache/apk/*
+
+COPY smoothie /usr/local/bin/smoothie
+
+# Create directories
+WORKDIR /smoothie
+# Expose data volume
+VOLUME /smoothie
+
+# Environment variables
+ENV SMOOTHIE_KEY_PATH "/smoothie/ssh/smoothie_server_ed25519"
+ENV SMOOTHIE_REPO_KEYS_PATH "/smoothie/ssh/smoothie_git_authorized_keys"
+ENV SMOOTHIE_REPO_PATH "/smoothie/repos"
+
+# Expose ports
+# SSH
+EXPOSE 23231/tcp
+
+# Set the default command
+ENTRYPOINT [ "/usr/local/bin/smoothie" ]
@@ -0,0 +1,39 @@
+terraform {
+ backend "s3" {
+ bucket = "charm-terraform-state"
+ key = "smoothie-development"
+ region = "us-east-1"
+ }
+}
+
+variable "environment" {
+ default = "development"
+}
+
+variable "aws_region" {
+ default = "us-east-1"
+}
+
+variable "app_image" {
+ default = "ghcr.io/charmbracelet/smoothie:snapshot"
+}
+
+variable "force_new_deployment" {
+ default = false
+}
+
+module "smoothie" {
+ # source = "../terraform-aws-smoothie"
+ source = "app.terraform.io/charm/smoothie/aws"
+ version = "0.1.2"
+
+ environment = var.environment
+ aws_region = var.aws_region
+ ecs_task_execution_role_name = "smoothieEcsTaskExecutionRole-${var.environment}"
+ app_image = var.app_image
+ app_count = 2
+ app_ssh_port = 23231
+ fargate_cpu = "1024"
+ fargate_memory = "2048"
+ force_new_deployment = var.force_new_deployment
+}