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

Docker First Cut #1766

Draft
wants to merge 53 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4cee1c6
New basic and KISS Dockerfile for funnel
miteshashar Jun 20, 2023
9adfd61
Install supervisor in Dockerfile
miteshashar Jun 21, 2023
48f10b6
Working funnel docker container using uwsgi in http mode
miteshashar Jun 23, 2023
f48d90f
Add postfix setup to docker compose
miteshashar Jun 25, 2023
1003475
Update instructions in sample.env
miteshashar Jun 25, 2023
7d78d7d
Include link to comprehensive dockerfile reference
miteshashar Jun 25, 2023
27df0c5
Configure postfix spool persistence in compose file
miteshashar Jun 25, 2023
e93f83d
Make postfix compose setup override-based
miteshashar Jun 25, 2023
e2e29d7
CI pytest on docker
miteshashar Jun 26, 2023
3aef270
Remove a debug instruction from Dockerfile
miteshashar Jun 26, 2023
3863779
Add extra_hosts to CI compose file
miteshashar Jun 26, 2023
2e05d9e
Create coverage directory as funnel instead of root in Dockerfile ci …
miteshashar Jun 26, 2023
65a40b3
Try to create a coverage folder in GHA host and set it's ownership be…
miteshashar Jun 26, 2023
1f4c3d2
Create & set permissions of coverage folder with uid and gid in Docke…
miteshashar Jun 26, 2023
0d2a491
Alternate approach to use docker compose run to pre-set permission of…
miteshashar Jun 26, 2023
13f3d48
Make CI tests fail to check if --exit-code-from works to mark GHA ste…
miteshashar Jun 26, 2023
7a74467
Make CI tests fail to check if --exit-code-from works to mark GHA ste…
miteshashar Jun 26, 2023
76ec793
Make CI tests fail to check if --exit-code-from works to mark GHA ste…
miteshashar Jun 26, 2023
9fe1352
Use pytest-github-actions-annotate-failures in the CI docker image
miteshashar Jun 26, 2023
aef75da
Try running tests with docker run in the GHA pytest docker workflow
miteshashar Jun 27, 2023
dfd892f
Try running tests with docker run in the GHA pytest docker workflow
miteshashar Jun 27, 2023
08b7655
Try running tests with docker run in the GHA pytest docker workflow
miteshashar Jun 27, 2023
c96f714
Try running tests with docker run in the GHA pytest docker workflow
miteshashar Jun 27, 2023
f814079
Try running tests with docker run in the GHA pytest docker workflow
miteshashar Jun 27, 2023
e4fad2e
Added --no-log-prefix to the pytest step - log prefixes maybe interfe…
miteshashar Jun 27, 2023
04a7922
Remove deliberate test failure as pytest failure annotations now work…
miteshashar Jun 27, 2023
a5575d4
Move coverage report preparation for docker-based CI back into entryp…
miteshashar Jun 27, 2023
a8a6be1
Add pytest-github-actions-annotate-failures to python dependencies fo…
miteshashar Jun 27, 2023
f95e7bf
Update trigger conditions for pytest docker GHA workflow
miteshashar Jun 27, 2023
9e381f8
Add the gha build cache backend for the funnel-ci build step in the p…
miteshashar Jun 28, 2023
e6408f1
Add step to build funnel production image in the pytest docker workfl…
miteshashar Jun 28, 2023
ed53849
Merge branch 'main' into docker
miteshashar Jun 28, 2023
2481c65
Update python dependencies
miteshashar Jun 28, 2023
554434e
Change entrypoint shell script for docker CI to not exit with code 0 …
miteshashar Jun 28, 2023
333dff3
Revert "Update python dependencies"
miteshashar Jun 28, 2023
9b69f71
Tags, caching and arm64 build in the last app rebuild stage
miteshashar Jun 28, 2023
d1dc0d6
QEMU is recommended for multi-platform builds; Add .github to .docker…
miteshashar Jun 29, 2023
686d475
set-output is deprecated by GHA; login to registries and push docker …
miteshashar Jun 29, 2023
ab3191c
Try personal token from https://github.com/settings/tokens/new?scopes…
miteshashar Jun 29, 2023
8f01f20
Remove arm64 build from docker GHA workflow – the build process is sl…
miteshashar Jun 29, 2023
45cd075
Merge branch 'main' into docker
miteshashar Jun 29, 2023
3b80a85
Update docker commands for running CI tests
miteshashar Jun 29, 2023
b194dd2
Added rq service in docker compose
miteshashar Jun 30, 2023
8230d7a
Merge branch 'main' into docker
miteshashar Jun 30, 2023
7693385
Remove APP-*-SITE_ID environment variables from .testenv; Add DEBUG_T…
miteshashar Jul 5, 2023
cef9907
Correction: Replace DEBUG_TB_INTERCEPT_REDIRECTS with FLASK_DEBUG_TB_…
miteshashar Jul 5, 2023
8c77dd2
Merge branch 'main' into docker
miteshashar Jul 7, 2023
084061d
Merge branch 'main' into docker
miteshashar Jul 8, 2023
324059c
Merge branch 'main' into docker
miteshashar Jul 20, 2023
f3ac8b0
Merge branch 'main' into docker
miteshashar Jul 23, 2023
7ba0838
Merge branch 'main' into docker
miteshashar Oct 24, 2023
b5f05e0
Install rust in docker to support installation of z-base-32
miteshashar Oct 31, 2023
6b99f09
Install uwsgi in docker
miteshashar Oct 31, 2023
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
5 changes: 4 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**/.webassets-cache
**/__pycache__
.webpack_cache
.cache
.eslintcache

# MacOS file
**/.DS_Store
Expand Down Expand Up @@ -74,6 +74,9 @@ env/
# Versioning files
.git

# github workflow files
.github

# Local DBs
dump.rdb
test.db
Expand Down
71 changes: 0 additions & 71 deletions .github/workflows/docker-ci-tests.yml

This file was deleted.

92 changes: 92 additions & 0 deletions .github/workflows/pytest-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: 'Pytest Docker'

on:
push:
paths:
- '**.py'
- '**.js'
- '**.scss'
- '**.jinja2'
- '.flaskenv'
- '.testenv'
- 'requirements/base.txt'
- 'requirements/test.txt'
- '.github/workflows/pytest-docker.yml'
- 'Dockerfile'
- 'Makefile'
- 'pyproject.toml'
- 'docker-compose.ci.yml'
- 'docker/entrypoints/ci.sh'
- 'docker/initdb.sh'
- 'package.json'
- 'package-lock.json'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build funnel-ci image
id: build-funnel-ci
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
target: ci
tags: funnel-ci
load: true
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Set permissions for coverage
run: docker compose -f docker-compose.ci.yml run --rm -u root --entrypoint "" --no-deps --quiet-pull main chown -R 1000:1000 coverage
- name: Test with pytest
run: docker compose -f docker-compose.ci.yml up --quiet-pull --no-attach db --no-attach redis --no-log-prefix --exit-code-from main
- name: Upload coverage report to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
path-to-lcov: coverage/funnel.lcov
flag-name: docker-3.11
- name: Set short git commit SHA
if: ${{ github.ref_name == 'main' || github.ref_name == 'docker' }}
id: sha
run: |
short_sha=$(git rev-parse --short ${{ github.sha }})
echo "short=$short_sha" >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
if: ${{ github.ref_name == 'main' || github.ref_name == 'docker' }}
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
if: ${{ github.ref_name == 'main' || github.ref_name == 'docker' }}
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GHCR_WRITE_TOKEN }}
- name: Build & push funnel image
if: ${{ github.ref_name == 'main' || github.ref_name == 'docker' }}
id: build-funnel
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
target: app
tags: |
hasgeek/funnel:${{ github.ref_name }}
hasgeek/funnel:sha-${{ steps.sha.outputs.short }}
ghcr.io/hasgeek/funnel:${{ github.ref_name }}
ghcr.io/hasgeek/funnel:sha-${{ steps.sha.outputs.short }}
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
__pycache__
.nox
monkeytype.sqlite3
.ci-cache
.cache

# MacOS file
.DS_Store
Expand Down
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,10 @@ repos:
# hooks:
# - id: dockerfile_lint
# files: .*Dockerfile.*
# - repo: https://github.com/hadolint/hadolint
# rev: v2.12.1-beta
# hooks:
# - id: hadolint-docker
- repo: https://github.com/hadolint/hadolint
rev: v2.12.1-beta
hooks:
- id: hadolint-docker
- repo: https://github.com/IamTheFij/docker-pre-commit
rev: v3.0.1
hooks:
Expand Down
2 changes: 0 additions & 2 deletions .testenv
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ FLASK_IMAGE_URL_DOMAINS='["images.example.com"]'
FLASK_IMAGE_URL_SCHEMES='["https"]'
FLASK_SES_NOTIFICATION_TOPICS=null
# Per app config
APP_FUNNEL_SITE_ID=hasgeek-test
APP_FUNNEL_SERVER_NAME=funnel.test:3002
APP_FUNNEL_SHORTLINK_DOMAIN=f.test:3002
APP_FUNNEL_DEFAULT_DOMAIN=funnel.test
APP_FUNNEL_UNSUBSCRIBE_DOMAIN=bye.test
APP_SHORTLINK_SITE_ID=shortlink-test
166 changes: 62 additions & 104 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,112 +1,70 @@
# syntax=docker/dockerfile:1.4

