Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: refactor docker images #4561

Merged
merged 1 commit into from
Feb 5, 2025
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
61 changes: 37 additions & 24 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ jobs:
name: Build and test
runs-on: ubuntu-latest
outputs:
gitsha: ${{ steps.setDockerSHAs.outputs.gitsha }}
image_sha: ${{ steps.setDockerSHAs.outputs.image_sha }}
image_version: ${{ steps.setDockerSHAs.outputs.image_version }}
build_version: ${{ steps.setDockerSHAs.outputs.build_version }}
timeout-minutes: 20
steps:
- name: Checkout
Expand Down Expand Up @@ -82,8 +84,17 @@ jobs:
# We lint/test/build affected but in order to build image, we need to ensure everything
# is built. Build anything that hasn't been built yet (takes advantage of nx cache
# for anything already built from above)
npx nx run-many -t build --all
echo "GITSHA=`echo $(echo ${{ steps.setNxSHAs.outputs.head }} | cut -c1-8).${{ github.run_number }}.${{ github.run_attempt }}`" >> "$GITHUB_OUTPUT"
npx nx run-many -t build

# build values for docker image tags
VERSION_SUFFIX=${{ github.run_number }}.${{ github.run_attempt }}
FULL_SHA=${{ steps.setNxSHAs.outputs.head }}
# instead of using rev-parse we always just get the first 8 characters but we'll ensure
# its unique (just in case 8 is not enough) by appending the VERSION_SUFFIX
SHORT_SHA=$(echo ${FULL_SHA} | cut -c1-8)
echo "IMAGE_SHA=${FULL_SHA}" >> "$GITHUB_OUTPUT"
echo "IMAGE_VERSION=${FULL_SHA}.${VERSION_SUFFIX}" >> "$GITHUB_OUTPUT"
echo "BUILD_VERSION=${SHORT_SHA}.${VERSION_SUFFIX}" >> "$GITHUB_OUTPUT"

- name: Set up docker buildx
uses: docker/setup-buildx-action@v3
Expand All @@ -93,11 +104,11 @@ jobs:
uses: docker/metadata-action@v5
with:
tags: |
type=raw,value=${{ steps.setDockerSHAs.outputs.gitsha }}
type=raw,value=${{ steps.setDockerSHAs.outputs.image_version }}
type=ref,event=branch
type=ref,event=pr
labels: |
org.opencontainers.image.version=${{ steps.setDockerSHAs.outputs.gitsha }}
org.opencontainers.image.version=${{ steps.setDockerSHAs.outputs.image_version }}

