diff --git a/.github/workflows/release-singleimage-test.yml b/.github/workflows/release-singleimage-test.yml index 078355a654..579b82ed84 100644 --- a/.github/workflows/release-singleimage-test.yml +++ b/.github/workflows/release-singleimage-test.yml @@ -16,25 +16,12 @@ jobs: matrix: node-version: [18.x] steps: - # - name: Fail if not a tag - # run: | - # if [[ $GITHUB_REF != refs/tags/* ]]; then - # echo "Workflow Dispatch can only be run on tags" - # exit 1 - # fi - name: "Checkout" uses: actions/checkout@v4 with: submodules: true token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - # - name: Fail if tag is not in master - # run: | - # if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then - # echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch" - # exit 1 - # fi - - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -42,9 +29,6 @@ jobs: cache: "yarn" - name: Setup QEMU uses: docker/setup-qemu-action@v3 - # - name: Setup Docker Buildx - # id: buildx - # uses: docker/setup-buildx-action@v3 - name: Generate package names file run: ./scripts/generatePackageNamesFile.sh - name: Run Yarn @@ -68,21 +52,8 @@ jobs: context: . push: true pull: true - # platforms: linux/amd64,linux/arm64 platforms: linux/amd64 tags: budibase/budibase-test:test - file: ./hosting/single/Dockerfile + file: ./hosting/single/Dockerfile.v2 cache-from: type=registry,ref=budibase/budibase-test:test cache-to: type=inline - # - name: Tag and release Budibase Azure App Service docker image - # uses: docker/build-push-action@v5 - # with: - # context: . - # push: true - # pull: true - # platforms: linux/amd64 - # build-args: TARGETBUILD=aas - # tags: budibase/budibase-test:aas - # file: ./hosting/single/Dockerfile - # cache-from: type=registry,ref=budibase/budibase-test:aas - # cache-to: type=inline diff --git a/.github/workflows/release-singleimage.yml b/.github/workflows/release-singleimage.yml new file mode 100644 index 0000000000..61ab9a4eb2 --- /dev/null +++ b/.github/workflows/release-singleimage.yml @@ -0,0 +1,79 @@ +name: Deploy Budibase Single Container Image to DockerHub + +on: + workflow_dispatch: + +env: + CI: true + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + REGISTRY_URL: registry.hub.docker.com +jobs: + build: + name: "build" + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - name: Maximize build space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 30000 + swap-size-mb: 1024 + remove-android: 'true' + remove-dotnet: 'true' + - name: Fail if not a tag + run: | + if [[ $GITHUB_REF != refs/tags/* ]]; then + echo "Workflow Dispatch can only be run on tags" + exit 1 + fi + - name: "Checkout" + uses: actions/checkout@v2 + with: + submodules: true + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Setup QEMU + uses: docker/setup-qemu-action@v1 + - name: Setup Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + - name: Run Yarn + run: yarn + - name: Update versions + run: ./scripts/updateVersions.sh + - name: Run Yarn Build + run: yarn build:docker:pre + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_API_KEY }} + - name: Get the latest release version + id: version + run: | + release_version=$(cat lerna.json | jq -r '.version') + echo $release_version + echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV + - name: Tag and release Budibase service docker image + uses: docker/build-push-action@v2 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: budibase/budibase,budibase/budibase:${{ env.RELEASE_VERSION }} + file: ./hosting/single/Dockerfile + - name: Tag and release Budibase Azure App Service docker image + uses: docker/build-push-action@v2 + with: + context: . + push: true + platforms: linux/amd64 + build-args: TARGETBUILD=aas + tags: budibase/budibase-aas,budibase/budibase-aas:${{ env.RELEASE_VERSION }} + file: ./hosting/single/Dockerfile diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile index 229c6189e7..95e383edb0 100644 --- a/hosting/single/Dockerfile +++ b/hosting/single/Dockerfile @@ -1,44 +1,28 @@ FROM node:18-slim as build # install node-gyp dependencies -RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq +RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends apt-utils cron g++ make python3 +# add pin script +WORKDIR / +ADD scripts/cleanup.sh ./ +RUN chmod +x /cleanup.sh -# copy and install dependencies +# build server WORKDIR /app -COPY package.json . +ADD packages/server . COPY yarn.lock . -COPY lerna.json . -COPY .yarnrc . -COPY packageNames.txt . +RUN yarn install --production=true --network-timeout 100000 +RUN /cleanup.sh -COPY packages/server/package.json packages/server/package.json -COPY packages/worker/package.json packages/worker/package.json -# string-templates does not get bundled during the esbuild process, so we want to use the local version -COPY packages/string-templates/package.json packages/string-templates/package.json +# build worker +WORKDIR /worker +ADD packages/worker . +COPY yarn.lock . +RUN yarn install --production=true --network-timeout 100000 +RUN /cleanup.sh - -COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh -RUN chmod +x ./scripts/removeWorkspaceDependencies.sh -RUN ./scripts/removeWorkspaceDependencies.sh - - -# We will never want to sync pro, but the script is still required -RUN echo '' > scripts/syncProPackage.js -RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json -RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production - -# copy the actual code -COPY packages/server/dist packages/server/dist -COPY packages/server/pm2.config.js packages/server/pm2.config.js -COPY packages/server/client packages/server/client -COPY packages/server/builder packages/server/builder -COPY packages/worker/dist packages/worker/dist -COPY packages/worker/pm2.config.js packages/worker/pm2.config.js -COPY packages/string-templates packages/string-templates - - -FROM budibase/couchdb as runner +FROM budibase/couchdb ARG TARGETARCH ENV TARGETARCH $TARGETARCH #TARGETBUILD can be set to single (for single docker image) or aas (for azure app service) @@ -46,6 +30,9 @@ ENV TARGETARCH $TARGETARCH ARG TARGETBUILD=single ENV TARGETBUILD $TARGETBUILD +COPY --from=build /app /app +COPY --from=build /worker /worker + # install base dependencies RUN apt-get update && \ apt-get install -y --no-install-recommends software-properties-common nginx uuid-runtime redis-server @@ -60,14 +47,14 @@ RUN apt install software-properties-common apt-transport-https gpg -y \ # install other dependencies, nodejs, oracle requirements, jdk8, redis, nginx WORKDIR /nodejs -RUN curl -sL https://deb.nodesource.com/setup_18.x -o /tmp/nodesource_setup.sh && \ +RUN curl -sL https://deb.nodesource.com/setup_16.x -o /tmp/nodesource_setup.sh && \ bash /tmp/nodesource_setup.sh && \ apt-get install -y --no-install-recommends libaio1 nodejs && \ npm install --global yarn pm2 # setup nginx -COPY hosting/single/nginx/nginx.conf /etc/nginx -COPY hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default +ADD hosting/single/nginx/nginx.conf /etc/nginx +ADD hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default RUN mkdir -p /var/log/nginx && \ touch /var/log/nginx/error.log && \ touch /var/run/nginx.pid && \ @@ -75,41 +62,29 @@ RUN mkdir -p /var/log/nginx && \ WORKDIR / RUN mkdir -p scripts/integrations/oracle -COPY packages/server/scripts/integrations/oracle scripts/integrations/oracle +ADD packages/server/scripts/integrations/oracle scripts/integrations/oracle RUN /bin/bash -e ./scripts/integrations/oracle/instantclient/linux/install.sh # setup minio WORKDIR /minio -COPY scripts/install-minio.sh ./install.sh +ADD scripts/install-minio.sh ./install.sh RUN chmod +x install.sh && ./install.sh # setup runner file WORKDIR / -COPY hosting/single/runner.sh . +ADD hosting/single/runner.sh . RUN chmod +x ./runner.sh -COPY hosting/single/healthcheck.sh . +ADD hosting/single/healthcheck.sh . RUN chmod +x ./healthcheck.sh # Script below sets the path for storing data based on $DATA_DIR # For Azure App Service install SSH & point data locations to /home -COPY hosting/single/ssh/sshd_config /etc/ -COPY hosting/single/ssh/ssh_setup.sh /tmp +ADD hosting/single/ssh/sshd_config /etc/ +ADD hosting/single/ssh/ssh_setup.sh /tmp RUN /build-target-paths.sh - -# setup letsencrypt certificate -RUN apt-get install -y certbot python3-certbot-nginx -COPY hosting/letsencrypt /app/letsencrypt -RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh - -COPY --from=build /app/node_modules /node_modules -COPY --from=build /app/package.json /package.json -COPY --from=build /app/packages/server /app -COPY --from=build /app/packages/worker /worker -COPY --from=build /app/packages/string-templates /string-templates - -RUN cd /string-templates && yarn link && cd ../app && yarn link @budibase/string-templates && cd ../worker && yarn link @budibase/string-templates - +# cleanup cache +RUN yarn cache clean -f EXPOSE 80 EXPOSE 443 @@ -117,6 +92,20 @@ EXPOSE 443 EXPOSE 2222 VOLUME /data +# setup letsencrypt certificate +RUN apt-get install -y certbot python3-certbot-nginx +ADD hosting/letsencrypt /app/letsencrypt +RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh +# Remove cached files +RUN rm -rf \ + /root/.cache \ + /root/.npm \ + /root/.pip \ + /usr/local/share/doc \ + /usr/share/doc \ + /usr/share/man \ + /var/lib/apt/lists/* \ + /tmp/* HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh" diff --git a/hosting/single/Dockerfile.v2 b/hosting/single/Dockerfile.v2 new file mode 100644 index 0000000000..229c6189e7 --- /dev/null +++ b/hosting/single/Dockerfile.v2 @@ -0,0 +1,127 @@ +FROM node:18-slim as build + +# install node-gyp dependencies +RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 jq + + +# copy and install dependencies +WORKDIR /app +COPY package.json . +COPY yarn.lock . +COPY lerna.json . +COPY .yarnrc . +COPY packageNames.txt . + +COPY packages/server/package.json packages/server/package.json +COPY packages/worker/package.json packages/worker/package.json +# string-templates does not get bundled during the esbuild process, so we want to use the local version +COPY packages/string-templates/package.json packages/string-templates/package.json + + +COPY scripts/removeWorkspaceDependencies.sh scripts/removeWorkspaceDependencies.sh +RUN chmod +x ./scripts/removeWorkspaceDependencies.sh +RUN ./scripts/removeWorkspaceDependencies.sh + + +# We will never want to sync pro, but the script is still required +RUN echo '' > scripts/syncProPackage.js +RUN jq 'del(.scripts.postinstall)' package.json > temp.json && mv temp.json package.json +RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install --production + +# copy the actual code +COPY packages/server/dist packages/server/dist +COPY packages/server/pm2.config.js packages/server/pm2.config.js +COPY packages/server/client packages/server/client +COPY packages/server/builder packages/server/builder +COPY packages/worker/dist packages/worker/dist +COPY packages/worker/pm2.config.js packages/worker/pm2.config.js +COPY packages/string-templates packages/string-templates + + +FROM budibase/couchdb as runner +ARG TARGETARCH +ENV TARGETARCH $TARGETARCH +#TARGETBUILD can be set to single (for single docker image) or aas (for azure app service) +# e.g. docker build --build-arg TARGETBUILD=aas .... +ARG TARGETBUILD=single +ENV TARGETBUILD $TARGETBUILD + +# install base dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends software-properties-common nginx uuid-runtime redis-server + +# Install postgres client for pg_dump utils +RUN apt install software-properties-common apt-transport-https gpg -y \ + && curl -fsSl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/postgresql.gpg > /dev/null \ + && echo deb [arch=amd64,arm64,ppc64el signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main | tee /etc/apt/sources.list.d/postgresql.list \ + && apt update -y \ + && apt install postgresql-client-15 -y \ + && apt remove software-properties-common apt-transport-https gpg -y + +# install other dependencies, nodejs, oracle requirements, jdk8, redis, nginx +WORKDIR /nodejs +RUN curl -sL https://deb.nodesource.com/setup_18.x -o /tmp/nodesource_setup.sh && \ + bash /tmp/nodesource_setup.sh && \ + apt-get install -y --no-install-recommends libaio1 nodejs && \ + npm install --global yarn pm2 + +# setup nginx +COPY hosting/single/nginx/nginx.conf /etc/nginx +COPY hosting/single/nginx/nginx-default-site.conf /etc/nginx/sites-enabled/default +RUN mkdir -p /var/log/nginx && \ + touch /var/log/nginx/error.log && \ + touch /var/run/nginx.pid && \ + usermod -a -G tty www-data + +WORKDIR / +RUN mkdir -p scripts/integrations/oracle +COPY packages/server/scripts/integrations/oracle scripts/integrations/oracle +RUN /bin/bash -e ./scripts/integrations/oracle/instantclient/linux/install.sh + +# setup minio +WORKDIR /minio +COPY scripts/install-minio.sh ./install.sh +RUN chmod +x install.sh && ./install.sh + +# setup runner file +WORKDIR / +COPY hosting/single/runner.sh . +RUN chmod +x ./runner.sh +COPY hosting/single/healthcheck.sh . +RUN chmod +x ./healthcheck.sh + +# Script below sets the path for storing data based on $DATA_DIR +# For Azure App Service install SSH & point data locations to /home +COPY hosting/single/ssh/sshd_config /etc/ +COPY hosting/single/ssh/ssh_setup.sh /tmp +RUN /build-target-paths.sh + + +# setup letsencrypt certificate +RUN apt-get install -y certbot python3-certbot-nginx +COPY hosting/letsencrypt /app/letsencrypt +RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh + +COPY --from=build /app/node_modules /node_modules +COPY --from=build /app/package.json /package.json +COPY --from=build /app/packages/server /app +COPY --from=build /app/packages/worker /worker +COPY --from=build /app/packages/string-templates /string-templates + +RUN cd /string-templates && yarn link && cd ../app && yarn link @budibase/string-templates && cd ../worker && yarn link @budibase/string-templates + + +EXPOSE 80 +EXPOSE 443 +# Expose port 2222 for SSH on Azure App Service build +EXPOSE 2222 +VOLUME /data + + +HEALTHCHECK --interval=15s --timeout=15s --start-period=45s CMD "/healthcheck.sh" + +# must set this just before running +ENV NODE_ENV=production +WORKDIR / + +CMD ["./runner.sh"] diff --git a/scripts/build-single-image.sh b/scripts/build-single-image.sh index a9abe8c8da..99432483e8 100755 --- a/scripts/build-single-image.sh +++ b/scripts/build-single-image.sh @@ -1,4 +1,4 @@ #!/bin/bash yarn build --scope @budibase/server --scope @budibase/worker ./scripts/generatePackageNamesFile.sh -docker build -f hosting/single/Dockerfile -t budibase:latest . +docker build -f hosting/single/Dockerfile.v2 -t budibase:latest .