FROM nikolaik/python-nodejs:python3.11-nodejs20-bullseye as base
# https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md

# https://github.com/zalando/postgres-operator/blob/master/docker/logical-backup/Dockerfile
# https://stackoverflow.com/questions/68465355/what-is-the-meaning-of-set-o-pipefail-in-bash-script
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
FROM node:lts-alpine as assets
USER node
WORKDIR /home/node/app
RUN mkdir -pv /home/node/app/funnel/static/build /home/node/app/funnel/static/build_cache
COPY --chown=node:node package.json package-lock.json ./
RUN --mount=type=cache,target=/home/node/.npm/,uid=1000,gid=1000 npm ci
COPY --chown=node:node ./funnel/assets/ ./funnel/assets/
COPY --chown=node:node webpack.config.js .eslintrc.js ./
RUN --mount=type=cache,target=/home/node/app/.webpack_cache/,uid=1000,gid=1000 \
--mount=type=cache,target=/home/node/app/funnel/static/build_cache/,uid=1000,gid=1000 \
cp -R funnel/static/build_cache funnel/static/build \
&& npm run build \
&& cp -R funnel/static/build funnel/static/build_cache \
&& cp -R funnel/static/build funnel/static/built

LABEL Name=Funnel
LABEL Version=0.1
FROM python:3.11-bullseye as app
LABEL maintainer="Hasgeek"
RUN chsh -s /usr/sbin/nologin root
# hadolint ignore=DL3008
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update -yqq \
&& apt-get install -yqq --no-install-recommends supervisor curl \
&& apt-get autoclean -yqq \
&& apt-get autoremove -yqq \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -pv /var/log/supervisor
RUN addgroup --gid 1000 funnel && adduser --uid 1000 --gid 1000 funnel
ENV PATH "$PATH:/home/funnel/.local/bin"
USER funnel
# hadolint ignore=DL4006
RUN curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | /bin/bash -s -- -y
ENV PATH "/home/funnel/.cargo/bin:$PATH"
WORKDIR /home/funnel/app

USER pn
RUN \
mkdir -pv /home/pn/.cache/pip /home/pn/.npm /home/pn/tmp /home/pn/app /home/pn/app/coverage && \
chown -R pn:pn /home/pn/.cache /home/pn/.npm /home/pn/tmp /home/pn/app /home/pn/app/coverage
EXPOSE 3000
WORKDIR /home/pn/app
COPY --chown=funnel:funnel Makefile Makefile
COPY --chown=funnel:funnel requirements/base.txt requirements/base.txt
RUN mkdir -pv /home/funnel/.cache/pip
# hadolint ignore=DL3013,DL3042
RUN --mount=type=cache,target=/home/funnel/.cache/pip,uid=1000,gid=1000 make install-python && pip install --upgrade uwsgi

ENV PATH "$PATH:/home/pn/.local/bin"
COPY --chown=funnel:funnel . .
COPY --from=assets --chown=funnel:funnel /home/node/app/funnel/static/built/ funnel/static/build
RUN mkdir -pv /home/funnel/app/logs
ENTRYPOINT [ "uwsgi", "--ini" ]