- name: Cache for docker
id: cache
Expand Down Expand Up @@ -125,7 +136,7 @@ jobs:
load: true
file: ./apps/platform/Dockerfile
build-args: |
GITSHA=${{ steps.setDockerSHAs.outputs.gitsha }}
BUILD_VERSION=${{ steps.setDockerSHAs.outputs.build_version }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
outputs: |
Expand All @@ -140,7 +151,7 @@ jobs:

- name: Integration and e2e tests
env:
GITSHA: ${{ steps.setDockerSHAs.outputs.gitsha }}
APP_IMAGE: ${{ steps.setDockerSHAs.outputs.image_version }}
run: |
./scripts/seed-etc-hosts.sh

Expand Down Expand Up @@ -274,29 +285,31 @@ jobs:
- name: Push image to ECR
id: pushImageToECR
env:
LOCAL_IMAGE_TAG: ${{ needs.build.outputs.gitsha }}
REGISTRY_IMAGE_TAG: ${{ steps.login-ecr.outputs.registry }}/uesio:${{ needs.build.outputs.gitsha }}
IMAGE_VERSION_TAG: ${{ needs.build.outputs.image_version }}
IMAGE_SHA_TAG: ${{ needs.build.outputs.image_sha }}-latest
REGISTRY_IMAGE_TAG_BASE: ${{ steps.login-ecr.outputs.registry }}/uesio
run: |
echo "LOCAL_IMAGE_TAG=${LOCAL_IMAGE_TAG}" >> "$GITHUB_OUTPUT"
echo "REGISTRY_IMAGE_TAG=${REGISTRY_IMAGE_TAG}" >> "$GITHUB_OUTPUT"
REGISTRY_SHA_TAG=${REGISTRY_IMAGE_TAG_BASE}:${IMAGE_SHA_TAG}
REGISTRY_VERSION_TAG=${REGISTRY_IMAGE_TAG_BASE}:${IMAGE_VERSION_TAG}
echo "REGISTRY_VERSION_TAG=${REGISTRY_VERSION_TAG}" >> "$GITHUB_OUTPUT"
docker load --input ${{ runner.temp }}/uesio-image.tar
docker tag $LOCAL_IMAGE_TAG $REGISTRY_IMAGE_TAG
docker image push $REGISTRY_IMAGE_TAG
docker tag $IMAGE_VERSION_TAG $REGISTRY_SHA_TAG
docker tag $IMAGE_VERSION_TAG $REGISTRY_VERSION_TAG
docker image push $REGISTRY_IMAGE_TAG_BASE

- name: Update docker container image tag for dev
env:
LOCAL_IMAGE_TAG: ${{ steps.pushImageToECR.outputs.LOCAL_IMAGE_TAG }}
REGISTRY_IMAGE_TAG: ${{ steps.pushImageToECR.outputs.REGISTRY_IMAGE_TAG }}
appTaskDefPath: ./aws/dev/ecs/task_definitions/uesio_web.json
workerTaskDefPath: ./aws/dev/ecs/task_definitions/uesio_worker.json
REGISTRY_VERSION_TAG: ${{ steps.pushImageToECR.outputs.registry_version_tag }}
APP_TASK_DEF_PATH: ./aws/dev/ecs/task_definitions/uesio_web.json
WORKER_TASK_DEF_PATH: ./aws/dev/ecs/task_definitions/uesio_worker.json
run: |
echo "Docker image SHA updated to $LOCAL_IMAGE_TAG"
jq --arg img "$REGISTRY_IMAGE_TAG" '.containerDefinitions[0].image = $img' $appTaskDefPath > tmp1.json
jq --arg img "$REGISTRY_IMAGE_TAG" '.containerDefinitions[0].image = $img' $workerTaskDefPath > tmp2.json
mv tmp1.json $appTaskDefPath
mv tmp2.json $workerTaskDefPath
echo "Docker image SHA updated to $REGISTRY_VERSION_TAG"
jq --arg img "$REGISTRY_VERSION_TAG" '.containerDefinitions[0].image = $img' $APP_TASK_DEF_PATH > tmp1.json
jq --arg img "$REGISTRY_VERSION_TAG" '.containerDefinitions[0].image = $img' $WORKER_TASK_DEF_PATH > tmp2.json
mv tmp1.json $APP_TASK_DEF_PATH
mv tmp2.json $WORKER_TASK_DEF_PATH
git config user.name github-actions
git config user.email [email protected]
git add $appTaskDefPath $workerTaskDefPath
git commit -m "ci: Auto-update dev image to $LOCAL_IMAGE_TAG"
git add $APP_TASK_DEF_PATH $WORKER_TASK_DEF_PATH
git commit -m "ci: Auto-update dev image to $REGISTRY_VERSION_TAG"
git push
82 changes: 49 additions & 33 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,66 @@ on:
push:
tags:
- "v*"
secrets:
AWS_ACCOUNT_ID_DEV:
required: true
AWS_ECR_ROLE_DEV:
required: true
AWS_REGION_DEV:
required: true

# Request permissions to be able to create releases
permissions:
id-token: write # Needed to assume role using AWS OIDC provider
actions: write # Access to Github actions
contents: write # This is required for actions/checkout

env:
GO_CACHE_INFO_FILE: wf-go-cache-info.txt

jobs:
docker_publish_to_ghcr:
name: Publish to GitHub Container Registry
runs-on: ubuntu-latest
permissions: write-all
permissions:
id-token: write # This is required for requesting a OIDC JWT for AWS
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Login to GitHub Container Registry
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ECR_ROLE_DEV }}
role-session-name: ecrpull
aws-region: ${{ secrets.AWS_REGION_DEV }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Pull the latest Docker image from ECR
shell: bash
env:
FULL_SHA: ${{ github.sha }}
REGISTRY_ID: ${{ secrets.AWS_ACCOUNT_ID_DEV }}
IMAGE_TAG: ${{ steps.login-ecr.outputs.registry }}/uesio:${{ github.sha }}
SHA_TAG: ${{ github.sha }}-latest
ECR_REGISTRY_ID: ${{ secrets.AWS_ACCOUNT_ID_DEV }}
ECR_REGISTRY_URI: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY_NAME: uesio
GHCR_IMAGE_TAG_BASE: ghcr.io/${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
# Make sure that the Docker image for this commit exists in ECR
image_exists=$(bash ./scripts/ecr-image-exists.sh $REGISTRY_ID uesio $FULL_SHA)
IMAGE_EXISTS=$(bash ./scripts/ecr-image-exists.sh $ECR_REGISTRY_ID $ECR_REPOSITORY_NAME $SHA_TAG)
if [[ "$image_exists" == "no" ]]; then
echo "Docker image does not exist in ECR"
if [[ "$IMAGE_EXISTS" == "no" ]]; then
echo "Docker image does not exist in ECR for tag $SHA_LATEST_TAG"
exit 1
fi
echo "Pulling Docker image from ECR..."
docker pull $IMAGE_TAG
echo "Pushing tag $RELEASE_TAG to Github Container Registry..."=
docker tag $IMAGE_TAG $GHCR_IMAGE_TAG_BASE:$RELEASE_TAG
docker push $GHCR_IMAGE_TAG_BASE:$RELEASE_TAG
echo "Pushing latest tag to Github Container Registry..."
docker tag $IMAGE_TAG $GHCR_IMAGE_TAG_BASE:latest
docker push $GHCR_IMAGE_TAG_BASE:latest
ECR_SHA_TAG=${ECR_REGISTRY_URI}/${ECR_REPOSITORY_NAME}:${SHA_TAG}
echo "Pulling Docker image $ECR_SHA_TAG from ECR..."
docker pull $ECR_SHA_TAG
echo "Pushing tag $GHCR_IMAGE_TAG_BASE to Github Container Registry..."=
docker tag $ECR_SHA_TAG $GHCR_IMAGE_TAG_BASE:$RELEASE_TAG
docker tag $ECR_SHA_TAG $GHCR_IMAGE_TAG_BASE:latest
docker push --all-tags $GHCR_IMAGE_TAG_BASE
cli_release_artifacts:
name: Build asset for ${{ matrix.goos }} - ${{ matrix.goarch }}
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -92,16 +91,30 @@ jobs:
artifact_name: uesio-macos-arm64
asset_name: uesio-macos-arm64
steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup Go

# https://github.com/actions/setup-go/issues/358 - cache is shared across jobs by default since the dependency
# graph is the same, however each job results in different dependencies being downloaded and the first one
# to finish wins with regards to saving the cache. To workaround, we create a file to include in the graph
# that contains information specified to the workflow & job so that each job gets a separate go cache.
# Note that the cache key used (https://github.com/actions/setup-go/blob/main/src/cache-restore.ts#L35) by
# actions/setup-go is already platform/arch/go-version specific so we only need to further differentiate
# by workflow and job.
- name: Create go cache info file
run: echo "go-cache-${{ github.workflow }}-${{ github.job }}" > ${GO_CACHE_INFO_FILE}

- name: Setup go
uses: actions/setup-go@v5
with:
go-version-file: go.work
cache-dependency-path: |
apps/*/go.sum
go.work.sum
${{ env.GO_CACHE_INFO_FILE }}
- name: Build CLI
shell: bash
env:
Expand All @@ -110,12 +123,14 @@ jobs:
cd apps/cli
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o $outputPath
cd ../..
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.artifact_name }}
path: |
apps/cli/dist/bin/${{ matrix.artifact_name }}
upload_release_binaries:
name: Upload binaries to release
runs-on: ubuntu-latest
Expand All @@ -128,6 +143,7 @@ jobs:
path: binaries
pattern: binaries-*
merge-multiple: true

- name: Upload release artifacts
uses: Roang-zero1/github-upload-release-artifacts-action@v2
with:
Expand Down
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,6 @@ npm run in-docker
open https://studio.uesio-dev.com:3000
```

**NOTE**: Docker Compose aggressively caches, so to force the app to rebuild the image (e.g. to rebuild JS / Go source), use this instead:

```
npm run in-docker-force-build
```

# <a id="set-up-ssl"></a> Set up SSL

SSL is optional for local development. It is enabled using by setting the environment variable `UESIO_USE_HTTPS=true`
Expand Down
6 changes: 3 additions & 3 deletions apps/platform/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ COPY ./apps/platform/platform ./platform
COPY ./dist/ui ./dist/ui
COPY ./dist/vendor ./dist/vendor

ARG GITSHA
ENV GITSHA=${GITSHA}
LABEL build_version=${GITSHA}
ARG BUILD_VERSION
ENV BUILD_VERSION=${BUILD_VERSION}
LABEL build_version=${BUILD_VERSION}

EXPOSE 3000

Expand Down
18 changes: 9 additions & 9 deletions apps/platform/pkg/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ var nameParam = getMetadataItemParam("name")
var itemParam = fmt.Sprintf("%s/%s", nsParam, nameParam)
var versionParam = "{version:(?:v[0-9]+\\.[0-9]+\\.[0-9]+)|(?:[a-z0-9]{8,}(?:\\.[0-9]+\\.[0-9]+)?)}"

// Version will either be a Uesio bundle version string, e.g. v1.2.3,
// an 8-character short Git sha, e.g. abcd1234 or an 8-character short
// Git sha followed by runnumber.runattempt, e.g. abcd1234.13.3
// Version will either be a Uesio bundle version string, e.g. v1.2.3, an 8-character
// short Git sha followed by runnumber.runattempt, e.g. abcd1234.13.3 or the current
// unix epoch time (e.g., 1738704509)
var versionedItemParam = fmt.Sprintf("%s/%s/%s", nsParam, versionParam, nameParam)

// Grouping values can either be full Uesio items (e.g. <user>/<app>.<name>) or simple values, e.g. "LISTENER",
Expand All @@ -67,8 +67,8 @@ var (
staticPrefix = "/static"
)

// Vendored scripts live under /static but do NOT get the GITSHA of the Uesio app,
// because they are not expected to change with the GITSHA, but are truly static, immutable
// Vendored scripts live under /static but do NOT get the version of the Uesio app,
// because they are not expected to change with the version, but are truly static, immutable
const vendorPrefix = "/static/vendor"

func serve(cmd *cobra.Command, args []string) {
Expand All @@ -82,13 +82,13 @@ func serve(cmd *cobra.Command, args []string) {
panic("Failed to obtain working directory")
}

// If we have gitsha, append that to the prefixes to enable us to have versioned assets
gitsha := os.Getenv("GITSHA")
// If we have BUILD_VERSION, append that to the prefixes to enable us to have versioned assets
version := os.Getenv("BUILD_VERSION")
cacheSiteBundles := os.Getenv("UESIO_CACHE_SITE_BUNDLES")
cacheStaticAssets := false
staticAssetsPath := ""
if gitsha != "" {
staticAssetsPath = "/" + gitsha
if version != "" {
staticAssetsPath = "/" + version
} else if cacheSiteBundles == "true" {
staticAssetsPath = fmt.Sprintf("/%d", time.Now().Unix())
}
Expand Down
Loading
Loading