Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions .github/workflows/ubuntu-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: ubuntu-dev

# Pull requests build the image on amd64 and arm64 for validation only (no login, no push).
# Pushes to main build both arches and publish a multi-arch manifest to DockerHub.
on:
pull_request:
paths:
- 'ubuntu-dev/**'
- '.github/workflows/ubuntu-dev.yml'
push:
branches: [main]
paths:
- 'ubuntu-dev/**'
- '.github/workflows/ubuntu-dev.yml'
workflow_dispatch:

env:
IMAGE: eloqdata/ubuntu-dev

jobs:
build:
name: build (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# Login (and therefore the password) is only used off pull requests.
# Fork PRs never receive secrets, so PR validation never touches credentials.
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
tags: |
type=raw,value=latest
type=raw,value=24.04
type=sha,prefix=sha-

- name: Generate arch-suffixed tags
id: suffixed_tags
shell: bash
run: |
arch=$(echo "${{ matrix.platform }}" | cut -d/ -f2)
echo "tags<<EOF" >> "$GITHUB_OUTPUT"
while IFS= read -r tag; do
[ -z "$tag" ] && continue
echo "${tag}-${arch}" >> "$GITHUB_OUTPUT"
done <<< "${{ steps.meta.outputs.tags }}"
echo "EOF" >> "$GITHUB_OUTPUT"

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: ./ubuntu-dev
platforms: ${{ matrix.platform }}
# PR: build only (validation). main: push the arch-suffixed image.
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.suffixed_tags.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.platform }}-ubuntu-dev
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}-ubuntu-dev

merge:
name: merge manifest
if: github.event_name != 'pull_request'
needs: build
runs-on: ubuntu-24.04
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
tags: |
type=raw,value=latest
type=raw,value=24.04
type=sha,prefix=sha-

- name: Create and push manifest list
shell: bash
run: |
while IFS= read -r tag; do
[ -z "$tag" ] && continue
echo "Merging manifests for $tag"
docker buildx imagetools create -t "$tag" \
"${tag}-amd64" \
"${tag}-arm64"
done <<< "${{ steps.meta.outputs.tags }}"

- name: Inspect
run: docker buildx imagetools inspect ${{ env.IMAGE }}:24.04
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,44 @@
# eloq-docker
# eloq-docker

Docker images for EloqData development.

## Images

### `eloqdata/ubuntu-dev`

A lightweight Ubuntu 24.04 development image containing the build toolchain and libraries that
EloqData projects need, installed entirely via `apt` (compilers, CMake/Ninja, common C/C++ dev
libraries, Python 3, Node.js, Go, the JDK, and the Google Cloud CLI). It runs as a non-root user
`eloq` with passwordless `sudo`.

Pull it (Docker automatically selects `amd64` or `arm64` for your machine):

```sh
docker pull eloqdata/ubuntu-dev:24.04
```

Tags: `latest`, `24.04`, and `sha-<commit>`.

Build locally:

```sh
docker build -t eloqdata/ubuntu-dev ./ubuntu-dev
```

## CI

`.github/workflows/ubuntu-dev.yml` builds the image on native `amd64` and `arm64` runners:

- **Pull requests** build both architectures for validation (no login, no push).
- **Pushes to `main`** build and push each architecture, then merge them into a single multi-arch
manifest published to DockerHub.

### Required repository secrets

| Secret | Value |
| --- | --- |
| `DOCKER_USERNAME` | DockerHub username with write access to `eloqdata/ubuntu-dev` |
| `DOCKER_PASSWORD` | That account's DockerHub password (or access token) |

Configure them in **Settings → Secrets and variables → Actions**. They are encrypted at rest and
automatically masked in build logs.
43 changes: 43 additions & 0 deletions ubuntu-dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive
ENV PATH=/home/eloq/.local/bin:$PATH

# Force IPv4 for apt to avoid flaky IPv6 mirrors.
RUN echo 'Acquire::ForceIPv4 "true";' > /etc/apt/apt.conf.d/99force-ipv4

# Development toolchain and libraries — everything here is installable via apt.
RUN apt-get update && apt-get install -y --no-install-recommends \
jq sudo vim wget curl gnupg apt-transport-https apt-utils \
python3 python3-dev python3-pip python3-venv \
gdb lcov ccache rsync \
build-essential gcc g++ make cmake ninja-build m4 bison pkg-config patchelf \
git openssh-client openssh-server \
openjdk-11-jdk golang nodejs npm \
libprotobuf-dev protobuf-compiler \
libcurl4-openssl-dev libssl-dev openssl gnutls-dev \
libncurses5-dev ncurses-dev libreadline-dev \
zlib1g-dev libbz2-dev liblz4-dev libzstd-dev liblzma-dev \
libuv1-dev libgflags-dev libleveldb-dev libsnappy-dev libjsoncpp-dev \
libboost-context-dev libboost-stacktrace-dev \
libc-ares-dev libc-ares2 libsqlite3-dev libffi-dev \
ca-certificates tar redis tcl \
&& rm -rf /var/lib/apt/lists/*

# Google Cloud CLI (installed from Google's apt repository).
RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg \
| gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \
> /etc/apt/sources.list.d/google-cloud-sdk.list \
&& apt-get update && apt-get install -y --no-install-recommends google-cloud-cli \
&& rm -rf /var/lib/apt/lists/*

# Non-root user with passwordless sudo (no password is baked into the image).
RUN useradd -rm -s /bin/bash -g sudo eloq \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& ln -sf /usr/bin/python3 /usr/bin/python \
&& mkdir -p /var/crash && chown -R eloq /var/crash

USER eloq
WORKDIR /home/eloq
RUN mkdir -p /home/eloq/workspace
Loading