FROM base as devtest_base
FROM app as ci
USER root
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update -yqq && \
apt-get install -yqq --no-install-recommends lsb-release && \
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' && \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
apt-get update -yqq && apt-get upgrade -yqq && \
echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections && \
DEBIAN_FRONTEND=noninteractive apt-get install -yqq --no-install-recommends firefox-esr postgresql-client-15 && \
cd /tmp/ && \
curl -fsSL $(curl -fsSL https://api.github.com/repos/mozilla/geckodriver/releases/latest | grep browser_download_url | grep 'linux64.tar.gz\"'| grep -o 'http.*\.gz') > gecko.tar.gz && \
tar -xvzf gecko.tar.gz && \
rm gecko.tar.gz && \
chmod +x geckodriver && \
mv geckodriver /usr/local/bin && \
apt-get autoclean -yqq && \
apt-get autoremove -yqq && \
cd /home/pn/app
USER pn

FROM base as assets
COPY --chown=pn:pn package.json package.json
COPY --chown=pn:pn package-lock.json package-lock.json
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/home/pn/.npm,uid=1000,gid=1000 npm ci
COPY --chown=pn:pn ./funnel/assets ./funnel/assets
COPY --chown=pn:pn .eslintrc.js .eslintrc.js
COPY --chown=pn:pn webpack.config.js webpack.config.js
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/home/pn/.npm,uid=1000,gid=1000 npm run build

FROM base as dev_assets
COPY --chown=pn:pn package.json package.json
COPY --chown=pn:pn package-lock.json package-lock.json
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/home/pn/.npm,uid=1000,gid=1000 npm install
COPY --chown=pn:pn ./funnel/assets ./funnel/assets
COPY --chown=pn:pn .eslintrc.js .eslintrc.js
COPY --chown=pn:pn webpack.config.js webpack.config.js
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/home/pn/.npm,uid=1000,gid=1000 npx webpack --mode development --progress

FROM base as deps
COPY --chown=pn:pn Makefile Makefile
RUN make deps-editable
COPY --chown=pn:pn requirements/base.txt requirements/base.txt
RUN --mount=type=cache,target=/home/pn/.cache/pip,uid=1000,gid=1000 \
pip install --upgrade pip && \
pip install --use-pep517 -r requirements/base.txt

FROM devtest_base as test_deps
COPY --chown=pn:pn Makefile Makefile
RUN make deps-editable
COPY --chown=pn:pn requirements/base.txt requirements/base.txt
COPY --chown=pn:pn requirements/test.txt requirements/test.txt
RUN --mount=type=cache,target=/home/pn/.cache/pip,uid=1000,gid=1000 pip install --use-pep517 -r requirements/test.txt

FROM devtest_base as dev_deps
COPY --chown=pn:pn Makefile Makefile
RUN make deps-editable
COPY --chown=pn:pn requirements requirements
RUN --mount=type=cache,target=/home/pn/.cache/pip,uid=1000,gid=1000 pip install --use-pep517 -r requirements/dev.txt
COPY --from=dev_assets --chown=pn:pn /home/pn/app/node_modules /home/pn/app/node_modules

FROM deps as production
COPY --chown=pn:pn . .
COPY --chown=pn:pn --from=assets /home/pn/app/funnel/static /home/pn/app/funnel/static
ENTRYPOINT ["uwsgi", "--ini"]

FROM production as supervisor
USER root
RUN \
apt-get update -yqq && \
apt-get install -yqq --no-install-recommends supervisor && \
apt-get autoclean -yqq && \
apt-get autoremove -yqq && \
mkdir -pv /var/log/supervisor
COPY ./docker/supervisord/supervisord.conf /etc/supervisor/supervisord.conf
# COPY ./docker/uwsgi/emperor.ini /etc/uwsgi/emperor.ini
ENTRYPOINT ["/usr/bin/supervisord"]

FROM test_deps as test
ENV PWD=/home/pn/app
COPY --chown=pn:pn . .

COPY --chown=pn:pn --from=assets /home/pn/app/funnel/static /home/pn/app/funnel/static
ENTRYPOINT ["/home/pn/app/docker/entrypoints/ci-test.sh"]
FROM dev_deps as dev
RUN --mount=type=cache,target=/home/pn/.cache/pip,uid=1000,gid=1000 cp -R /home/pn/.cache/pip /home/pn/tmp/.cache_pip
RUN mv /home/pn/tmp/.cache_pip /home/pn/.cache/pip
COPY --chown=pn:pn --from=dev_assets /home/pn/app/funnel/static /home/pn/app/funnel/static
RUN mkdir -pv /home/funnel/app/coverage && chown -R 1000:1000 /home/funnel/.cache /home/funnel/app/coverage
# hadolint ignore=DL3008,DL4006,SC2046
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update -yqq \
&& apt-get install -yqq --no-install-recommends xvfb firefox-esr \
&& apt-get autoclean -yqq \
&& apt-get autoremove -yqq \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL $(curl -fsSL https://api.github.com/repos/mozilla/geckodriver/releases/latest \
| grep browser_download_url \
| grep 'linux64.tar.gz\"' \
| grep -o 'http.*\.gz') \
| tar -xvz -C /usr/local/bin
USER funnel
ENV PYTHONUNBUFFERED=1
ENV GITHUB_ACTIONS=true
COPY --chown=funnel:funnel requirements/base.txt requirements/test.txt ./requirements/
RUN --mount=type=cache,target=/home/funnel/.cache/pip,uid=1000,gid=1000 make install-python-test
ENTRYPOINT [ "/home/funnel/app/docker/entrypoints/ci.sh" ]
Loading
Loading