diff --git a/bin/quickstart.sh b/bin/quickstart.sh index 3ae750bf..5a876c26 100755 --- a/bin/quickstart.sh +++ b/bin/quickstart.sh @@ -1,130 +1,140 @@ #!/bin/bash set -e function die() { echo "$1" exit 1 } -rpm -qv composer >/dev/null 2>&1 || \ - test ! -z "$(which composer 2>/dev/null)" || \ - die "Is composer installed?" - rpm -qv docker-compose >/dev/null 2>&1 || \ test ! -z "$(which docker-compose 2>/dev/null)" || \ die "Is docker-compose installed?" -rpm -qv npm >/dev/null 2>&1 || \ - test ! -z "$(which npm 2>/dev/null)" || \ - die "Is npm installed?" - -rpm -qv php >/dev/null 2>&1 || \ - test ! -z "$(which php 2>/dev/null)" || \ - die "Is php installed?" - -rpm -qv php-ldap >/dev/null 2>&1 || \ - test ! -z "$(php --ini | grep ldap)" || \ - die "Is php-ldap installed?" - -rpm -qv php-mysqlnd >/dev/null 2>&1 || \ - test ! -z "$(php --ini | grep mysql)" || \ - die "Is php-mysqlnd installed?" - -test ! -z "$(php --modules | grep swoole)" || \ - die "Is swoole installed?" - test ! -z "$(grep 'systemd.unified_cgroup_hierarchy=0' /proc/cmdline)" || \ die "systemd containers only work with cgroupv1 (use 'grubby --update-kernel=ALL --args=\"systemd.unified_cgroup_hierarchy=0\"' and a reboot to fix)" base_dir=$(dirname $(dirname $0)) # Always reset .env with .env.example cp src/.env.example src/.env if [ -f "src/env.local" ]; then # Ensure there's a line ending echo "" >> src/.env cat src/env.local >> src/.env fi docker pull docker.io/kolab/centos7:latest docker-compose down --remove-orphans +src/artisan octane:stop >/dev/null 2>&1 || : +src/artisan horizon:terminate >/dev/null 2>&1 || : + docker-compose build coturn kolab mariadb meet pdns-sql proxy redis nginx bin/regen-certs docker-compose up -d coturn kolab mariadb meet pdns-sql proxy redis # Workaround until we have docker-compose --wait (https://github.com/docker/compose/pull/8777) function wait_for_container { container_id="$1" container_name="$(docker inspect "${container_id}" --format '{{ .Name }}')" echo "Waiting for container: ${container_name} [${container_id}]" waiting_done="false" while [[ "${waiting_done}" != "true" ]]; do container_state="$(docker inspect "${container_id}" --format '{{ .State.Status }}')" if [[ "${container_state}" == "running" ]]; then health_status="$(docker inspect "${container_id}" --format '{{ .State.Health.Status }}')" echo "${container_name}: container_state=${container_state}, health_status=${health_status}" if [[ ${health_status} == "healthy" ]]; then waiting_done="true" fi else echo "${container_name}: container_state=${container_state}" waiting_done="true" fi sleep 1; done; } # Ensure the containers we depend on are fully started wait_for_container 'kolab' wait_for_container 'kolab-redis' +if [ "$1" == "--nodev" ]; then + echo "starting everything in containers" + docker-compose build swoole webapp + docker-compose up -d webapp nginx + wait_for_container 'kolab-webapp' + exit 0 +fi +echo "Starting the development environment" + +rpm -qv composer >/dev/null 2>&1 || \ + test ! -z "$(which composer 2>/dev/null)" || \ + die "Is composer installed?" + +rpm -qv npm >/dev/null 2>&1 || \ + test ! -z "$(which npm 2>/dev/null)" || \ + die "Is npm installed?" + +rpm -qv php >/dev/null 2>&1 || \ + test ! -z "$(which php 2>/dev/null)" || \ + die "Is php installed?" + +rpm -qv php-ldap >/dev/null 2>&1 || \ + test ! -z "$(php --ini | grep ldap)" || \ + die "Is php-ldap installed?" + +rpm -qv php-mysqlnd >/dev/null 2>&1 || \ + test ! -z "$(php --ini | grep mysql)" || \ + die "Is php-mysqlnd installed?" + +test ! -z "$(php --modules | grep swoole)" || \ + die "Is swoole installed?" + pushd ${base_dir}/src/ rm -rf vendor/ composer.lock php -dmemory_limit=-1 $(which composer) install npm install find bootstrap/cache/ -type f ! -name ".gitignore" -delete ./artisan key:generate ./artisan clear-compiled ./artisan cache:clear ./artisan horizon:install if [ ! -f storage/oauth-public.key -o ! -f storage/oauth-private.key ]; then ./artisan passport:keys --force fi cat >> .env << EOF PASSPORT_PRIVATE_KEY="$(cat storage/oauth-private.key)" PASSPORT_PUBLIC_KEY="$(cat storage/oauth-public.key)" EOF if rpm -qv chromium 2>/dev/null; then chver=$(rpmquery --queryformat="%{VERSION}" chromium | awk -F'.' '{print $1}') ./artisan dusk:chrome-driver ${chver} fi if [ ! -f 'resources/countries.php' ]; then ./artisan data:countries fi npm run dev popd docker-compose up -d nginx pushd ${base_dir}/src/ rm -rf database/database.sqlite ./artisan db:ping --wait php -dmemory_limit=512M ./artisan migrate:refresh --seed ./artisan data:import || : -./artisan octane:stop >/dev/null 2>&1 || : nohup ./artisan octane:start --host=$(grep OCTANE_HTTP_HOST .env | tail -n1 | sed "s/OCTANE_HTTP_HOST=//") > octane.out & -./artisan horizon:terminate >/dev/null 2>&1 || : nohup ./artisan horizon > horizon.out & popd diff --git a/docker-compose.yml b/docker-compose.yml index 68e93267..a1f53e12 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,217 +1,233 @@ version: '3' services: coturn: build: context: ./docker/coturn/ container_name: kolab-coturn healthcheck: interval: 10s test: "kill -0 $$(cat /tmp/turnserver.pid)" timeout: 5s retries: 30 environment: - TURN_PUBLIC_IP=${COTURN_PUBLIC_IP} - TURN_LISTEN_PORT=3478 - TURN_STATIC_SECRET==${COTURN_STATIC_SECRET} hostname: sturn.mgmt.com image: kolab-coturn network_mode: host restart: on-failure tty: true kolab: build: context: ./docker/kolab/ container_name: kolab depends_on: mariadb: condition: service_healthy extra_hosts: - "kolab.mgmt.com:127.0.0.1" environment: - DB_HOST=${DB_HOST} - DB_ROOT_PASSWORD=Welcome2KolabSystems - DB_HKCCP_DATABASE=${DB_DATABASE} - DB_HKCCP_USERNAME=${DB_USERNAME} - DB_HKCCP_PASSWORD=${DB_PASSWORD} - DB_KOLAB_DATABASE=kolab - DB_KOLAB_USERNAME=kolab - DB_KOLAB_PASSWORD=Welcome2KolabSystems - DB_RC_USERNAME=roundcube - DB_RC_PASSWORD=Welcome2KolabSystems - IMAP_HOST=127.0.0.1 - IMAP_PORT=11993 - MAIL_HOST=127.0.0.1 - MAIL_PORT=10587 healthcheck: interval: 10s test: test -f /tmp/kolab-init.done timeout: 5s retries: 30 hostname: kolab.mgmt.com image: kolab network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./ext/:/src/:ro - /etc/letsencrypt/:/etc/letsencrypt/:ro - ./docker/certs/ca.cert:/etc/pki/tls/certs/ca.cert:ro - ./docker/certs/ca.cert:/etc/pki/ca-trust/source/anchors/ca.cert:ro - ./docker/certs/kolab.hosted.com.cert:/etc/pki/tls/certs/kolab.hosted.com.cert - ./docker/certs/kolab.hosted.com.key:/etc/pki/tls/certs/kolab.hosted.com.key - ./docker/certs/kolab.mgmt.com.cert:/etc/pki/tls/certs/kolab.mgmt.com.cert - ./docker/certs/kolab.mgmt.com.key:/etc/pki/tls/certs/kolab.mgmt.com.key - ./docker/kolab/utils:/root/utils:ro - ./src/.env:/.dockerenv:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro mariadb: container_name: kolab-mariadb environment: MYSQL_ROOT_PASSWORD: Welcome2KolabSystems TZ: "+02:00" healthcheck: interval: 10s test: test -e /var/run/mysqld/mysqld.sock timeout: 5s retries: 30 image: mariadb network_mode: host nginx: build: context: ./docker/nginx/ args: APP_WEBSITE_DOMAIN: ${APP_WEBSITE_DOMAIN:?err} depends_on: kolab: condition: service_healthy healthcheck: interval: 10s test: "kill -0 $$(cat /run/nginx.pid)" timeout: 5s retries: 30 container_name: kolab-nginx hostname: nginx.hosted.com image: kolab-nginx network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./docker/certs/imap.hosted.com.cert:/etc/pki/tls/certs/imap.hosted.com.cert - ./docker/certs/imap.hosted.com.key:/etc/pki/tls/private/imap.hosted.com.key pdns-sql: build: context: ./docker/pdns-sql/ container_name: kolab-pdns-sql depends_on: mariadb: condition: service_healthy hostname: pdns-sql image: apheleia/kolab-pdns-sql network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro proxy: build: context: ./docker/proxy/ args: APP_WEBSITE_DOMAIN: ${APP_WEBSITE_DOMAIN:?err} SSL_CERTIFICATE: /etc/letsencrypt/live/${APP_WEBSITE_DOMAIN:?err}/fullchain.pem SSL_CERTIFICATE_KEY: /etc/letsencrypt/live/${APP_WEBSITE_DOMAIN:?err}/privkey.pem healthcheck: interval: 10s test: "kill -0 $$(cat /run/nginx.pid)" timeout: 5s retries: 30 container_name: kolab-proxy hostname: ${APP_WEBSITE_DOMAIN:?err} image: kolab-proxy network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./docker/certs/:/etc/certs/:ro - /etc/letsencrypt/:/etc/letsencrypt/:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro redis: build: context: ./docker/redis/ healthcheck: interval: 10s test: "redis-cli ping || exit 1" timeout: 5s retries: 30 container_name: kolab-redis hostname: redis image: redis network_mode: host volumes: - ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro swoole: build: context: ./docker/swoole/ container_name: kolab-swoole image: apheleia/swoole:4.8.x + webapp: + build: + context: ./docker/webapp/ + container_name: kolab-webapp + image: kolab-webapp + healthcheck: + interval: 10s + test: "/src/kolabsrc/artisan octane:status || exit 1" + timeout: 5s + retries: 30 + depends_on: + kolab: + condition: service_healthy + network_mode: host + volumes: + - ./src:/src/kolabsrc.orig:ro worker: build: context: ./docker/worker/ container_name: kolab-worker depends_on: - kolab hostname: worker image: kolab-worker network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./src:/home/worker/src.orig:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro meet: build: context: ./docker/meet/ healthcheck: interval: 10s test: "curl --insecure -H 'X-AUTH-TOKEN: ${MEET_SERVER_TOKEN}' --fail https://localhost:12443/meetmedia/api/health || exit 1" timeout: 5s retries: 30 environment: - WEBRTC_LISTEN_IP=${MEET_WEBRTC_LISTEN_IP:?err} - PUBLIC_DOMAIN=${MEET_PUBLIC_DOMAIN:?err} - LISTENING_HOST=0.0.0.0 - LISTENING_PORT=12443 - TURN_SERVER=${MEET_TURN_SERVER} - TURN_STATIC_SECRET=${COTURN_STATIC_SECRET} - AUTH_TOKEN=${MEET_SERVER_TOKEN:?err} - WEBHOOK_TOKEN=${MEET_WEBHOOK_TOKEN:?err} - WEBHOOK_URL=${APP_PUBLIC_URL:?err}/api/webhooks/meet - SSL_CERT=/etc/pki/tls/certs/meet.${APP_WEBSITE_DOMAIN:?err}.cert - SSL_KEY=/etc/pki/tls/private/meet.${APP_WEBSITE_DOMAIN:?err}.key network_mode: host container_name: kolab-meet image: kolab-meet volumes: - ./meet/server:/src/meet/:ro - ./docker/meet/build/node_modules:/root/node_modules - ./docker/certs/meet.${APP_WEBSITE_DOMAIN}.cert:/etc/pki/tls/certs/meet.${APP_WEBSITE_DOMAIN}.cert - ./docker/certs/meet.${APP_WEBSITE_DOMAIN}.key:/etc/pki/tls/private/meet.${APP_WEBSITE_DOMAIN}.key diff --git a/docker/webapp/Dockerfile b/docker/webapp/Dockerfile new file mode 100644 index 00000000..4b9d4747 --- /dev/null +++ b/docker/webapp/Dockerfile @@ -0,0 +1,13 @@ +FROM apheleia/swoole:4.8.x + +MAINTAINER Jeroen van Meeuwen + +USER root + +RUN dnf -y install findutils + +EXPOSE 8000 + +COPY init.sh /init.sh + +CMD [ "/init.sh" ] diff --git a/docker/webapp/init.sh b/docker/webapp/init.sh new file mode 100755 index 00000000..e2cbd630 --- /dev/null +++ b/docker/webapp/init.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -e +cp -a /src/kolabsrc.orig /src/kolabsrc +cd /src/kolabsrc + +rm -rf vendor/ composer.lock .npm storage/framework +mkdir -p storage/framework/{sessions,views,cache} + +php -dmemory_limit=-1 $(command -v composer) install +npm install +find bootstrap/cache/ -type f ! -name ".gitignore" -delete +./artisan key:generate +./artisan storage:link +./artisan clear-compiled +./artisan cache:clear +./artisan horizon:install + +if [ ! -f storage/oauth-public.key -o ! -f storage/oauth-private.key ]; then + ./artisan passport:keys --force +fi + +cat >> .env << EOF +PASSPORT_PRIVATE_KEY="$(cat storage/oauth-private.key)" +PASSPORT_PUBLIC_KEY="$(cat storage/oauth-public.key)" +EOF + +if rpm -qv chromium 2>/dev/null; then + chver=$(rpmquery --queryformat="%{VERSION}" chromium | awk -F'.' '{print $1}') + ./artisan dusk:chrome-driver ${chver} +fi + +if [ ! -f 'resources/countries.php' ]; then + ./artisan data:countries +fi + +npm run dev + +rm -rf database/database.sqlite +./artisan db:ping --wait +php -dmemory_limit=512M ./artisan migrate:refresh --seed +./artisan data:import || : +nohup ./artisan horizon >/dev/null 2>&1 & +./artisan octane:start --host=$(grep OCTANE_HTTP_HOST .env | tail -n1 | sed "s/OCTANE_HTTP_HOST=//")