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

Use a registry for storing docker frontend image #57

Merged
merged 1 commit into from
Jul 4, 2023
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
30 changes: 21 additions & 9 deletions .castor/infra.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,44 @@ function destroy(

docker_compose(['down', '--remove-orphans', '--volumes', '--rmi=local'], withBuilder: true);
$files = finder()
->in(variable('root_dir') . '/infrastructure/docker/services/router/etc/ssl/certs/')
->in(variable('root_dir') . '/infrastructure/docker/services/router/certs/')
->name('*.pem')
->files()
;
fs()->remove($files);
}

#[AsTask(description: 'Push images to the registry')]
function push(): void
{
docker_compose(['push'], withBuilder: true);
}

#[AsTask(description: 'Pull images from the registry')]
function pull(): void
{
docker_compose(['pull', '-q'], withBuilder: true);
}

#[AsTask(description: 'Generates SSL certificates (with mkcert if available or self-signed if not)')]
function generate_certificates(
#[AsOption(description: 'Force the certificates re-generation without confirmation', shortcut: 'f')]
bool $force = false,
): void {
if (file_exists(variable('root_dir') . '/infrastructure/docker/services/router/etc/ssl/certs/cert.pem') && !$force) {
if (file_exists(variable('root_dir') . '/infrastructure/docker/services/router/certs/cert.pem') && !$force) {
io()->comment('SSL certificates already exists.');
io()->note('Run "castor infra:generate-certificates --force" to generate new certificates.');

return;
}

if ($force) {
if (file_exists($f = variable('root_dir') . '/infrastructure/docker/services/router/etc/ssl/certs/cert.pem')) {
io()->comment('Removing existing certificates in infrastructure/docker/services/router/etc/ssl/certs/*.pem.');
if (file_exists($f = variable('root_dir') . '/infrastructure/docker/services/router/certs/cert.pem')) {
io()->comment('Removing existing certificates in infrastructure/docker/services/router/certs/*.pem.');
unlink($f);
}

if (file_exists($f = variable('root_dir') . '/infrastructure/docker/services/router/etc/ssl/certs/key.pem')) {
if (file_exists($f = variable('root_dir') . '/infrastructure/docker/services/router/certs/key.pem')) {
unlink($f);
}
}
Expand All @@ -125,8 +137,8 @@ function generate_certificates(

run([
'mkcert',
'-cert-file', 'infrastructure/docker/services/router/etc/ssl/certs/cert.pem',
'-key-file', 'infrastructure/docker/services/router/etc/ssl/certs/key.pem',
'-cert-file', 'infrastructure/docker/services/router/certs/cert.pem',
'-key-file', 'infrastructure/docker/services/router/certs/key.pem',
$rootDomain,
"*.{$rootDomain}",
...variable('extra_domains'),
Expand All @@ -141,9 +153,9 @@ function generate_certificates(
return;
}

run(['infrastructure/docker/services/router/generate-ssl.sh']);
run(['infrastructure/docker/services/router/generate-ssl.sh'], quiet: true);

io()->success('Successfully generated self-signed SSL certificates in infrastructure/docker/services/router/etc/ssl/certs/*.pem.');
io()->success('Successfully generated self-signed SSL certificates in infrastructure/docker/services/router/certs/*.pem.');
io()->comment('Consider installing mkcert to generate locally trusted SSL certificates and run "castor infra:generate-certificates --force".');

if ($force) {
Expand Down
17 changes: 10 additions & 7 deletions .castor/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function about(): void
}

#[AsTask(description: 'Opens a shell (bash) into a builder container')]
function builder(string $user = 'app'): void
function builder(): void
{
$c = get_context()
->withTimeout(null)
Expand All @@ -56,7 +56,7 @@ function builder(string $user = 'app'): void
->withQuiet()
->withAllowFailure()
;
docker_compose_run('bash', c: $c, user: $user);
docker_compose_run('bash', c: $c);
}

#[AsContext(default: true)]
Expand Down Expand Up @@ -98,15 +98,18 @@ function create_default_context(): Context
$data['user_id'] = 1000;
}

// @phpstan-ignore-next-line
return new Context($data, pty: 'dev' === $data['env']);
return new Context(
// @phpstan-ignore-next-line
$data,
pty: 'dev' === $data['env'],
environment: create_default_environment(),
);
}

function docker_compose_run(
string $runCommand,
Context $c = null,
string $service = 'builder',
string $user = 'app',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not possible to exec something with something else than app. Anyway, we never changed this value, right?

bool $noDeps = true,
string $workDir = null,
bool $portMapping = false,
Expand All @@ -115,7 +118,6 @@ function docker_compose_run(
$command = [
'run',
'--rm',
'-u', $user,
];

if ($noDeps) {
Expand Down Expand Up @@ -156,9 +158,10 @@ function docker_compose(array $subCommand, Context $c = null, bool $withBuilder
'PROJECT_DIRECTORY' => variable('project_directory'),
'PROJECT_ROOT_DOMAIN' => variable('root_domain'),
'PROJECT_DOMAINS' => $domains,
'USER_ID' => variable('user_id'),
'COMPOSER_CACHE_DIR' => variable('composer_cache_dir'),
'PHP_VERSION' => variable('php_version'),
], false)
], true)
;

$command = [
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@ name: Continuous Integration

permissions:
contents: read
packages: read

jobs:
ci:
name: Continuous Integration
runs-on: ubuntu-latest
env:
BUILDKIT_PROGRESS: plain
DOCKER_BUILDKIT: 1
CI: 1
steps:
-
name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: 'ghcr.io'
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

-
uses: actions/checkout@v3

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@
/.castor.stub.php
/infrastructure/docker/.env
/infrastructure/docker/docker-compose.override.yml
/infrastructure/docker/services/router/etc/ssl/certs/*
/infrastructure/docker/services/router/certs/*
20 changes: 18 additions & 2 deletions castor.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,27 @@ function create_default_variables(): array
];
}

/**
* @return array<string, mixed>
*/
function create_default_environment(): array
{
return [
'BUILDER_VERSION' => 'latest',
'FRONTEND_VERSION' => 'latest',
'ROUTER_VERSION' => 'latest',
];
}

#[AsTask(description: 'Builds and starts the infrastructure, then install the application (composer, yarn, ...)')]
function start(): void
function start(bool $build = false): void
{
infra\generate_certificates(false);
infra\build();
if ($build) {
infra\build();
} else {
infra\pull();
}
infra\up();
cache_clear();
install();
Expand Down
11 changes: 6 additions & 5 deletions infrastructure/docker/docker-compose.builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ volumes:

services:
builder:
image: "ghcr.io/jolicode/monologue/builder:${BUILDER_VERSION:-latest}"
lyrixx marked this conversation as resolved.
Show resolved Hide resolved
build:
context: services/php
target: builder
# cache_to:
# - "ghcr.io/jolicode/monologue/builder:${BUILDER_VERSION:-latest}"
# cache_from:
# - "ghcr.io/jolicode/monologue/builder:${BUILDER_VERSION:-latest}"
Comment on lines +12 to +15
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want, we can share the cache on the registry. Not sure it's useful tho

depends_on:
- postgres
environment:
- COMPOSER_MEMORY_LIMIT=-1
# The following list contains the common environment variables exposed by CI platforms
- UID=${USER_ID}
- GITHUB_ACTIONS
- CI # Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari
- CONTINUOUS_INTEGRATION # Travis CI, Cirrus CI
- BUILD_NUMBER # Jenkins, TeamCity
- RUN_ID # TaskCluster, dsari
volumes:
- "../../${PROJECT_DIRECTORY}:/home/app/application:cached"
- "${COMPOSER_CACHE_DIR}:/home/app/.composer/cache"
Expand Down
16 changes: 14 additions & 2 deletions infrastructure/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ volumes:

services:
router:
build: services/router
image: "ghcr.io/jolicode/monologue/router:${ROUTER_VERSION:-latest}"
build:
context: services/router
# cache_to:
# - "ghcr.io/jolicode/monologue/router:${ROUTER__VERSION:-latest}"
# cache_from:
# - "ghcr.io/jolicode/monologue/router:${ROUTER__VERSION:-latest}"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "./services/router/certs:/etc/ssl/certs"
network_mode: host

frontend:
image: "ghcr.io/jolicode/monologue/frontend:${FRONTEND_VERSION:-latest}"
build:
context: services/php
target: frontend
# cache_to:
# - "ghcr.io/jolicode/monologue/frontend:${FRONTEND_VERSION:-latest}"
# cache_from:
# - "ghcr.io/jolicode/monologue/frontend:${FRONTEND_VERSION:-latest}"
depends_on:
- postgres
volumes:
Expand All @@ -29,7 +41,7 @@ services:
- "traefik.http.routers.${PROJECT_NAME}-frontend-unsecure.middlewares=redirect-to-https@file"

postgres:
build: services/postgres
image: postgres:15.2
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid pushing an extra image to the registry

environment:
POSTGRES_PASSWORD: monologue
POSTGRES_USER: monologue
Expand Down
17 changes: 12 additions & 5 deletions infrastructure/docker/services/php/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
FROM debian:11.7-slim as php-base

LABEL org.opencontainers.image.source https://github.com/jolicode/monologue

RUN apt-get update \
&& apt install -y --no-install-recommends \
curl \
ca-certificates \
gnupg \
&& curl -s https://packages.sury.org/php/apt.gpg | gpg --dearmor > /usr/share/keyrings/deb.sury.org-php.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php bullseye main" > /etc/apt/sources.list.d/sury.list
&& echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php bullseye main" > /etc/apt/sources.list.d/sury.list \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
Expand All @@ -33,14 +37,19 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

# Fake user to maps with the one on the host
COPY entrypoint /
ARG USER_ID
RUN addgroup --gid 1000 app && \
adduser --system --uid $USER_ID --home /home/app --shell /bin/bash app
RUN addgroup --gid $USER_ID app && \
adduser --system --uid $USER_ID --home /home/app --shell /bin/bash app && \
curl -Ls https://github.com/tianon/gosu/releases/download/1.16/gosu-amd64 | \
install /dev/stdin /usr/local/bin/gosu && \
sed "s/{{ application_user }}/app/g" -i /entrypoint

# Configuration
COPY base/php-configuration /etc/php/${PHP_VERSION}

WORKDIR /home/app/application
ENTRYPOINT [ "/entrypoint" ]

FROM php-base as frontend

Expand Down Expand Up @@ -94,5 +103,3 @@ RUN mkdir -p "/home/app/.composer/cache" \

ENV PATH="$PATH:/home/app/application/tools/php-cs-fixer/vendor/bin"
ENV PATH="$PATH:/home/app/application/tools/phpstan/vendor/bin"

USER app
26 changes: 26 additions & 0 deletions infrastructure/docker/services/php/entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh

set -e
set -u

if [ $(id -u) != 0 ]; then
echo "Running this image as non root is not allowed"
exit 1
fi

: "${UID:=0}"
: "${GID:=${UID}}"

if [ "$#" = 0 ]; then
set -- "$(command -v bash 2>/dev/null || command -v sh)" -l
fi

if [ "$UID" != 0 ]; then
usermod -u "$UID" "{{ application_user }}" >/dev/null 2>/dev/null && {
groupmod -g "$GID" "{{ application_user }}" >/dev/null 2>/dev/null ||
usermod -a -G "$GID" "{{ application_user }}" >/dev/null 2>/dev/null
}
set -- gosu "${UID}:${GID}" "${@}"
fi

exec "$@"
3 changes: 0 additions & 3 deletions infrastructure/docker/services/postgres/Dockerfile

This file was deleted.

6 changes: 5 additions & 1 deletion infrastructure/docker/services/router/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
FROM traefik:v2.7

COPY etc/. /etc/
LABEL org.opencontainers.image.source https://github.com/jolicode/monologue

COPY traefik /etc/traefik

VOLUME [ "/etc/ssl/certs" ]
Empty file.
5 changes: 3 additions & 2 deletions infrastructure/docker/services/router/generate-ssl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

BASE=$(dirname $0)

rm -rf mkdir $BASE/certs/

CERTS_DIR=$BASE/etc/ssl/certs
CERTS_DIR=$BASE/certs

rm -rf mkdir $CERTS_DIR

mkdir -p $CERTS_DIR

Expand Down