feat(init): first commit

This commit is contained in:
Philippe Caseiro 2023-06-05 15:24:42 +02:00
parent 1ee84e57a5
commit b13a5e892f
37 changed files with 926 additions and 2 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
/tmp
/tools
/.trivy
/docs

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/tmp
/tools
/.trivy

41
Makefile Normal file
View File

@ -0,0 +1,41 @@
IMAGE_NAME := reg.cadoles.com/cadoles/sp
DOCKERFILE ?=
DAY_SUFFIX_TAG ?= $(shell date +%Y%m%d)
build:
_build:
docker \
build \
-t "$(IMAGE_NAME):$(IMAGE_TAG)" \
-f $(DOCKERFILE) \
.
scan:
_scan: tools/trivy/bin/trivy
mkdir -p .trivy/$(IMAGE_NAME)/$(IMAGE_TAG)
tools/trivy/bin/trivy --cache-dir .trivy/.cache image -o ".trivy/$(IMAGE_NAME)/$(IMAGE_TAG)/report.txt" $(TRIVY_ARGS) $(IMAGE_NAME):$(IMAGE_TAG)
cat ".trivy/$(IMAGE_NAME)/$(IMAGE_TAG)/report.txt"
tools/trivy/bin/trivy:
mkdir -p tools/trivy/bin
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b ./tools/trivy/bin v0.27.1
release:
_release:
docker tag $(IMAGE_NAME):$(IMAGE_TAG) $(IMAGE_NAME):$(IMAGE_TAG)-$(DAY_SUFFIX_TAG)
docker push $(IMAGE_NAME):$(IMAGE_TAG)-$(DAY_SUFFIX_TAG)
docker push $(IMAGE_NAME):$(IMAGE_TAG)
_test: tools/bin/bash_unit
tools/bin/bash_unit ./tests/test_$(IMAGE_TAG).sh
tools/bin/bash_unit:
mkdir -p tools/bin
cd tools/bin && bash <(curl -s https://raw.githubusercontent.com/pgrange/bash_unit/master/install.sh)
include recipes/*.mk

View File

@ -1,3 +1,19 @@
# sp-containers =======
# Shibboleth and OIDC ServiceProvider containers based on "apache".
Shibboleth and OIDC ServiceProvider containers based on "apache". Recettes de construction d'image de conteneurs Symfony prêts à l'emploi pour le développement ou la production.
Inspiré de [`sherifabdlnaby/kubephp`](https://github.com/sherifabdlnaby/kubephp)
## Liste des images
|Image|Description|
|-----|-----------|
|`reg.cadoles.com/cadoles/sp:alpine-oidc-base`|Alpine 3.18, Apache 2.4, mod-auth-oidc|
|`reg.cadoles.com/cadoles/sp:debian-shib-base`|Debian 11.7, Aapache 2.4, shibboleth-sp 3.2.2, php 7.4, php-fpm |
[Accéder au dépôt](https://reg.cadoles.com/harbor/projects/5/repositories/sp/artifacts-tab)
## Documentation
[Voir la documentation](./docs/README.md)
>>>>>>> c2e23db (feat(init): first commit)

13
docs/README.md Normal file
View File

@ -0,0 +1,13 @@
# Documentation
## Tutoriels
- [Créer une image pour votre projet Symfony](./docker-usage.md)
- [Utilisation avec Kubernetes](./kubernetes-usage.md)
- [Créer une application avec docker-compose](./starting-with-docker-compose.md)
## Comment faire pour ... ?
- [Installer des paquets supplémentaires](./additional-packages.md)
- [Contextualiser la configuration](./configuration-contextualization.md)
- [Utiliser une version spécifique de NodeJS](./customize_nodejs_version.md)

View File

@ -0,0 +1,12 @@
# Installer des paquets supplémentaires
Vous pouvez spécifier des paquets supplémentaires (par exemple des dépendances PHP) en ajoutant l'argument de construction `ADDITIONAL_PACKAGES`.
**Exemple**
```
docker build \
-t my-symfony-app:latest \
--build-arg "ADDITIONAL_PACKAGES=vim=9.0.0999-r0 curl=7.87.0-r0" \
.
```

View File

@ -0,0 +1,19 @@
# Contextualisation la configuration
Les images intègrent l'utilitaire [`gomplate`](https://docs.gomplate.ca/) par défaut.
Ce dernier est utilisé au démarrage du conteneur afin de compléter les fichiers prévus à cet effet avec les données de contexte. Cette opération est réalisée par le script [`files/common/scripts/run.sh`](../files/common/scripts/run.sh).
Le principe général est le suivant:
1. Au démarrage du conteneur:
1. Trouver tous les fichiers de l'arborescence correspondant dont le nom termine par `<CHEMIN>/<NOM_FICHIER>.<EXT>.gotmpl`
2. Générer le fichier `<CHEMIN>/<NOM_FICHIER>.<EXT>` via `gomplate`
> Par exemple, le fichier `/etc/nginx/nginx.conf.gotmpl` sera automatiquement transformé en `/etc/nginx/nginx.conf` au démarrage du conteneur.
Cette opération s'appliquent également aux fichiers ajoutés par les images étendant les images de base, ainsi que dans les volumes.
Une grande partie des fichiers de configuration par défaut des images sont prévus pour être compatibles avec ce mécanisme. Vous pouvez donc personnaliser une partie de leurs attributs via des variables d'environnement.
> [Voir par exemple le fichier `files/common/nginx/nginx.conf.gotmpl`](../files/common/nginx/nginx.conf.gotmpl).

View File

@ -0,0 +1,9 @@
# Utiliser une version spécifique de NodeJS
Les images intègrent l'outil [nvm](https://github.com/nvm-sh/nvm) par défaut. Cet outil permet d'installer une version spécifique de NodeJS.
Pour personnaliser la version de NodeJS installée dans l'image de votre conteneur, créez un fichier `.nvmrc` à la racine de votre projet Symfony contenant la version de NodeJS souhaitée (par exemple: `lts/hydrogen` ou `v18.13.0`).
La liste des versions disponibles est visible via la commande `nvm ls-remote`.
(Plus d'informations sur le site du projet NVM](https://github.com/nvm-sh/nvm#nvmrc)

102
docs/docker-usage.md Normal file
View File

@ -0,0 +1,102 @@
# Créer une image Docker pour votre projet Symfony
> ⚠ La procédure suivante s'applique dans le cadre d'un déploiement sur Docker.
>
> Pour créer une image à destination d'un environnement Kubernetes, préférer
> la procédure ["Usage dans Kubernetes"](./kubernetes-usage.md)
## Création d'une image
1. Dans le répertoire de votre projet, créer le fichier `Dockerfile` suivant:
```Dockerfile
ARG ADDITIONAL_PACKAGES="<packages_list>"
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-standalone
```
> La variable d'environnement `ADDITIONAL_PACKAGES` permet de définir une liste de paquets supplémentaires à installer avant d'exécuter les "triggers" de base embaqrués par l'image. Voir ["Installer des paquets supplémentaires"](./additional-packages.md) pour plus d'information.
2. Créer le fichier `.dockerignore` avec les données suivantes:
```text
/vendor
/var
```
3. Construire l'image de votre application
```sh
docker build \
-t my-symfony-app:latest \
.
```
4. Exécuter l'image de votre application
```sh
docker run \
-it \
--rm \
-p 8080:8080 \
my-symfony-app:latest
```
5. Ouvrir l'URL http://localhost:8080. Votre application devrait s'afficher.
## Utilisation de votre image en développement
1. **Avec docker**:
```sh
docker run \
-it --rm \
-p 8080:8080 \
-v "${PWD}/src:/app/src:delegated" \
-v "${PWD}/templates:/app/templates:delegated" \
-v "${PWD}/translations:/app/translations:delegated" \
-v "${PWD}/tests:/app/tests:delegated" \
-v "${PWD}/config:/app/config:delegated" \
-v "${PWD}/.env:/app/.env:delegated" \
test-symfony-app
```
2. **Avec docker-compose**:
1. Créer un fichier `Dockerfile.standalone` à la racine de votre projet:
```dockerfile
ARG ADDITIONAL_PACKAGES=""
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-standalone
```
2. Créer un fichier `docker-compose.yml`:
```yaml
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile.standalone
ports:
- ${APP_HTTP_PORT:-8080}:8080
volumes:
- ./src:/app/src:delegated
- ./templates:/app/templates:delegated
- ./translations:/app/translations:delegated
- ./tests:/app/tests:delegated
- ./config:/app/config:delegated
- ./.env:/app/.env:delegated
environment:
PHP_FPM_MEMORY_LIMIT: 128m
APP_ENV: dev
## truncated for brevity
```
3. Démarrer l'environnement
```sh
docker-compose up
```

3
docs/kubernetes-usage.md Normal file
View File

@ -0,0 +1,3 @@
# Utilisation avec Kubernetes
> `TODO`

View File

@ -0,0 +1,115 @@
# Créer un projet en utilisant docker-compose
> ⚠ La procédure suivante s'applique dans le cadre du développement d'une application
> en utilisant l'image ["standalone"](./docker-usage.md).
## Création du projet symfony
1. **Création du projet**
```shell
symfony new app --webapp [other options...]
# voir https://symfony.com/download pour l'installation de symfony CLI
```
2. **Création du ficher Dockerfile**
A la racine du projet, créer le fichier `Dockerfile` et placer ce contenu:
```dockerfile
ARG ADDITIONAL_PACKAGES="php81-pdo=8.1.14-r0 php81-pdo_pgsql=8.1.14-r0"
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-standalone
```
**Notes**: adapter la liste des paquets additionnels à votre besoin.
3. **Création du fichier docker-compose**
A la racine du projet, créer le fichier (ou remplacer celui existant)`docker-compose.yml`, supprimer le fichier `docker-compose.override.yml` et placer ce contenu:
```yaml
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./:/app:delegated
environment:
PHP_FPM_MEMORY_LIMIT: 128m
APP_ENV: dev
DATABASE_URL: postgresql://${POSTGRES_PASSWORD:-app}:${POSTGRES_PASSWORD:-app}@db:5432/${POSTGRES_DB:-app}?serverVersion=15&chartset=utf8
ports:
- ${APP_HTTP_PORT:-8080}:8080
db:
image: postgres:${POSTGRES_VERSION:-15}-alpine
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-app}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-app}
POSTGRES_USER: ${POSTGRES_USER:-app}
volumes:
- app-db-data:/var/lib/postgresql/data:rw
volumes:
app-db-data:
```
4. Création du fichier `Makefile`
A la racine du projet, créer le fichier `Makefile` et placer ce contenu:
```make
dc := docker-compose
de := $(dc) exec
dr := $(dc) run --rm
app := $(dr) --no-deps app
.DEFAULT_GOAL := help
.PHONY: help
help: ## Affiche cette aide
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: dev
dev: vendor/autoload.php ## Lance le serveur de développement
$(dc) up
# -----------------------------------
# Utilitaires
# -----------------------------------
.PHONY: php
app: ## Se connecte au conteneur PHP
$(app) /bin/sh
# -----------------------------------
# Builds
# -----------------------------------
.PHONY: build
build: ## build application image
docker build \
-t app-standalone:latest \
.
# -----------------------------------
# Dependencies
# -----------------------------------
vendor/autoload.php: composer.lock
$(app) composer install
touch vendor/autoload.php
```
## Démarrer l'environnement
```shell
cd app/
make
# doit afficher la liste des commandes disponible
make dev
# doit démarrer l'environnement docker défini dans votre docker-compose.yml
# l'application doit être disponible à l'adresse http://localhost:8080
```
## Installer des dépendances `composer`
```shell
make app
# dans le conteneur
composer require ....
```

View File

@ -0,0 +1,14 @@
FROM reg.cadoles.com/proxy_cache/library/alpine:edge
#FROM reg.cadoles.com/proxy_cache/library/httpd:alpine3.18
# Adding testing repo
RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update && apk add apache-mod-auth-openidc
COPY files/alpine/sp-oidc/base/conf.d/mod-auth-openidc.conf /etc/apache2/conf.d/mod-auth-openidc.conf
COPY files/alpine/sp-oidc/base/conf.d/default-vhost.conf /etc/apache2/conf.d/default-vhost.conf
COPY files/alpine/sp-oidc/base/scripts/httpd-foreground /usr/local/bin/
CMD ["httpd-foreground"]

View File

@ -0,0 +1,14 @@
FROM reg.cadoles.com/proxy_cache/library/alpine:edge
#FROM reg.cadoles.com/proxy_cache/library/httpd:alpine3.18
# Adding testing repo
RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk update && apk add apache-mod-auth-openidc
COPY conf.d/mod-auth-openidc.conf /etc/apache2/conf.d/mod-auth-openidc.conf
COPY conf.d/default-vhost.conf /etc/apache2/conf.d/default-vhost.conf
COPY scripts/httpd-foreground /usr/local/bin/
CMD ["httpd-foreground"]

View File

@ -0,0 +1,29 @@
<VirtualHost _default_:80>
ServerName ${SP_SERVER_NAME}:80
DocumentRoot /var/www/html
CustomLog /proc/self/fd/1 common
ErrorDocument 400 /error/
ErrorDocument 401 /error/
ErrorDocument 403 /error/
ErrorDocument 404 /error/
ErrorDocument 500 /error/
ErrorDocument 502 /error/
ErrorDocument 503 /error/
ErrorDocument 504 /error/
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
<Location /error>
AllowOverride All
Options +Indexes
Require all granted
</Location>
</VirtualHost>

View File

@ -0,0 +1,14 @@
LoadModule auth_openidc_module modules/mod_auth_openidc.so
OIDCProviderMetadataURL ${SP_OIDC_PROVIDER_METADATA_URL} #http://portal.mse.local:8000/auth/.well-known/openid-configuration
OIDCClientID ${SP_OIDC_CLIENT_NAME} #mse
OIDCClientSecret ${SP_OIDC_CLIENT_SERCRET} #$mse&123456$
OIDCProviderTokenEndpointAuth client_secret_basic
OIDCCookieSameSite On
OIDCSessionType client-cookie
OIDCXForwardedHeaders X-Forwarded-Host
# OIDCRedirectURI is a vanity URL that must point to a path protected by this module but must NOT point to any content
OIDCRedirectURI ${SP_OIDC_REDIRECT_URI} #http://portal.mse.local:8000/protected/redirect_uri
OIDCCryptoPassphrase ${SP_OIDC_CRYPTO_PASSPHRASE} #$mse&123456$
OIDCOAuthAcceptTokenAs header
OIDCUnAutzAction 302 ${SP_OIDC_ERROR_URI} #http://portal.mse.local:8000/erreur?msg=mod_auth_fail

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
# Apache gets grumpy about PID files pre-existing
rm -f /run/apache2/httpd.pid
exec httpd -DFOREGROUND "$@"

View File

@ -0,0 +1,23 @@
#!/bin/bash
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )";
source "$SCRIPT_DIR/lib.sh"
# Test reg.cadoles.com/cadoles/symfony:alpine-php-7.4-standalone with Symfony 4.4
test_alpine_sp_oidc() {
# FIXME
local container_name=$(run_symfony_app_container "4.4" "7.4" "alpine-php-7.4-standalone")
local image_name=$(docker inspect -f '{{.Config.Image}}' ${container_name})
trap_add "docker kill ${container_name}" EXIT
trap_add "docker rmi -f ${image_name}" EXIT
local app_url="http://$(docker port ${container_name} 8080/tcp)"
# Check that application is responding as expected
local page_content=$(curl -s "${app_url}" | pandoc -f html -t plain)
assert_matches 'Welcome to Symfony 4\.4\.*' "${page_content}" "Could not find Symfony default welcome message !"
}

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
# Apache gets grumpy about PID files pre-existing
rm -f /run/apache2/httpd.pid
exec httpd -DFOREGROUND "$@"

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -eu
for CHECK in $@; do
/bin/sh "/usr/local/share/cadoles-symfony/healthcheck/check-${CHECK}.sh"
done

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -eu
wget --quiet --tries=1 --spider 127.0.0.1:8090/healthcheck || exit 1;

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -eu
# TODO

View File

@ -0,0 +1,89 @@
upstream backend {
server {{ env.Getenv "NGINX_APP_UPSTREAM_BACKEND_SERVER" "unix:/tmp/php-fpm.sock" }};
keepalive {{ env.Getenv "NGINX_APP_UPSTREAM_BACKEND_KEEPALIVE" "40" }};
# Must be less than php-fpm.conf:pm.max_requests
keepalive_requests {{ env.Getenv "NGINX_APP_UPSTREAM_BACKEND_KEEPALIVE_REQUESTS" "250" }};
keepalive_timeout {{ env.Getenv "NGINX_APP_UPSTREAM_BACKEND_KEEPALIVE_TIMEOUT" "10" }};
}
server {
listen {{ env.Getenv "NGINX_APP_SERVER_LISTEN" "8080" }} default_server;
server_name {{ env.Getenv "NGINX_APP_SERVER_NAME" "_" }};
set $base /app;
root $base{{ env.Getenv "NGINX_APP_ROOT" "/public"}};
# deny all dot files except .well-known
location ~ /\.(?!well-known) {
deny all;
}
# index.php
index index.php;
# index.php fallback
location / {
# try to serve file directly, fallback to index.php
try_files $uri {{ env.Getenv "NGINX_APP_PHP_INDEX" "/index.php"}}$is_args$args;
}
# Disable falling back to PHP script for the asset directories;
location ~ ^/({{ env.Getenv "NGINX_APP_ASSETS_DIRECTORIES" "public|bundles|web"}})/ {
try_files $uri =404;
}
# handle non-files
location ~ {{ env.Getenv "NGINX_APP_PHP_NON_FILE_PATTERN" "^/index\\.php(/|$)" }} {
# default fastcgi_params
include fastcgi_params;
# fastcgi settings
fastcgi_pass backend;
fastcgi_index index.php;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
# fastcgi params
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=none";
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
# favicon.ico
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
expires 7d;
access_log off;
}
# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin "*";
expires 7d;
access_log off;
}
}

View File

@ -0,0 +1,10 @@
# Compression
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 32 16k;
gzip_http_version 1.1;
gzip_min_length 250;
gzip_types image/jpeg image/bmp image/svg+xml text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript image/x-icon;

View File

@ -0,0 +1,9 @@
server {
listen 8090;
location /healthcheck {
stub_status;
access_log off;
allow 127.0.0.1;
deny all;
}
}

View File

@ -0,0 +1,3 @@
# logging
access_log /dev/stdout;
error_log stderr {{ env.Getenv "NGINX_ERROR_LOG_LEVEL" "warn" }};

View File

@ -0,0 +1,3 @@
# MIME
include mime.types;
default_type application/octet-stream;

View File

@ -0,0 +1,6 @@
# Non Root Temp Paths
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;

View File

@ -0,0 +1,4 @@
# Replace loadbalancer IP(real-ip) with actual client IP.
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

View File

@ -0,0 +1,50 @@
# user www-data;
pid /tmp/nginx.pid;
worker_processes auto;
daemon off;
events {
worker_connections {{ env.Getenv "NGINX_EVENTS_WORKER_CONNECTIONS" "1024" }};
}
http {
charset {{ env.Getenv "NGINX_CHARSET" "utf-8" }};
# copies data between one FD and other from within the kernel
# faster than read() + write()
sendfile {{ env.Getenv "NGINX_SENDFILE" "on" }};
# send headers in one piece, it is better than sending them one by one
tcp_nopush {{ env.Getenv "NGINX_TCP_NOPUSH" "on" }};
# don't buffer data sent, good for small data bursts in real time
tcp_nodelay {{ env.Getenv "NGINX_TCP_NODELAY" "on" }};
# allow the server to close connection on non responding client, this will free up memory
reset_timedout_connection {{ env.Getenv "NGINX_RESET_TIMEDOUT_CONNECTION" "on" }};
# hide server info for security
server_tokens {{ env.Getenv "NGINX_SERVER_TOKENS" "off" }};
log_not_found {{ env.Getenv "NGINX_LOG_NOT_FOUND" "off" }};
types_hash_max_size 2048;
# if the request body size is more than the buffer size, then the entire (or partial)
# request body is written into a temporary file
client_body_buffer_size 128k;
# maximum body size
client_max_body_size {{ env.Getenv "NGINX_CLIENT_MAX_BODY_SIZE" "16M" }};
# maximum number and size of buffers for large headers to read from client request
large_client_header_buffers 4 256k;
# cache information about FDs, frequently accessed files
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 5;
open_file_cache_errors off;
# load configs
include /etc/nginx/conf.d/*.conf;
}

View File

@ -0,0 +1,10 @@
#!/bin/sh
export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release
NVM_DIR="$HOME/.nvm"
source "$NVM_DIR/nvm.sh"
nvm_get_arch() { nvm_echo "x64-musl"; }
nvm $@

View File

@ -0,0 +1,34 @@
#!/bin/bash
set -eo pipefail
main() {
if [ "${INSTALL_DEPENDENCIES}" == "0" ]; then
echo "Dependencies installation disabled. Doing nothing."
exit
fi
install_additional_packages
}
# Return 3 for unknown distribution
install_additional_packages() {
if [ -z "${ADDITIONAL_PACKAGES}" ]; then
return
fi
echo "Installing additional packages '${ADDITIONAL_PACKAGES}'..."
if [ -f "/etc/debian_version" ]; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y ${ADDITIONAL_PACKAGES}
elif [ -f "/etc/alpine-release" ]; then
apk update
apk add --no-cache ${ADDITIONAL_PACKAGES}
else
return 3
fi
}
main

View File

@ -0,0 +1,24 @@
#!/bin/bash
set -eo pipefail
main() {
echo "Generating filesystem templates..."
generate_templates
exec $@
}
generate_templates() {
# Find *.gotmpl files and generate associated configuration files
local template_files=$(find / -type f -name '*.gotmpl')
for tmpl in $template_files; do
local dest_file=${tmpl%".gotmpl"}
echo "Generating file '$dest_file'..."
gomplate -f "$tmpl" > "$dest_file"
chmod $(stat -c '%a' "$tmpl") "$dest_file"
chown $(stat -c '%u:%g' "$tmpl") "$dest_file"
done
}
main $@

View File

@ -0,0 +1,27 @@
FROM reg.cadoles.com/proxy_cache/library/debian:stable-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update -y && \
apt-get install -y libapache2-mod-shib php-fpm
RUN a2enmod rewrite expires headers remoteip ssl \
proxy proxy_fcgi proxy_http proxy_balancer \
lbmethod_bybusyness lbmethod_byrequests lbmethod_bytraffic lbmethod_heartbeat
EXPOSE 80
COPY files/common/healthcheck /usr/local/share/cadoles/healthcheck
COPY files/common/scripts /usr/local/share/cadoles/scripts
SHELL ["/bin/bash", "-c"]
CMD ["/bin/bash"]
# ========= Child image build triggers ==========
ONBUILD COPY . /app
ONBUILD ARG ADDITIONAL_PACKAGES
ONBUILD ARG INSTALL_DEPENDENCIES
ONBUILD ARG INSTALL_COMPOSER_DEPENDENCIES
ONBUILD ARG INSTALL_NPM_DEPENDENCIES
ONBUILD RUN . /usr/local/share/cadoles/scripts/install-dependencies.sh

28
recipes/alpine-sp-oidc.mk Normal file
View File

@ -0,0 +1,28 @@
build: build-alpine-sp-oidc-base
build-alpine-sp-oidc-base:
$(MAKE) \
IMAGE_TAG=alpine-sp-oidc-base \
DOCKERFILE=files/alpine/sp-oidc/base/Dockerfile \
_build
scan: scan-alpine-sp-oidc-base
scan-alpine-sp-oidc-base:
$(MAKE) \
IMAGE_TAG=alpine-sp-oidc-base \
_scan
release: release-alpine-sp-oidc-base
release-alpine-sp-oidc-base:
$(MAKE) \
IMAGE_TAG=alpine-sp-oidc-base \
_release
test: test-alpine-sp-oidc-base
test-alpine-sp-oidc-base:
$(MAKE) \
IMAGE_TAG=alpine-sp-oidc-base \
_test

28
recipes/debian-sp-shib.mk Normal file
View File

@ -0,0 +1,28 @@
build: build-debian-sp-shib-base
build-debian-sp-shib-base:
$(MAKE) \
IMAGE_TAG=debian-sp-shib-base \
DOCKERFILE=files/debian/sp-shib/base/Dockerfile \
_build
scan: scan-debian-sp-shib-base
scan-debian-sp-shib-base:
$(MAKE) \
IMAGE_TAG=debian-sp-shib-base \
_scan
release: release-debian-sp-shib-base
release-debian-sp-shib-base:
$(MAKE) \
IMAGE_TAG=debian-sp-shib-base \
_release
test: test-debian-sp-shib-base
test-debian-sp-shib-base:
$(MAKE) \
IMAGE_TAG=debian-sp-shib-base \
_test

114
tests/lib.sh Normal file
View File

@ -0,0 +1,114 @@
#!/bin/bash
log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$@"; exit 1; }
run_symfony_app_container() {
set -e
trap "set +e" RETURN
local symfony_version=${1}
local php_version=${2}
local image_tag=${3}
cd "${SCRIPT_DIR}/.."
# Create temporary directory
local project_dir=$(mktemp -d)
local run_id=$(date +%s)
# Defer cleanup on exit
trap_add "rm -rf ${project_dir}" EXIT
# Create dummy Symfony project
symfony new --dir="${project_dir}" --version="${symfony_version}" --php="${php_version}" --webapp 1>&2
cat > "${project_dir}/Dockerfile" <<EOF
FROM reg.cadoles.com/cadoles/symfony:${image_tag}
EOF
cat > "${project_dir}/.dockerignore" <<EOF
/var
/vendor
EOF
local image_name="symfony-test-${image_tag}:${run_id}"
# Build Symfony project image
docker build \
-t "${image_name}" \
"${project_dir}" \
1>&2
local http_port=$(get_unused_port)
local container_name="symfony-test-${image_tag}-${run_id}"
# Start project image
docker run \
-d \
--rm \
-p "${http_port}:8080" \
--name "${container_name}" \
"${image_name}" \
1>&2
# Wait container is healthy with a timeout
local duration=0
local last_tick=$(date +%s)
local container_status=$(docker inspect -f '{{.State.Health.Status}}' ${container_name})
log "Waiting for container to become healthy..." 1>&2
until [ "${container_status}" == "healthy" ]; do
sleep 1
local now=$(date +%s)
duration=$(( ${duration} + ( ${now} - ${last_tick} ) ))
if [ ${duration} -gt 60 ]; then
fail "Container did not become healthy before timeout !"
fi
last_tick=${now}
container_status=$(docker inspect -f '{{.State.Health.Status}}' ${container_name})
done
echo "${container_name}"
}
get_unused_port() {
set -e
trap "set +e" RETURN
local lport=32768;
local uport=60999;
while true; do
local mport=$[${lport} + (${RANDOM} % $uport)];
(echo "" >/dev/tcp/127.0.0.1/${mport}) >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo ${mport};
return 0;
fi
done
}
# From https://stackoverflow.com/a/7287873
trap_add() {
local trap_add_cmd=$1;
shift || fatal "${FUNCNAME} usage error"
for trap_add_name in "$@"; do
trap -- "$(
# helper fn to get existing trap command from output
# of trap -p
extract_trap_cmd() { printf '%s\n' "$3"; }
# print existing trap command with newline
eval "extract_trap_cmd $(trap -p "${trap_add_name}")"
# print the new trap command
printf '%s\n' "${trap_add_cmd}"
)" "${trap_add_name}" \
|| fatal "unable to add to trap ${trap_add_name}"
done
}
declare -f -t trap_add

View File

@ -0,0 +1,23 @@
#!/bin/bash
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )";
source "$SCRIPT_DIR/lib.sh"
# Test reg.cadoles.com/cadoles/symfony:alpine-php-7.4-standalone with Symfony 4.4
test_alpine_sp_oidc() {
# FIXME
local container_name=$(run_symfony_app_container "4.4" "7.4" "alpine-php-7.4-standalone")
local image_name=$(docker inspect -f '{{.Config.Image}}' ${container_name})
trap_add "docker kill ${container_name}" EXIT
trap_add "docker rmi -f ${image_name}" EXIT
local app_url="http://$(docker port ${container_name} 8080/tcp)"
# Check that application is responding as expected
local page_content=$(curl -s "${app_url}" | pandoc -f html -t plain)
assert_matches 'Welcome to Symfony 4\.4\.*' "${page_content}" "Could not find Symfony default welcome message !"
}