From 59e1a2adabe9ff5504c8a5b237350086e51966ad Mon Sep 17 00:00:00 2001 From: RJ Padilla Date: Sat, 10 Jul 2021 01:07:44 -0400 Subject: [PATCH] multiarch support (#3) --- .github/workflows/force.yml | 78 +++++++++++++++++++ .github/workflows/pm2.yml | 71 ++++++++++++++++-- .github/workflows/utils.sh | 121 ++++++++++++++++++++++++++++++ Dockerfile => Dockerfile.template | 2 +- 4 files changed, 266 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/force.yml create mode 100644 .github/workflows/utils.sh rename Dockerfile => Dockerfile.template (84%) diff --git a/.github/workflows/force.yml b/.github/workflows/force.yml new file mode 100644 index 0000000..78b99b2 --- /dev/null +++ b/.github/workflows/force.yml @@ -0,0 +1,78 @@ +name: build by force + +on: + # push: + # branches: + # - master + # - main + workflow_dispatch: + # repository_dispatch: + # types: pm2 + +jobs: + pm2: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: login to docker + run: docker login -u ${{ secrets.DOCKERUSERNAME }} -p ${{ secrets.DOCKERAPIKEY }} + - name: treehouses pm2 + run: | + export DOCKER_CLI_EXPERIMENTAL=enabled + repo="treehouses/pm2" + base="treehouses/node" + source .github/workflows/utils.sh + echo "amd64" + baseamd64=$(get_manifest_sha "$base:latest" "amd64") + echo $baseamd64 + # repoamd64=$(get_manifest_sha "$repo:latest" "amd64") + # echo $repoamd64 + # echo "flag amd64" + # flag_amd64=$(is_base "$base@"$baseamd64 "$repo@"$repoamd64) + # echo $flag_amd64 + echo "arm" + basearm=$(get_manifest_sha "$base:latest" "arm") + echo $basearm + # repoarm=$(get_manifest_sha "$repo:latest" "arm") + # echo $repoarm + # flagarm=$(is_base "$base@"$basearm "$repo@"$repoarm) + # echo "flag arm" + # echo $flagarm + echo "arm64" + basearm64=$(get_manifest_sha "$base:latest" "arm64") + echo $basearm64 + # repoarm64=$(get_manifest_sha "$repo:latest" "arm64") + # echo $repoarm64 + # echo "flag arm64" + # flagarm64=$(is_base "$base@"$basearm64 "$repo@"$repoarm64) + # echo $flagarm64 + version2=$(image_version $repo:latest) + echo "repo version is $version2" + flag=true #$(compare "$base@"$basearm "$repo@"$repoarm "$base@"$baseamd64 "$repo@"$repoamd64 "$base@"$basearm64 "$repo@"$repoarm64 "$repo" "$repo-tags:amd64") + echo $flag + if [[ $flag == true ]]; then + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + build_image "$base:latest" arm "$repo" + build_image "$base:latest" amd64 "$repo" + build_image "$base:latest" arm64 "$repo" + deploy_image "$repo" arm + deploy_image "$repo" amd64 + deploy_image "$repo" arm64 + sudo npm install -g @treehouses/cli + export gitter_channel="${{ secrets.CHANNEL }}" + echo "tags" + tag=$(date +%Y%m%d%H%M) + tag2="latest" + echo $tag + create_manifest $repo $tag $tag2 $repo-tags:amd64 $repo-tags:arm $repo-tags:arm64 + docker manifest inspect $repo:$tag + docker manifest inspect $repo:$tag2 + docker manifest push $repo:$tag; docker manifest push $repo:$tag2 + echo "https://hub.docker.com/r/treehouses/pm2/tags" + treehouses feedback "new treehouses/pm2 check https://hub.docker.com/r/treehouses/pm2/tags" + else + echo "no changes" + fi + + diff --git a/.github/workflows/pm2.yml b/.github/workflows/pm2.yml index 4bb65c8..cd47330 100644 --- a/.github/workflows/pm2.yml +++ b/.github/workflows/pm2.yml @@ -1,6 +1,13 @@ -name: pm2 +name: build on change -on: [push] +on: + push: + branches: + - master + - main + workflow_dispatch: + repository_dispatch: + types: pm2 jobs: pm2: @@ -10,8 +17,62 @@ jobs: uses: actions/checkout@v2 - name: login to docker run: docker login -u ${{ secrets.DOCKERUSERNAME }} -p ${{ secrets.DOCKERAPIKEY }} - - name: building pm2 and deploying to docker + - name: treehouses pm2 run: | export DOCKER_CLI_EXPERIMENTAL=enabled - docker build -t treehouses/pm2 . - docker push treehouses/pm2 + repo="treehouses/pm2" + base="treehouses/node" + source .github/workflows/utils.sh + echo "amd64" + baseamd64=$(get_manifest_sha "$base:latest" "amd64") + echo $baseamd64 + repoamd64=$(get_manifest_sha "$repo:latest" "amd64") + echo $repoamd64 + echo "flag amd64" + flag_amd64=$(is_base "$base@"$baseamd64 "$repo@"$repoamd64) + echo $flag_amd64 + echo "arm" + basearm=$(get_manifest_sha "$base:latest" "arm") + echo $basearm + repoarm=$(get_manifest_sha "$repo:latest" "arm") + echo $repoarm + flagarm=$(is_base "$base@"$basearm "$repo@"$repoarm) + echo "flag arm" + echo $flagarm + echo "arm64" + basearm64=$(get_manifest_sha "$base:latest" "arm64") + echo $basearm64 + repoarm64=$(get_manifest_sha "$repo:latest" "arm64") + echo $repoarm64 + echo "flag arm64" + flagarm64=$(is_base "$base@"$basearm64 "$repo@"$repoarm64) + echo $flagarm64 + version2=$(image_version $repo:latest) + echo "repo version is $version2" + flag=$(compare "$base@"$basearm "$repo@"$repoarm "$base@"$baseamd64 "$repo@"$repoamd64 "$base@"$basearm64 "$repo@"$repoarm64 "$repo" "$repo-tags:amd64") + echo $flag + if [[ $flag == true ]]; then + docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + build_image "$base:latest" arm "$repo" + build_image "$base:latest" amd64 "$repo" + build_image "$base:latest" arm64 "$repo" + deploy_image "$repo" arm + deploy_image "$repo" amd64 + deploy_image "$repo" arm64 + sudo npm install -g @treehouses/cli + export gitter_channel="${{ secrets.CHANNEL }}" + echo "tags" + tag=$(date +%Y%m%d%H%M) + tag2="latest" + echo $tag + create_manifest $repo $tag $tag2 $repo-tags:amd64 $repo-tags:arm $repo-tags:arm64 + docker manifest inspect $repo:$tag + docker manifest inspect $repo:$tag2 + docker manifest push $repo:$tag; docker manifest push $repo:$tag2 + echo "https://hub.docker.com/r/treehouses/pm2/tags" + treehouses feedback "new treehouses/pm2 check https://hub.docker.com/r/treehouses/pm2/tags" + else + echo "no changes" + fi + + diff --git a/.github/workflows/utils.sh b/.github/workflows/utils.sh new file mode 100644 index 0000000..6229cdf --- /dev/null +++ b/.github/workflows/utils.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +# Echos out sha function from saved .txt file +get_manifest_sha() { + local repo=$1 + local arch=$2 + docker pull -q $1 &>/dev/null + docker manifest inspect $1 > "$2".txt + sha="" + i=0 + while [ "$sha" == "" ] && read -r line; do + architecture=$(jq .manifests[$i].platform.architecture "$2".txt |sed -e 's/^"//' -e 's/"$//') + if [ "$architecture" = "$2" ];then + sha=$(jq .manifests[$i].digest "$2".txt |sed -e 's/^"//' -e 's/"$//') + echo ${sha} + fi + i=$i+1 + done < "$2".txt +} + +# Echos out sha function +get_sha() { + repo=$1 + docker pull $1 &>/dev/null + sha=$(docker image inspect $1 | jq --raw-output '.[0].RootFS.Layers|.[]') # [0] means first element of list,[]means all the elments of lists + echo $sha +} + +# Check if base is part of an image +is_base() { + local base_sha # alpine + local image_sha # new image + local base_repo=$1 + local image_repo=$2 + + base_sha=$(get_sha $base_repo) + image_sha=$(get_sha $image_repo) + + for i in $base_sha; do + local found="false" + for j in $image_sha; do + if [[ $i = $j ]]; then + found="true" + break + fi + done + if [ $found == "false" ]; then + echo "false" + return 0 + fi + done + echo "true" +} + +image_version() { + local version + repo=$1 # nginx repo + version=$(docker run -it $1 /bin/sh -c "nginx -v" |awk '{print$3}') + echo $version +} + +compare() { + result_arm=$(is_base $1 $2) + result_arm64=$(is_base $3 $4) + result_amd64=$(is_base $5 $6) + if [ $result_arm == "false" ] || [ $result_amd64 == "false" ] || [ $result_arm64 == "false" ]; + then + echo "true" + else + echo "false" + fi +} + +create_manifest() { + local repo=$1 + local tag1=$2 + local tag2=$3 + local x86=$4 + local rpi=$5 + local arm64=$6 + docker manifest create $repo:$tag1 $x86 $rpi $arm64 + docker manifest create $repo:$tag2 $x86 $rpi $arm64 + docker manifest annotate $repo:$tag1 $x86 --arch amd64 + docker manifest annotate $repo:$tag1 $rpi --arch arm + docker manifest annotate $repo:$tag1 $arm64 --arch arm64 + docker manifest annotate $repo:$tag2 $x86 --arch amd64 + docker manifest annotate $repo:$tag2 $rpi --arch arm + docker manifest annotate $repo:$tag2 $arm64 --arch arm64 +} + +build_image(){ + local repo=$1 # this is the base repo, for example treehouses/alpine + local arch=$2 #arm arm64 amd64 + local tag_repo=$3 # this is the tag repo, for example treehouses/node + if [ $# -le 1 ]; then + echo "missing parameters." + exit 1 + fi + sha=$(get_manifest_sha $@) + echo $sha + base_image="$repo@$sha" + echo $base_image + if [ -n "$sha" ]; then + tag=$tag_repo-tags:$arch + sed "s|{{base_image}}|$base_image|g" Dockerfile.template > Dockerfile.$arch + docker buildx build --platform linux/$arch -t $tag -f Dockerfile.$arch . + fi +} + +deploy_image(){ + local repo=$1 + local arch=$2 #arm arm64 amd64 + tag_arch=$repo-tags:$arch + tag_time=$(date +%Y%m%d%H%M) + tag_arch_time=$repo-tags:$arch-$tag_time + echo $tag_arch_time + docker tag $tag_arch $tag_arch_time + docker push $tag_arch_time + docker tag $tag_arch_time $tag_arch + docker push $tag_arch +} diff --git a/Dockerfile b/Dockerfile.template similarity index 84% rename from Dockerfile rename to Dockerfile.template index 80ae3c7..f5a1d5c 100644 --- a/Dockerfile +++ b/Dockerfile.template @@ -1,4 +1,4 @@ -FROM treehouses/node +FROM {{base_image}} # Install pm2 RUN npm install pm2 -g