~ /yaayes.dev
Home Blog Contact
← cd ..

CI/CD Pipeline Best Practices

· by Yassine Sedrani · 4 min read

Let’s talk about CI/CD pipelines. You know, those things that either save your life or make you question your career choices at 2 AM.

The Golden Rules

After breaking production one too many times, I’ve learned these golden rules:

1. Keep Your Pipeline Fast

Nobody likes waiting 45 minutes for tests to run. Here’s how to speed things up:

  • Parallelize tests: Run independent tests concurrently
  • Cache dependencies: Don’t download the internet every time
  • Use incremental builds: Only build what changed
  • Split large test suites: Break them into smaller, faster chunks
# GitHub Actions example
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        test-suite: [unit, integration, e2e]
    steps:
      - uses: actions/checkout@v3
      - name: Cache dependencies
        uses: actions/cache@v3
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      - name: Run ${{ matrix.test-suite }} tests
        run: npm run test:${{ matrix.test-suite }}

2. Fail Fast, Fail Loud

Don’t wait until the end to find out something went wrong. The earlier you catch issues, the better:

#!/bin/bash
set -e  # Exit on any error

# Linting
echo "Running linters..."
npm run lint || exit 1

# Type checking
echo "Type checking..."
npm run type-check || exit 1

# Tests
echo "Running tests..."
npm test || exit 1

echo "✅ All checks passed!"

3. Environment Parity

Your staging environment should be as close to production as possible. Use the same:

  • Operating system
  • Runtime versions
  • Database versions
  • Configuration management

4. Automated Rollbacks

Things will break. Accept it. Plan for it.

deploy:
  steps:
    - name: Deploy
      run: ./deploy.sh
    - name: Health check
      run: ./health-check.sh
    - name: Rollback on failure
      if: failure()
      run: ./rollback.sh

Testing Strategies

The Test Pyramid

Remember this distribution:

  • 70% Unit tests: Fast, isolated, run everywhere
  • 20% Integration tests: Test component interactions
  • 10% E2E tests: Full user flows (expensive but valuable)

Don’t Skip Tests

I know, I know. You’re in a hurry. But trust me:

# This is not a test strategy
if [ "$FRIDAY" == "true" ]; then
  echo "Skipping tests, it's Friday 🍺"
  exit 0
fi

Security in CI/CD

Scan Everything

  • Container images: Use tools like Trivy
  • Dependencies: Check for known vulnerabilities
  • Secrets: Never commit them (use secret managers)
- name: Scan image
  run: |
    docker run --rm \
      aquasec/trivy image \
      --severity HIGH,CRITICAL \
      myapp:latest

Secrets Management

# ❌ BAD
- name: Deploy
  run: deploy.sh
  env:
    API_KEY: sk-1234567890abcdef

# ✅ GOOD
- name: Deploy
  run: deploy.sh
  env:
    API_KEY: ${{ secrets.API_KEY }}

Monitoring and Observability

Your pipeline should tell you:

  • ✅ What passed
  • ❌ What failed
  • ⏱️ How long it took
  • 📊 Trends over time

Common Pitfalls

  1. Flaky tests: Fix or quarantine them immediately
  2. Too many manual approvals: Automate what you can
  3. Ignoring failed builds: Treat them like production outages
  4. No rollback strategy: Always have a plan B

🚀 Level Up Your Dev Workflow

Speaking of automation and DevOps workflows… ever been stuck away from your dev machine when you need to fix something urgently? Or wanted to code from your iPad but your project requires a complex Docker environment?

Here’s the problem: Your beautiful CI/CD pipeline is worthless if you can’t access your development environment when inspiration strikes at 2 AM… from your tablet.

VS Code’s Remote Tunnels sound great in theory, but they completely fall apart with Dev Containers. Port forwarding? Only works from localhost. SSH tunneling? Yeah, good luck setting that up from a coffee shop.

I recently cracked this problem: running VS Code CLI and DevTunnel INSIDE your Docker containers with persistent authentication that survives rebuilds. The result? Your entire dev environment accessible from literally any device with a browser - iPad, phone, your friend’s laptop, even that ancient Chromebook collecting dust.

The full guide covers:

  • 🔐 Persistent authentication (no more re-authenticating after every rebuild)
  • 🌐 Public URLs for your web services without port-forwarding gymnastics
  • ⚡ Supervisor-managed tunnels that just work™
  • 😱 The authentication nightmare I went through so you don’t have to

→ Read the complete setup guide: Remote Development from Anywhere

Because the best DevOps setup is one you can access from a beach in Bali. Or your couch. We don’t judge. ☕


Conclusion

Building a good CI/CD pipeline is an iterative process. Start simple, measure everything, and continuously improve. Your future self (and your team) will thank you.

Remember: A good pipeline is one that you trust to deploy on Friday afternoon. If you’re not there yet, keep improving!

🚀 Happy deploying!

// Comments