Skip to content
Snippets Groups Projects
Commit e2c3d819 authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

initial import

parents
No related branches found
No related tags found
No related merge requests found
docker/containers/*
docker/.env
docker/docker-compose.yml
.vscode/launch.json
#!/bin/bash
# ======================================================================
#
# DOCKER DEV ENVIRONMENT :: INIT
# (work in progress)
#
# ----------------------------------------------------------------------
# 2021-11-nn <axel.hahn@iml.unibe.ch>
# ======================================================================
cd $( dirname $0 )
. $( basename $0 ).cfg
# ----------------------------------------------------------------------
# FUNCTIONS
# ----------------------------------------------------------------------
function h2(){
echo
echo -e "\e[33m>>>>> $*\e[0m"
}
function h3(){
echo
echo -e "\e[34m----- $*\e[0m"
}
function _gitinstall(){
h2 "install/ update app from git repo ${gitrepo} in ${gittarget} ..."
test -d ${gittarget} && ( cd ${gittarget} && git pull )
test -d ${gittarget} || git clone -b ${gitbranch} ${gitrepo} ${gittarget}
}
# set acl on local directory
function _setWritepermissions(){
h2 "set write permissions on ${gittarget} ..."
local _user=$( id -gn )
typeset -i local _user_uid=0
test -f /etc/subuid && _user_uid=$( grep $_user /etc/subuid 2>/dev/null | cut -f 2 -d ':' )-1
typeset -i local DOCKER_USER_OUTSIDE=$_user_uid+$DOCKER_USER_UID
# echo $DOCKER_USER_OUTSIDE
set -vx
# remove current acl
sudo setfacl -bR "${WRITABLEDIR}"
# default permissions: both the host user and the user with UID 33 (www-data on many systems) are owners with rwx perms
sudo setfacl -dRm u:${DOCKER_USER_OUTSIDE}:rwx,${_user}:rwx "${WRITABLEDIR}"
# permissions: make both the host user and the user with UID 33 owner with rwx perms for all existing files/directories
sudo setfacl -Rm u:${DOCKER_USER_OUTSIDE}:rwx,${_user}:rwx "${WRITABLEDIR}"
set +vx
}
# helper function: cut a text file starting from database start marker
# see _generateFiles()
function _fix_no-db(){
local _file=$1
if [ $DB_ADD = false ]; then
typeset -i local iStart=$( cat ${_file} | fgrep -n "$CUTTER_NO_DATABASE" | cut -f 1 -d ':' )-1
if [ $iStart -gt 0 ]; then
sed -ni "1,${iStart}p" ${_file}
fi
fi
}
# loop over all files in templates subdir make replacements and generate
# a target file.
# It skips if
# - 1st line is not starting with "# TARGET: filename"
# - target file has no updated lines
function _generateFiles(){
# re-read config vars
. $( basename $0 ).cfg
local _tmpfile=/tmp/newfilecontent$$.tmp
h2 "generate files from templates..."
for mytpl in $( ls -1 ./templates/* )
do
# h3 $mytpl
local _doReplace=1
# fetch traget file from first line
target=$( head -1 $mytpl | grep "^# TARGET:" | cut -f 2- -d ":" | awk '{ print $1 }' )
if [ -z "$target" ]; then
echo SKIP: $mytpl - target was not found in 1st line
_doReplace=0
fi
# if [ -f "../$target" ]; then
# echo SKIP: target file already exists: $target
# _doReplace=0
#fi
# write generated files to target
if [ $_doReplace -eq 1 ]; then
# write file from line 2 to a tmp file
sed -n '2,$p' $mytpl >$_tmpfile
# add generator
# sed -i "s#{{generator}}#generated by $0 - template: $mytpl - $( date )#g" $_tmpfile
local _md5=$( md5sum $_tmpfile | awk '{ print $1 }' )
sed -i "s#{{generator}}#GENERATED BY $0 - template: $mytpl - $_md5#g" $_tmpfile
# loop over vars to make the replacement
grep "^[a-zA-Z]" $( basename $0 ).cfg | while read line
do
# echo replacement: $line
mykey=$( echo $line | cut -f 1 -d '=' )
myvalue="$( eval echo \"\${$mykey}\" )"
# grep "{{$mykey}}" $_tmpfile
# TODO: multiline values fail here in replacement with sed
sed -i "s#{{$mykey}}#${myvalue}#g" $_tmpfile
done
_fix_no-db $_tmpfile
# echo "changes for $target:"
diff "../$target" "$_tmpfile" | grep -v "$_md5" | grep -v "^---" | grep .
if [ $? -eq 0 -o ! -f "../$target" ]; then
echo -n "$mytpl - changes detected - writing [$target] ... "
mkdir -p $( dirname "../$target" ) || exit 2
mv "$_tmpfile" "../$target" || exit 2
echo OK
else
rm -f $_tmpfile
echo "SKIP: $mytpl - Nothing to do."
fi
fi
echo
done
}
# loop over all files in templates subdir make replacements and generate
# a traget file.
function _removeGeneratedFiles(){
h2 "remove generated files..."
for mytpl in $( ls -1 ./templates/* )
do
h3 $mytpl
# fetch traget file from first line
target=$( head -1 $mytpl | grep "^# TARGET:" | cut -f 2- -d ":" | awk '{ print $1 }' )
if [ ! -z "$target" -a -f "../$target" ]; then
echo -n "REMOVING "
ls -l "../$target" || exit 2
rm -f "../$target" || exit 2
echo OK
else
echo SKIP: $target
fi
done
}
function _showContainers(){
local bLong=$1
h2 CONTAINERS
if [ -z "$bLong" ]; then
docker-compose ps
else
docker ps | grep $APP_NAME
fi
}
function _showContainers__(){
local line=
local bLong=$1
# typeset -i iCounter=0
h2 CONTAINERS
docker ps | grep $APP_NAME | while read line
do
# iCounter=$iCounter+1
if [ -z "$bLong" ]; then
echo $line | awk '{ print "NAME [" $12 "] " $7" "$8" "$9 }'
else
# echo $line | awk '{ print "IMAGE " $2 " ID " $1 ": " $7" "$8" "$9 " | PORTS: " $10 " " $11 }'
echo $line | awk '{ print "NAME [" $12 "]" }'
echo $line | awk '{ print " STATUS: " $7" "$8" "$9 }'
echo $line | awk '{ print " IMAGE : " $2 }'
echo $line | awk '{ print " ID : " $1 }'
echo $line | awk '{ print " PORTS : " $10 " " $11 }'
echo
fi
done
# test $iCounter -eq 0 && echo "NO CONTAINER IS RUNNING"
}
# a bit stupid ... i think I need to delete it.
function _showInfos(){
_showContainers long
h2 INFO
docker-compose top
echo
echo "In a web browser:"
echo -n " $frontendurl"
wget -O /dev/null -S $frontendurl 2>/dev/null && echo " ... OK, frontend is reachable"
echo
echo "In a local DB admin tool:"
echo " host : localhost"
echo " port : ${DB_PORT}"
echo " user : root"
echo " password: ${MYSQL_ROOT_PASS}"
echo
}
function _wait(){
echo -n "... press RETURN > "; read dummy
}
# ----------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------
action=$1
while true; do
echo
echo -e "\e[32m===== INITIALIZER FOR APP [$APP_NAME] ===== \e[0m"
if [ -z "$action" ]; then
_showContainers
h2 MENU
echo " i - init application; set permissions"
echo " t - generate files from templates"
echo " T - remove generated files"
echo
echo " m - more infos"
echo
echo " u - startup containers docker-compose up -d"
echo " s - shutdown containers docker-compose stop"
echo " r - remove containers docker-compose rm -f"
echo
echo " c - console (bash)"
echo
echo -n " select >"
read action
fi
case "$action" in
i)
# _gitinstall
_setWritepermissions
;;
t)
_generateFiles
;;
T)
_removeGeneratedFiles
rm -rf containers
;;
f)
_removeGeneratedFiles
_generateFiles
_wait
;;
m)
_showInfos
_wait
;;
u)
docker-compose up -d --remove-orphans
test ! -z "${APP_ONSTARTUP}" && sleep 2 && docker exec -it appmonitor-server /bin/bash -c "${APP_ONSTARTUP}"
echo "In a web browser:"
echo " $frontendurl"
echo
_wait
;;
s)
docker-compose stop
;;
r)
docker-compose rm -f
;;
c)
docker ps
echo -n "id or name >"
read dockerid
test -z "$dockerid" || docker exec -it $dockerid /bin/bash
;;
*) echo "ACTION [$action] NOT IMPLEMENTED."
esac
action=
done
# ----------------------------------------------------------------------
# ======================================================================
#
# settings for init.sh and base values for replacements in template files
# This script is sourced by init.sh ... this file is bash syntax
#
# ----------------------------------------------------------------------
# 2021-12-17 <axel.hahn@iml.unibe.ch>
# ======================================================================
APP_NAME=my_new_app
# web port 80 in container is seen on localhost as ...
APP_PORT=8001
APP_APT_PACKAGES="git unzip zip"
#APP_APACHE_MODULES="rewrite"
APP_APACHE_MODULES=""
APP_PHP_VERSION=8.1
# APP_PHP_MODULES="curl pdo_mysql mbstring xml zip xdebug"
APP_PHP_MODULES="curl mbstring xml zip xdebug"
# optional exec command after container was started with init.sh script
# APP_ONSTARTUP="php /var/www/${APP_NAME}/public_html/myservice.php"
APP_ONSTARTUP=""
# ----------------------------------------------------------------------
# add a container with database?
DB_ADD=false
# ----------------------------------------------------------------------
# for an optional database server
DB_PORT=13306
# ----- database settings
MYSQL_IMAGE=mariadb:10.5.9
MYSQL_RANDOM_ROOT_PASSWORD=0
MYSQL_ALLOW_EMPTY_PASSWORD=0
MYSQL_ROOT_PASS=12345678
MYSQL_USER=${APP_NAME}
MYSQL_PASS=mypassword
MYSQL_DB=${APP_NAME}
# ======================================================================
# ignore things below
# where to set acl where local user and web user in container
# can write simultanously
WRITABLEDIR=../public_html
# web service user in container
DOCKER_USER_UID=33
# document root inside web-server container
WEBROOT=/var/www/${APP_NAME}/public_html
CUTTER_NO_DATABASE="CUT-HERE-FOR-NO-DATABASE"
frontendurl=http://localhost:${APP_PORT}/
# ----------------------------------------------------------------------
# TARGET: docker/docker-compose.yml
#
# {{generator}}
#
# ======================================================================
#
# (1) see .env for set variables
# (2) run "docker-compose up" to startup
#
# ======================================================================
version: '3.9'
networks:
{{APP_NAME}}network:
services:
# ----- apache httpd + php
web-server:
build:
context: .
dockerfile: ./containers/web-server/Dockerfile
image: "php:{{APP_PHP_VERSION}}-apache"
container_name: '{{APP_NAME}}-server'
ports:
- '${APP_PORT}:80'
working_dir: ${WEBROOT}
volumes:
- ../:/var/www/${APP_NAME}
- ./containers/web-server/apache/sites-enabled:/etc/apache2/sites-enabled
- ./containers/web-server/php/extra-php-config.ini:/usr/local/etc/php/conf.d/extra-php-config.ini
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 10s
timeout: 3s
retries: 5
# start_period: 40s
networks:
- {{APP_NAME}}network
user: ${DOCKER_USER_UID}
# --- 8< --- {{CUTTER_NO_DATABASE}} --- 8< ---
depends_on:
- db-server
# ----- mariadb
db-server:
image: {{MYSQL_IMAGE}}
container_name: '${APP_NAME}-db'
# restart: always
ports:
- '${DB_PORT}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASS}'
MYSQL_USER: '${MYSQL_USER}'
MYSQL_PASSWORD: '${MYSQL_PASS}'
MYSQL_DATABASE: '${MYSQL_DB}'
volumes:
# - ./containers/db-server/db_data:/var/lib/mysql
- ./containers/db-server/mariadb/my.cnf:/etc/mysql/conf.d/my.cnf
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD
interval: 5s
retries: 5
networks:
- {{APP_NAME}}network
# TARGET: docker/.env
# ======================================================================
#
# {{generator}}
# values to be used in docker-composer.yml
#
# ======================================================================
# ----- application
APP_NAME={{APP_NAME}}
# uid of www-data in the docker container
DOCKER_USER_UID={{DOCKER_USER_UID}}
APP_PORT={{APP_PORT}}
WEBROOT={{WEBROOT}}
# --- 8< --- {{CUTTER_NO_DATABASE}} --- 8< ---
DB_PORT={{DB_PORT}}
# ----- database settings
MYSQL_RANDOM_ROOT_PASSWORD={{MYSQL_RANDOM_ROOT_PASSWORD}}
MYSQL_ALLOW_EMPTY_PASSWORD={{MYSQL_ALLOW_EMPTY_PASSWORD}}
MYSQL_ROOT_PASS={{MYSQL_ROOT_PASS}}
MYSQL_USER={{APP_NAME}}
MYSQL_PASS={{MYSQL_PASS}}
MYSQL_DB={{APP_NAME}}
# TARGET: docker/containers/web-server/php/extra-php-config.ini
;
; {{generator}}
;
[PHP]
; ----------------------------------------------------------------------
; XDEBUG STUFF BELOW
; ----------------------------------------------------------------------
;
; error_reporting=E_ALL
;
; [xdebug]
; xdebug.mode=develop,debug
; ; xdebug.client_host=localhost
; xdebug.start_with_request=yes
; ; xdebug.start_with_request=trigger
;
; xdebug.log=/tmp/xdebug.log
; xdebug.discover_client_host = 1
; ; xdebug.client_port=9003
; xdebug.idekey="netbeans-xdebug"
\ No newline at end of file
# TARGET: docker/containers/db-server/mariadb/my.cnf
[mysqld]
; collation-server = utf8mb4_unicode_ci
; character-set-server = utf8mb4
\ No newline at end of file
# Templates
## Rules
* in the first line must be a line `# TARGET: [name of target file]` to define the target file
* Placeholdrs have the syntax variable in double brackets, i.e. `{{VARNAME}}`
* variables to be replaced are those in docker/init.sh.cfg and `{{genrator}}`
# TARGET: docker/containers/web-server/apache/sites-enabled/vhost_app.conf
#
# {{generator}}
#
<VirtualHost *:80>
DocumentRoot {{WEBROOT}}
<Directory {{WEBROOT}}>
AllowOverride None
Order Allow,Deny
Allow from All
</Directory>
# example to prevent access with http
<Location "/no-access">
Require all denied
</Location>
</VirtualHost>
\ No newline at end of file
# TARGET: docker/containers/web-server/Dockerfile
#
# {{generator}}
#
# install packages
RUN apt-get update && apt-get install -y {{APP_APT_PACKAGES}}
# enable apache modules
RUN a2enmod {{APP_APACHE_MODULES}}
# install php packages
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
RUN install-php-extensions {{APP_PHP_MODULES}}
<?php
echo "<strong>OK</strong>, PHP is up an running";
\ No newline at end of file
# PHP App Template #
Free software and Open Source from University of Bern :: IML - Institute of Medical Education
- - -
## About this template ##
This template folder brings up a docker container with a PHP 8.1 dev environment with Apache httpd2 + mod_php.
You also can add 2nd container with a Mariadb instance.
The subdir ```./public_html/``` will be mounted as webroot that you can edit files locally which are visible inside the container too.
## Requirements ##
* Docker Non-root installation - see <https://docs.docker.com/engine/security/rootless/>
## How to use this template ##
### Create a new project folder ###
Copy folder to a new name: ```cp -r template-php my-new-php-app; cd my-new-php-app``` and remove the ```.git``` folder in it ```rm -rf .git```
The initial file structure looks like this:
```txt
.
├── docker # Docker data
│ ├── init.sh << shellscript for initialization
│ ├── init.sh.cfg << config file
│ └── templates << folder with templates
│ ├── docker-compose.yml
│ ├── dot_env
│ ├── extra-php-config.ini
│ ├── my.cnf
│ ├── readme.md
│ ├── vhost_app.conf
│ └── web-server-Dockerfile
├── public_html # your webroot for your data
│ └── index.php
└── readme.md
```
### Edit variables and files ###
* edit ```./docker/init.sh.cfg``` ... and edit
* ```APP_NAME=my_new_app```
* optional: set a new port ```APP_PORT=8001```
* set APP_* variables for packages to install or PHP version
* set DB_ADD to true or false to say if a database container is needed
* If a database is needed then set DB_PORT and MYSQL_* variables
* edit ```./docker/templates/vhost_app.conf``` to describe apache vhost config
* edit php settings in ```./docker/templates/extra-php.ini```
* edit mysql settings in ```./docker/templates/my.cnf```
### First start ###
* start init script in the docker folder: ```./docker/init.sh```
* use "i" for init ... it sets an ACL on the ./public_html/ subdir to allow write access for your current user and the apache user in the docker container
* use "t" to generate config files from templates with the settings from ./docker/init.sh.cfg
* use "u" to bring up the container (OR run ```docker-compose up -d``` )
### Edit files ###
* If the container was started you can ...
* open in your browser http://localhost:8001 to access ```./public_html/```
* edit files with the IDE of your choice
### Remarks ###
You can start ./docker/init.sh with a single letter in the interactive menu too, i.e. ```./docker/init.sh u``` to bring up the docker instance.
If you created the config files from templates you can repeat the creation ```./docker/init.sh t```. Before applying a change you should shutdown your docker instance.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment