Kahibaro
Discord Login Register

GitHub Actions

Understanding GitHub Actions in a Linux Context

GitHub Actions is GitHub’s built-in automation platform for CI/CD and workflow automation. In a Linux-focused workflow, you primarily run jobs on Linux runners, build and test Linux-targeted software, and use Linux tooling inside your pipelines.

This chapter focuses on how to use GitHub Actions effectively when your targets, tools, or deployment environments are Linux.

Core Concepts: Workflows, Jobs, and Runners

At a high level:

Key Linux-related idea: a job runs in a fresh Linux environment each time (unless you cache things), so you must install dependencies inside the workflow or use prebuilt actions.

Minimal Linux-based workflow:

name: CI
on:
  push:
    branches: [ "main" ]
jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install build dependencies
        run: sudo apt-get update && sudo apt-get install -y build-essential
      - name: Build
        run: make
      - name: Run tests
        run: make test

Linux Runners: GitHub-Hosted vs Self-Hosted

GitHub-Hosted Linux Runners

These are preconfigured virtual machines maintained by GitHub.

Common labels:

Characteristics:

Linux-specific considerations:

Self-Hosted Linux Runners

Useful when:

High-level steps to set up:

  1. Provision a Linux machine (physical or VM).
  2. Install basic requirements: Git, system tools.
  3. In GitHub repository or organization: SettingsActionsRunners → add runner.
  4. Follow GitHub’s script to:
    • Download the runner binary for Linux.
    • Configure it (connects to GitHub).
    • Install as a systemd service (optional but typical).

Then in your workflow:

jobs:
  build-on-self-hosted:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - run: make

You can use custom labels for better control:

runs-on: [ self-hosted, linux, gpu ]

Linux operational concerns:

Workflow Files: Linux-Oriented Structure

Workflows are YAML files under .github/workflows/. Example layout:

.github/
  workflows/
    ci.yml
    release.yml
    nightly.yml

A typical Linux-centric CI workflow:

name: Linux CI
on:
  pull_request:
  push:
    branches: [ "main" ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
      - name: Run unit tests
        run: pytest

Linux angle:

Common Events for DevOps Workflows

Some common triggers:

Example scheduled Linux build:

on:
  schedule:
    - cron: "0 2 * * *"   # Every day at 02:00 UTC
jobs:
  nightly-linux-build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/nightly-build.sh

The cron syntax is Linux-style crontab.

Steps and Actions: Using Linux Shell and Tools

Steps

Each step is either:

Linux-specific behaviors:

- name: Build with logging
  run: |
    set -e
    mkdir -p build
    cd build
    cmake ..
    make -j"$(nproc)"

Using Official Actions with Linux

Common ones:

Example: caching pip dependencies on Linux:

- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-
- name: Install dependencies
  run: pip install -r requirements.txt

Note: runner.os will be Linux on Linux runners.

Working with Containers in GitHub Actions on Linux

Containers are very natural in a Linux CI environment.

Using a Container for a Job

Instead of installing packages repeatedly, run the job in a prebuilt Linux container image:

jobs:
  build-in-container:
    runs-on: ubuntu-latest
    container:
      image: python:3.11-slim
    steps:
      - uses: actions/checkout@v4
      - name: Install build tools
        run: |
          apt-get update
          apt-get install -y build-essential
      - name: Run tests
        run: pytest

Linux considerations:

Building and Pushing Docker Images

Common for deploying Linux-based services.

Example:

jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write  # for registry authentication with OIDC (optionally)
    steps:
      - uses: actions/checkout@v4
      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: myuser/myapp:latest

This builds a Linux container image (default base) on an Ubuntu runner.

Using Matrix Builds for Multiple Linux Versions

Matrix builds let you test across multiple OS versions or tool versions.

Example: test on multiple Ubuntu versions and Python versions:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        os: [ ubuntu-20.04, ubuntu-22.04 ]
        python-version: [ "3.9", "3.11" ]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pip install -r requirements.txt
      - run: pytest

You can also matrix different Linux distributions by using different container images instead of different runs-on labels.

Environment Variables and Secrets on Linux Runners

Environment Variables

You can set environment variables at different levels:

Example:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      BUILD_TYPE: release
    steps:
      - uses: actions/checkout@v4
      - name: Print build type
        run: echo "Build type is $BUILD_TYPE"

On Linux runners, environment variables are accessed in the usual shell way: $VAR.

Secrets

Secrets (tokens, passwords, etc.) are stored in GitHub and injected into workflows:

- name: Deploy
  env:
    SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
  run: |
    mkdir -p ~/.ssh
    echo "$SSH_KEY" > ~/.ssh/id_ed25519
    chmod 600 ~/.ssh/id_ed25519
    ssh -o StrictHostKeyChecking=no user@server.example.com "deploy.sh"

Linux-specific part: handling file permissions with chmod, using SSH tools, etc.

Artifacts and Caching on Linux

Artifacts

Artifacts are files collected from a job (e.g., compiled binaries, logs).

Example:

- name: Build binary
  run: |
    make
    ls -l build/
- name: Upload binary
  uses: actions/upload-artifact@v4
  with:
    name: linux-binary
    path: build/myapp

Later workflow or job can download them using actions/download-artifact.

Caching

actions/cache is especially valuable on Linux for:

General pattern:

- uses: actions/cache@v4
  with:
    path: ~/.cache/mytool
    key: ${{ runner.os }}-mytool-${{ hashFiles('**/lockfile') }}
    restore-keys: |
      ${{ runner.os }}-mytool-

On Linux, caches are regular directories on ext4/XFS/etc. on the runner; GitHub handles upload/download.

Linux-Focused CI Examples

C/C++ Project on Linux

name: C Build
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install deps
        run: sudo apt-get update && sudo apt-get install -y build-essential cmake
      - name: Configure
        run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
      - name: Build
        run: cmake --build build -- -j"$(nproc)"
      - name: Run tests
        run: ctest --test-dir build

Python Project with Linters and Tests on Linux

name: Python CI
on:
  push:
  pull_request:
jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('requirements*.txt') }}
          restore-keys: |
            ${{ runner.os }}-pip-
      - name: Install dependencies
        run: pip install -r requirements.txt -r requirements-dev.txt
      - name: Lint
        run: flake8 src tests
      - name: Test
        run: pytest

Deploying from GitHub Actions to Linux Servers

GitHub Actions often serves as the bridge between code and Linux servers (on-prem or cloud VMs).

Common Linux deployment methods:

  1. SSH-based deploy:
    • Copy artifacts via scp or rsync.
    • Run remote commands with ssh (e.g., restart systemd service).

Example:

   - name: Copy files
     run: |
       rsync -avz ./build/ user@server:/opt/myapp/
   - name: Restart service
     run: |
       ssh user@server "sudo systemctl restart myapp.service"
  1. Container-based deploy:
    • Build and push Docker images in Actions.
    • On the Linux host, pull new images and restart containers (manually or via tools like Docker Swarm, Kubernetes, or systemd units that run containers).
  2. Package-based deploy:
    • Build .deb or .rpm packages on Linux runner.
    • Publish to an internal repo, then upgrade on servers using apt or dnf.

These deployments usually happen in workflows triggered by tags/releases or manual workflow_dispatch events.

Security and Best Practices for Linux-Based Workflows

Debugging GitHub Actions on Linux

When workflows misbehave:

  - name: Debug script
    run: |
      set -euxo pipefail
      ./script.sh
  - run: |
      pwd
      ls -R
      env | sort

By combining GitHub Actions with Linux runners, containers, and typical Linux tooling, you can build comprehensive CI/CD pipelines that compile, test, package, and deploy software reliably to Linux environments.

Views: 19

Comments

Please login to add a comment.

Don't have an account? Register now!