Skip to content

Commit ea138f4

Browse files
committed
(locally) Build & push lading container script
1 parent 530bc15 commit ea138f4

2 files changed

Lines changed: 183 additions & 4 deletions

File tree

Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ENV CARGO_INCREMENTAL=0
1818
WORKDIR /app
1919
RUN apt-get update && apt-get install -y \
2020
pkg-config=1.8.1-1 \
21-
libssl-dev=3.0.17-1~deb12u3 \
21+
libssl-dev=3.0.18-1~deb12u2 \
2222
protobuf-compiler=3.21.12-3 \
2323
fuse3=3.14.0-4 \
2424
libfuse3-dev=3.14.0-4 \
@@ -43,7 +43,7 @@ RUN --mount=type=secret,id=aws_access_key_id \
4343
export AWS_ACCESS_KEY_ID=$(cat /run/secrets/aws_access_key_id) && \
4444
export AWS_SECRET_ACCESS_KEY=$(cat /run/secrets/aws_secret_access_key) && \
4545
export AWS_SESSION_TOKEN=$(cat /run/secrets/aws_session_token) && \
46-
export RUSTC_WRAPPER=sccache && \
46+
if [ -n "${SCCACHE_BUCKET:-}" ]; then export RUSTC_WRAPPER=sccache; fi && \
4747
cargo chef cook --release --locked --features logrotate_fs --recipe-path recipe.json
4848

4949
# Stage 2: Builder - Build source code
@@ -56,7 +56,7 @@ ENV SCCACHE_REGION=${SCCACHE_REGION}
5656
WORKDIR /app
5757
RUN apt-get update && apt-get install -y \
5858
pkg-config=1.8.1-1 \
59-
libssl-dev=3.0.17-1~deb12u3 \
59+
libssl-dev=3.0.18-1~deb12u2 \
6060
protobuf-compiler=3.21.12-3 \
6161
fuse3=3.14.0-4 \
6262
libfuse3-dev=3.14.0-4 \
@@ -74,7 +74,7 @@ RUN --mount=type=secret,id=aws_access_key_id \
7474
export AWS_ACCESS_KEY_ID=$(cat /run/secrets/aws_access_key_id) && \
7575
export AWS_SECRET_ACCESS_KEY=$(cat /run/secrets/aws_secret_access_key) && \
7676
export AWS_SESSION_TOKEN=$(cat /run/secrets/aws_session_token) && \
77-
export RUSTC_WRAPPER=sccache && \
77+
if [ -n "${SCCACHE_BUCKET:-}" ]; then export RUSTC_WRAPPER=sccache; fi && \
7878
cargo build --release --locked --bin lading --features logrotate_fs
7979

8080
# Stage 3: Runtime

ci/container-build-and-push

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env bash
2+
set -o errexit
3+
set -o nounset
4+
set -o pipefail
5+
6+
ECR_REGISTRY="850406765696.dkr.ecr.us-west-2.amazonaws.com"
7+
ECR_REPO="${ECR_REGISTRY}/lading"
8+
AWS_VAULT_PROFILE="smp"
9+
10+
usage() {
11+
cat <<EOF
12+
Usage: ci/container-build-and-push [OPTIONS]
13+
14+
Build and push lading Docker images to ECR.
15+
16+
Options:
17+
--tag TAG Image tag (default: git commit SHA)
18+
--arch ARCH Architecture(s): amd64, arm64, or amd64,arm64 (default: amd64,arm64)
19+
--profile PROFILE aws-vault profile (default: smp)
20+
--no-push Build only, don't push to ECR
21+
-h, --help Show this help
22+
23+
Examples:
24+
ci/container-build-and-push # build both amd64+arm64, tag from git SHA
25+
ci/container-build-and-push --tag v0.32.0 # explicit tag
26+
ci/container-build-and-push --arch amd64,arm64 # multi-arch build
27+
ci/container-build-and-push --no-push # build only
28+
EOF
29+
exit 0
30+
}
31+
32+
# Parse arguments
33+
TAG=""
34+
ARCH=""
35+
PUSH=true
36+
37+
while [[ $# -gt 0 ]]; do
38+
case "$1" in
39+
--tag) TAG="$2"; shift 2 ;;
40+
--arch) ARCH="$2"; shift 2 ;;
41+
--profile) AWS_VAULT_PROFILE="$2"; shift 2 ;;
42+
--no-push) PUSH=false; shift ;;
43+
-h|--help) usage ;;
44+
*) echo "Unknown option: $1"; usage ;;
45+
esac
46+
done
47+
48+
# Check prerequisites
49+
for cmd in docker aws aws-vault jq; do
50+
if ! command -v "$cmd" &>/dev/null; then
51+
echo "Error: $cmd is not installed"
52+
exit 1
53+
fi
54+
done
55+
56+
# Ensure buildx is available
57+
if ! docker buildx version &>/dev/null; then
58+
echo "Error: Docker Buildx is not available"
59+
exit 1
60+
fi
61+
62+
# Check Docker has enough memory for release builds with LTO
63+
MIN_MEMORY_GB=16
64+
DOCKER_MEM_BYTES=$(docker info --format '{{.MemTotal}}' 2>/dev/null || echo 0)
65+
DOCKER_MEM_GB=$(( DOCKER_MEM_BYTES / 1073741824 ))
66+
if [[ "$DOCKER_MEM_GB" -lt "$MIN_MEMORY_GB" ]]; then
67+
echo "Error: Docker has ${DOCKER_MEM_GB} GB of memory, but at least ${MIN_MEMORY_GB} GB is required"
68+
echo "Increase memory in Docker Desktop → Settings → Resources"
69+
exit 1
70+
fi
71+
echo "Docker memory: ${DOCKER_MEM_GB} GB"
72+
73+
# Default to both architectures if not specified
74+
if [[ -z "$ARCH" ]]; then
75+
ARCH="amd64,arm64"
76+
echo "Defaulting to both architectures: ${ARCH}"
77+
fi
78+
79+
# Determine tag
80+
if [[ -z "$TAG" ]]; then
81+
TAG="sha-$(git rev-parse HEAD)"
82+
echo "Using git SHA tag: ${TAG}"
83+
fi
84+
85+
# Parse architectures
86+
IFS=',' read -ra ARCHS <<< "$ARCH"
87+
MULTI_ARCH=false
88+
if [[ ${#ARCHS[@]} -gt 1 ]]; then
89+
MULTI_ARCH=true
90+
fi
91+
92+
# Build platform string
93+
PLATFORMS=""
94+
for a in "${ARCHS[@]}"; do
95+
if [[ -n "$PLATFORMS" ]]; then
96+
PLATFORMS="${PLATFORMS},"
97+
fi
98+
PLATFORMS="${PLATFORMS}linux/${a}"
99+
done
100+
101+
# Set up QEMU for cross-arch builds
102+
if [[ "$MULTI_ARCH" == "true" ]]; then
103+
echo "Setting up QEMU for multi-arch builds..."
104+
docker run --rm --privileged tonistiigi/binfmt --install all >/dev/null 2>&1 || true
105+
fi
106+
107+
# Authenticate to ECR using a temporary docker config to avoid macOS credsStore issues.
108+
# We copy the real docker config (minus credsStore) and symlink cli-plugins so that
109+
# docker login can write credentials as plain JSON and buildx still works.
110+
DOCKER_CONFIG_DIR=""
111+
cleanup() {
112+
if [[ -n "$DOCKER_CONFIG_DIR" ]]; then
113+
rm -rf "$DOCKER_CONFIG_DIR"
114+
fi
115+
}
116+
trap cleanup EXIT
117+
118+
if [[ "$PUSH" == "true" ]]; then
119+
echo "Authenticating to ECR..."
120+
REAL_DOCKER_CONFIG="${DOCKER_CONFIG:-${HOME}/.docker}"
121+
DOCKER_CONFIG_DIR="$(mktemp -d)"
122+
# Copy config without credsStore/credHelpers so docker login writes auth as plain JSON
123+
jq 'del(.credsStore, .credHelpers)' "${REAL_DOCKER_CONFIG}/config.json" \
124+
> "${DOCKER_CONFIG_DIR}/config.json"
125+
# Symlink subdirectories so buildx CLI plugin and Docker contexts are found
126+
for subdir in cli-plugins contexts; do
127+
if [[ -d "${REAL_DOCKER_CONFIG}/${subdir}" ]]; then
128+
ln -s "${REAL_DOCKER_CONFIG}/${subdir}" "${DOCKER_CONFIG_DIR}/${subdir}"
129+
fi
130+
done
131+
aws-vault exec "$AWS_VAULT_PROFILE" -- \
132+
aws ecr get-login-password --region us-west-2 \
133+
| DOCKER_CONFIG="$DOCKER_CONFIG_DIR" docker login --username AWS --password-stdin "$ECR_REGISTRY"
134+
export DOCKER_CONFIG="$DOCKER_CONFIG_DIR"
135+
fi
136+
137+
# Create/use a buildx builder that supports multi-platform
138+
BUILDER_NAME="lading-builder"
139+
if ! docker buildx inspect "$BUILDER_NAME" &>/dev/null; then
140+
echo "Creating buildx builder: ${BUILDER_NAME}"
141+
docker buildx create --name "$BUILDER_NAME" --driver docker-container --use
142+
else
143+
docker buildx use "$BUILDER_NAME"
144+
fi
145+
146+
# Build image tags
147+
BUILD_TAGS=("--tag" "${ECR_REPO}:${TAG}")
148+
149+
PUSH_FLAG=""
150+
if [[ "$PUSH" == "true" ]]; then
151+
PUSH_FLAG="--push"
152+
elif [[ "$MULTI_ARCH" != "true" ]]; then
153+
PUSH_FLAG="--load"
154+
fi
155+
156+
# Build (multi-arch builds both platforms in parallel within a single buildx invocation)
157+
echo "Building for platform(s): ${PLATFORMS}"
158+
echo "Tag: ${TAG}"
159+
160+
docker buildx build \
161+
--platform "$PLATFORMS" \
162+
--build-arg SCCACHE_BUCKET="" \
163+
--build-arg SCCACHE_REGION="" \
164+
--build-arg AWS_ACCESS_KEY_ID="" \
165+
--build-arg AWS_SECRET_ACCESS_KEY="" \
166+
--build-arg AWS_SESSION_TOKEN="" \
167+
--secret "id=aws_access_key_id,src=/dev/null" \
168+
--secret "id=aws_secret_access_key,src=/dev/null" \
169+
--secret "id=aws_session_token,src=/dev/null" \
170+
"${BUILD_TAGS[@]}" \
171+
${PUSH_FLAG} \
172+
-f Dockerfile \
173+
.
174+
175+
if [[ "$PUSH" == "true" ]]; then
176+
echo "Pushed to ${ECR_REPO}:${TAG}"
177+
else
178+
echo "Build complete (not pushed)"
179+
fi

0 commit comments

Comments
 (0)