Urgent.News

What's breaking now, across thousands of outlets.

Tech

A Simple CI/CD Pipeline That Actually Works

The Problem with Most CI/CD Tutorials Most tutorials show you a pipeline that deploys a "hello world" app to a free Heroku instance. They skip the messy parts: secrets, rollbacks, and the moment your pipeline breaks because a dependency changed. I've been there. After years of fighting with over-engineered setups, I settled on a minimal pipeline that's easy to understand, debug, and extend. It's…

Many CI/CD tutorials lead readers through a complex pipeline deploying a simple "Hello World" application to a free service. However, these setups often omit critical aspects like secrets management, rollback procedures, and handling dependency changes. After struggling with overly complicated systems, the author settled on a straightforward pipeline that is easy to grasp, debug, and expand upon. It may not be flashy, but it effectively accomplishes the task.

The core of the pipeline consists of three stages: testing, building, and deploying. These stages can be implemented using various CI/CD tools like GitHub Actions, GitLab CI, CircleCI, or Jenkins, though the example uses GitHub Actions due to its free tier and seamless integration with other services.

To set up the pipeline, create a file named `.github/workflows/deploy.yml` in your repository. This YAML file defines the workflow, specifying when it should run (on pushes to the main branch or pull requests to the main branch) and the jobs it comprises.

The first job, named "test," executes on every push and pull request. It checks out the code, installs dependencies using `npm ci` (which respects the package-lock.json file), and runs the test suite. The job runs only if the current commit passes all tests, thanks to the `needs: test` dependency. This prevents the deployment job from running in case of test failures.

The second job, "build-and-deploy," runs on pushes to the main branch only. It builds the application into a `dist` directory. For a Node.js project, this might involve running a bundler like Vite or Webpack. For a Python project, you would use a command like `python -m build` instead. This stage ensures that only the built artifacts are deployed to the production server.

The third and final job, "deploy," uses the `scp-action` to copy the contents of the `dist` folder to a designated directory on a remote server. This action utilizes SSH keys for secure file transfer. By storing sensitive information such as server host, username, and private key as GitHub secrets, you avoid hardcoding credentials in the workflow file.

It is essential to create a dedicated user with limited permissions on the server to minimize security risks. In case of a rollback, simply extract the last backup of the `dist` folder from the server.

When setting up secrets, navigate to your GitHub repository settings, then to Secrets and Variables under Actions. Add the required secrets: `SERVER_HOST` (your server's IP or domain), `SERVER_USER` (SSH username, typically 'deploy' or 'ubuntu'), and `SSH_PRIVATE_KEY` (the private key associated with the deploy user's SSH key pair).

Before committing code, test the pipeline locally by running `npm test` and `npm run build`. If both commands succeed, push changes to the main branch to trigger the GitHub Actions workflow. Monitor the Actions tab in your repository to observe the pipeline's progress.

Common pitfalls to avoid include ensuring the SSH key is in the correct format (OpenSSH, not PuTTY), adjusting the source path in the deployment step to match your project's build output directory, and setting appropriate file permissions on the server to allow the deploy user write access to the target directory.

Once the pipeline is functional, consider extending it with additional features such as linting, database migrations, or notifications. However, add these enhancements only when necessary to maintain the pipeline's simplicity and ease of troubleshooting.

This minimalistic approach to CI/CD provides a solid foundation for small projects, side initiatives, and even certain production environments. By starting simple, you can quickly verify that the pipeline works as expected. As requirements grow, iteratively add complexity and new features to the pipeline. This strategy ensures that your deployment process remains manageable and effective over time.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

App Health Endpoint Design: 3 Probes That Keep Logging and Metrics Useful

Short answer: for a Node.js app in Docker or Kubernetes, give startup, readiness, and liveness probes separate meanings, keep routine health traffic out of application logging, and measure state…

  • Startup probe checks initialization completion
  • Readiness probe assesses safe request handling
  • Liveness probe detects process stuck state

More from Tuesday 25 August →