Tutorial: Automating Heroku Deployments with GitHub Actions and Docker: Streamlining the Deployment Process
In this tutorial, we'll delve into the process of utilizing GitHub Actions to automate the deployment of Docker images to Heroku. By the end of this tutorial, you'll have the know-how to achieve continuous deployment for a Fastify + TypeScript application.
Dependencies
pnpm add -D typescript @types/node ts-node ts-node-dev
pnpm add fastify prisma @prisma/client
Script Configuration
{
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts",
"start": "ts-node src/index.ts",
"build": "tsc"
}
}
Setting Up the Backend
We'll start by setting up a simple backend since our primary goal lies elsewhere.
import fastify from 'fastify';
const app = fastify();
app.get('/', async (request, reply) => {
return { hello: 'world' };
});
export const createServer = async () => {
const PORT: number = Number(process.env.PORT) || 3001;
const HOST: string = process.env.HOST || '0.0.0.0';
try {
await app.listen(PORT, HOST);
console.log(`Server is listening at ${HOST}:${PORT}`);
} catch (error) {
console.error('Error starting the server:', error);
process.exit(1);
}
};
createServer();
Dockerfile Creation
Next, let's craft a Dockerfile for our application. We'll employ the Docker multi-stage build approach, which allows us to create a production image that's considerably smaller than the development one, as we don't require all the development dependencies.
FROM node:16
WORKDIR /app
COPY package.json ./
COPY pnpm-lock.yaml ./
COPY tsconfig.json ./
COPY . .
RUN npm install -g pnpm
RUN pnpm install
RUN npx prisma generate
CMD ["pnpm", "run", "start"]
docker-compose.yml Setup
Now, we'll create a docker-compose file to facilitate development.
version: "3.9"
services:
server_api:
stdin_open: true
build:
context: .
dockerfile: Dockerfile
ports:
- "3001:3001"
container_name: server_api
restart: always
volumes:
- .:/app
Understanding GitHub Actions
GitHub Actions is a powerful tool provided by GitHub that enables you to automate various workflows, including building, testing, and deploying applications. It allows you to define custom workflows using YAML files, which can be triggered by events such as pushes, pull requests, or even on a schedule.
Creating the Workflow
Let's proceed to establish the GitHub Actions workflow. For this, create a file named deploy.yml
within the .github/workflows
directory.
name: Deploy to Heroku
on:
push:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build, Push and Release a Docker container to Heroku
uses: gonuit/heroku-docker-deploy@v1.3.3
with:
email: ${{ secrets.HEROKU_EMAIL }}
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: ${{ secrets.HEROKU_APP_NAME }}
dockerfile_directory: ./
dockerfile_name: Dockerfile
docker_options: "--no-cache"
process_type: web
In this workflow:
- We define the workflow's name and specify that it should trigger on pushes to the
master
branch. - The workflow runs on an
ubuntu-latest
virtual environment. - We set up Node.js using the
actions/setup-node
action. - Dependencies are installed using
pnpm
. - We build a Docker image for our Fastify app.
- We log in to the Heroku container registry.
- The Docker image is pushed to Heroku.
- Finally, the Docker image is released on Heroku.
Remember to replace your-heroku-app-name
with your actual Heroku app name.
Finalizing
In this tutorial, we've covered a comprehensive process for automating the deployment of a Dockerized Fastify + TypeScript application to Heroku using GitHub Actions. We started by setting up the backend, creating a Dockerfile, and configuring the docker-compose.yml
file for easier development. We introduced GitHub Actions, explaining its significance in automating workflows. Finally, we created a GitHub Actions workflow that builds, pushes, and releases a Docker container to Heroku upon pushing changes to the master
branch.
By embracing this automated deployment process, you can significantly enhance the efficiency and reliability of your application deployments, saving valuable time and minimizing manual errors.
Top comments (0)