├── .travis.yml ├── CHANGELOG.md ├── Dockerfile_nginx-72 ├── LICENSE ├── README.md ├── VERSION ├── build.sh ├── docker-compose.yml ├── docker-entrypoint.d ├── 01timezone ├── 10phpfpm ├── 20glpiplugins └── 21glpifiles ├── docker-entrypoint.sh ├── publish.sh ├── root ├── etc │ ├── nginx │ │ └── nginx.conf │ ├── php-fpm.d │ │ ├── custom.ini.j2 │ │ └── nginx.conf.j2 │ └── supervisord.conf ├── opt │ └── scripts │ │ └── cronwrapper.py └── usr │ └── local │ └── bin │ └── cronwrapper.py ├── tests.sh └── tests.yml /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: bash 3 | sudo: required 4 | 5 | # Tell Travis to start Docker when it brings up an environment. 6 | services: 7 | - docker 8 | 9 | env: 10 | global: 11 | - DOCKER_REPO=turgon37/glpi 12 | - secure: 'C/95oCVHTBhQklEiZpmHDDEOkRHfHmRDTaXb7XfBtLJQPmx92MIEpuiaRra1jsuy2ssQV8yaCrEXOajbkfcNWwgO4iR+PsQOmak0VfMuH29t+8c6siq9S8dBhlaT/X0KR3jDvuUUyJfd+zY4MFrN6J4p4mELsCq5GM15fTQhVxa9wi0q17Lno0OCkYprtThw6a+rw2VvuqSGDLcBvPVxAAalZJtlgn9+h1kbnlju7CnyDOng5Csgb/16E1e7gEgO/uL7A5C+bAgJbEkA6PPwu8hec6IB2Q7DZ55WAortcGUTN9OiNEpAFM5AEXel061iA8Y53H7S2DJKLYvvEo5enk2C4h8t1Nott5g65joTbRG/3gjO4sR7cSM0A156tM9mkzqIOzeeGZXgz1+Ktl/4IPrP80kZfxqlQ1MMzlAxa9Rwq/Ne8ovjRzh3J//Udm80QmjvhYWXsQQ9gdaKYTgemp8Chld3ZRnyHgJcwwIOe39/ZjAWmuUOvkJiNxse4jySFwQrz3GbblpGBL6QAYb6VrXbo+Ddb6nhWKflXzaLWtH7VRMqhIJu+OKk336kqpr8vkMJMmT5l4e7NjjPGUgmURnxdj3rUxTASljZmUYcDYvDrOX6924BSzaYsMLwOcPOwzLXEGz85d44S+OiL8h77B39fVNBuDRFbvzPqh18Zyk=' 13 | - secure: 'lms0WcFqVGGse7M0YW0zGgLtlvlCRL0fPMls0Ayy8tRfNuDWyVPzgS7u9jmdeb/L/NMxiSOnHgEg5DMyWovcyR+l65A3tL2vKkp0hG6bV8vB48QZH3/8Cz1PQ4iEVwQaCFU751M+lZzJobK9H40d0ecou1q1f8yyBwpf3YK6J/Y2Haii0Fu1j61Mjt+AtsXfQWXYfYKbCxx/AZn9gNwW7PEd6r9KTgQBLMXVRDtXUeqFrRNH6EeUxeWvs1Ik1dHTuPh+VF06UfV48b3hLGi9CFjdOSqtpt6e3BM0fVLCL/IoLonmcxillw2ds0hUWG4e8snyIUrd/JcqtyK3nmJ7/MA6q8+zCqYNMMTPjmt6sNUzyXWEUrvoZbgZjEshE/8cMFlyfoK3wRvbv6USFNk22SWXGCe7nW6x7DJLCN8Hke2y5UIbVBR/IFcM1zjXvX7HHVW8+F0E0+mwXwnxlsi9PoszZo3tbZv6kznr3JhiHT7HbQm4oKZA9muh432i4uMrzqsvhGPSmE+ebVSRObN9GApjp5BX1H9HSyA8kgnfTpNzbCooBsiK0OEKBBtI1NgSRw0oJdralaEWfaMjomM2dAhoR5G0/0U9a9inOyZiXcIi8GUmuuEKcskQRrVhbqBHTB2XC3o5/wl7k3K1sfvoB7JBwrftXYQnxCoghFwCkJM=' 14 | matrix: 15 | # Provide a list of GLPI version to build 16 | - GLPI_VERSION=9.5.5 IMAGE_VARIANT=nginx-72 UPDATE_README=1 UPDATE_LATEST=1 17 | - GLPI_VERSION=9.5.4 IMAGE_VARIANT=nginx-72 18 | 19 | before_install: 20 | - sudo apt update 21 | - sudo apt install -y shellcheck 22 | 23 | script: 24 | # 25 | ## Build 26 | # 27 | - ./build.sh 28 | 29 | # 30 | ## Run tests 31 | # 32 | - ./tests.sh && touch _test_ok 33 | 34 | # 35 | ## Publish 36 | # 37 | - '[ "$TRAVIS_PULL_REQUEST" == "false" ] || exit 0' 38 | - '[ "$TRAVIS_SECURE_ENV_VARS" == "true" -a -f _test_ok ] && ./publish.sh' 39 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Items starting with `DEPRECATE` are important deprecation notices. 4 | 5 | ## 3.3.0 (2021-03-06) 6 | 7 | + Move cronwrapper from /opt/scripts to /usr/local/bin folder 8 | + DEPRECATE /opt/scripts/cronwrapper.py in favor to /usr/local/bin/cronwrapper.py 9 | 10 | ## 3.2.3 (2020-07-09) 11 | 12 | + Add bz2, intl, zip extensions for GLPI 9.5 13 | 14 | ## 3.2.2 (2020-05-10) 15 | 16 | + Fix docker HEALTHCHECK command 17 | 18 | ### Build process 19 | 20 | + Improve publish script and edit pushed tags 21 | 22 | 23 | ## 3.2.1 (2020-05-10) 24 | 25 | ### Build process 26 | 27 | + Add shellcheck tests 28 | + Add Timezone test 29 | 30 | 31 | ## 3.2.0 (2020-05-08) 32 | 33 | + Update glpi to 9.4.5 in CI 34 | + Move supervisord pidfile into /run 35 | + Update Docker healthcheck to use FPM ping endpoint 36 | + Make PHP configuration dynamic using environment on container runtime 37 | + Move php fpm configuration during entrypoint phase 38 | + Split entrypoint tasks into separated files 39 | + Update cronwrapper python version + remove empty line newline 40 | 41 | ### Build process 42 | 43 | + Add PHP nginx-7.2 variant 44 | * Rewrite Dockerfile-56 composer stage 45 | 46 | 47 | ## 3.1.0 (2019-08-02) 48 | 49 | + Add support for zipped plugins 50 | 51 | 52 | ## 3.0.3 (2019-07-10) 53 | 54 | ### Image 55 | 56 | + Configure TZ in php.ini (thanks @Wolvverine) 57 | 58 | 59 | ## 3.0.2 (2019-06-22) 60 | 61 | ### Build process 62 | 63 | + Add 'latest' tag on image version 64 | 65 | 66 | ## 3.0.1 (2019-05-21) 67 | 68 | ### Build process 69 | 70 | + Fix empty SERVER_NAME php value when localhost is using 71 | + Fix issue #27 : related to applicative user uid's change 72 | + Fix #28 Add missing php packages and libs 73 | 74 | 75 | ## 3.0.0 (2019-03-10) 76 | 77 | ### Build process 78 | 79 | - Use the official PHP image as FROM 80 | - Separate image variant into dedicated dockerfiles 81 | 82 | ### Image 83 | 84 | - Replace start.sh by entrypoint 85 | - Remove cron job from supervisord 86 | - Add /opt/scripts/cronwrapper.py to format cron output 87 | - Remove support of GLPI_PLUGINS to install plugins, you must use GLPI_INSTALL_PLUGINS 88 | 89 | 90 | ## 2.4.2 (2018-12-16) 91 | 92 | ### Image 93 | 94 | - Handle Timezone configuration (thanks @Wolvverine) #21 95 | 96 | 97 | ## 2.4.1 (2018-11-03) 98 | 99 | ### Image 100 | 101 | - Clean composer local cache to free 20M of space 102 | 103 | 104 | ## 2.4.0 (2018-11-03) 105 | 106 | ### Image 107 | 108 | + Add ping and fping for https://github.com/pluginsGLPI/addressing plugin #18 109 | + Add apereo/phpCAS library to fix GLPI requirements #19 (https://github.com/apereo/phpCAS) 110 | + Upgrade GLPI to 9.3 #15 111 | 112 | See this issue to upgrade from 9.2* to 9.3* : https://github.com/glpi-project/glpi/issues/4311 113 | 114 | ### Deprecation 115 | 116 | - DEPRECATE environment variable GLPI_PLUGINS in favor of GLPI_INSTALL_PLUGINS (will be removed in 3.0) 117 | 118 | 119 | ## 2.3.0 (2018-05-29) 120 | 121 | ### Image 122 | 123 | + Add php5-soap #13 124 | + Add graphviz #12 125 | + Fix cronjob #11 126 | 127 | 128 | ## 2.2.0 (2018-04-02) 129 | 130 | ### Image 131 | 132 | + Add environment variable to control internal cronjob : GLPI_ENABLE_CRONJOB, default to enabled to keep backward compatiblity 133 | 134 | ### Deprecation 135 | 136 | - DEPRECATE internal cronjobs handled by supervisor, it will be removed in 3.0 release. 137 | 138 | 139 | ## 2.1.0 (2018-02-04) 140 | 141 | ### Image 142 | 143 | + Add docker healthcheck 144 | 145 | 146 | ## 2.0.0 (2018-02-03) 147 | 148 | ### Image 149 | 150 | + Upgrade to Alpine 3.7 151 | + Add GLPI_CHMOD_PATHS_FILES [#2](https://github.com/Turgon37/docker-glpi/issues/2) 152 | + Add support for .bz2 plugin archives 153 | + Add standard labels in docker image 154 | - Fix a bug when the image cannot be started if a plugin installation fail 155 | 156 | ### GLPI 157 | 158 | * Upgrade to 9.2.1 [#1](https://github.com/Turgon37/docker-glpi/issues/1) 159 | 160 | ### Deprecation 161 | 162 | - Deprecate `GLPI_PLUGINS` environment variable in favor of GLPI_INSTALL_PLUGINS. GLPI_INSTALL_PLUGINS is comma separated and follow the same pattern as GLPI_PLUGINS. 163 | 164 | 165 | ## 1.0.0 (2017-08-07) 166 | 167 | First release 168 | -------------------------------------------------------------------------------- /Dockerfile_nginx-72: -------------------------------------------------------------------------------- 1 | # First stage : download glpi + build it 2 | FROM composer:latest as build_glpi 3 | 4 | ARG GLPI_VERSION 5 | ARG GLPI_PATHS_ROOT=/var/www 6 | 7 | RUN mkdir -p "${GLPI_PATHS_ROOT}" 8 | RUN curl -v --fail -o glpi.tgz -L "https://github.com/glpi-project/glpi/releases/download/${GLPI_VERSION}/glpi-${GLPI_VERSION}.tgz" \ 9 | && tar -xzf glpi.tgz --strip 1 --directory ${GLPI_PATHS_ROOT} 10 | 11 | WORKDIR "${GLPI_PATHS_ROOT}" 12 | 13 | RUN curl --silent --show-error --fail --remote-name-all \ 14 | https://raw.githubusercontent.com/glpi-project/glpi/${GLPI_VERSION}/composer.json \ 15 | https://raw.githubusercontent.com/glpi-project/glpi/${GLPI_VERSION}/composer.lock \ 16 | && COMPOSER_HOME=/tmp/composer composer require \ 17 | --apcu-autoloader \ 18 | --classmap-authoritative \ 19 | --ignore-platform-reqs \ 20 | --no-interaction \ 21 | --no-progress \ 22 | --optimize-autoloader \ 23 | --prefer-dist \ 24 | --update-no-dev \ 25 | --working-dir ${GLPI_PATHS_ROOT} \ 26 | apereo/phpcas \ 27 | && rm -fv composer.json 28 | 29 | # Second stage : build final image 30 | FROM php:7.2-fpm-alpine3.11 31 | 32 | LABEL maintainer='Pierre GINDRAUD ' 33 | 34 | ARG GLPI_VERSION 35 | 36 | ENV GLPI_VERSION "${GLPI_VERSION}" 37 | ENV GLPI_PATHS_ROOT /var/www 38 | ENV GLPI_PATHS_PLUGINS /var/www/plugins 39 | ENV GLPI_REMOVE_INSTALLER no 40 | ENV GLPI_CHMOD_PATHS_FILES no 41 | ENV GLPI_INSTALL_PLUGINS '' 42 | 43 | ENV PHP_MEMORY_LIMIT 64M 44 | 45 | ENV PHPFPM_PM dynamic 46 | ENV PHPFPM_PM_MAX_CHILDREN 5 47 | ENV PHPFPM_PM_START_SERVERS 2 48 | ENV PHPFPM_PM_MIN_SPARE_SERVERS 1 49 | ENV PHPFPM_PM_MAX_SPARE_SERVERS 3 50 | ENV PHPFPM_PM_PROCESS_IDLE_TIMEOUT 10s 51 | ENV PHPFPM_PM_MAX_REQUEST 500 52 | 53 | # Install dependencies 54 | RUN set -ex; \ 55 | apk --no-cache add \ 56 | curl \ 57 | nginx \ 58 | fping \ 59 | graphviz \ 60 | iputils \ 61 | net-snmp-libs \ 62 | py3-jinja2 \ 63 | supervisor \ 64 | tar \ 65 | tzdata \ 66 | ; \ 67 | pip3 install \ 68 | j2cli \ 69 | ; \ 70 | apk add --no-cache --virtual .build-deps \ 71 | $PHPIZE_DEPS \ 72 | autoconf \ 73 | bzip2-dev \ 74 | coreutils \ 75 | curl-dev \ 76 | freetype-dev \ 77 | icu-dev \ 78 | imap-dev \ 79 | libevent-dev \ 80 | libjpeg-turbo-dev \ 81 | libmcrypt-dev \ 82 | libpng-dev \ 83 | libxml2-dev \ 84 | net-snmp-dev \ 85 | openldap-dev \ 86 | pcre-dev \ 87 | imagemagick-dev \ 88 | ; \ 89 | docker-php-source extract ; \ 90 | docker-php-ext-configure gd --with-freetype-dir=/usr --with-png-dir=/usr --with-jpeg-dir=/usr; \ 91 | docker-php-ext-configure ldap ; \ 92 | docker-php-ext-install \ 93 | bz2 \ 94 | exif \ 95 | gd \ 96 | imap \ 97 | intl \ 98 | ldap \ 99 | mysqli \ 100 | opcache \ 101 | snmp \ 102 | soap \ 103 | xmlrpc \ 104 | zip \ 105 | ; \ 106 | pecl install apcu && docker-php-ext-enable apcu ; \ 107 | docker-php-source delete ; \ 108 | runDeps="$( \ 109 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 110 | | tr ',' '\n' \ 111 | | sort -u \ 112 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 113 | )"; \ 114 | apk add --virtual .nextcloud-phpext-rundeps $runDeps; \ 115 | apk del .build-deps ; \ 116 | mkdir -p /run/nginx ; \ 117 | find "${GLPI_PATHS_ROOT}" -mindepth 1 -maxdepth 1 -not -name '.*' -and -not -name '..' | xargs rm -rfv 118 | 119 | # Copy glpi build 120 | COPY --from=build_glpi --chown=www-data:www-data ${GLPI_PATHS_ROOT} ${GLPI_PATHS_ROOT} 121 | 122 | # Add some configurations files 123 | COPY root/ / 124 | COPY /docker-entrypoint.sh / 125 | COPY /docker-entrypoint.d/* /docker-entrypoint.d/ 126 | 127 | RUN chmod -R +x /docker-entrypoint.d/ /usr/local/bin/cronwrapper.py \ 128 | && chmod -R g=rX,o=--- /var/www/* \ 129 | && addgroup nginx www-data 130 | 131 | EXPOSE 80/tcp 132 | VOLUME ["/var/www/files", "/var/www/config"] 133 | WORKDIR "${GLPI_PATHS_ROOT}" 134 | 135 | HEALTHCHECK --interval=5s --timeout=3s --retries=3 \ 136 | CMD curl --silent http://127.0.0.1:80/fpm-ping | grep -q pong || exit 1 137 | 138 | ENTRYPOINT ["/docker-entrypoint.sh"] 139 | CMD ["/usr/bin/supervisord", "--configuration", "/etc/supervisord.conf"] 140 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Pierre GINDRAUD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker GLPI 2 | 3 | [![Build Status](https://travis-ci.com/Turgon37/docker-glpi.svg?branch=master)](https://travis-ci.com/Turgon37/docker-glpi) 4 | [![](https://images.microbadger.com/badges/image/turgon37/glpi.svg)](https://microbadger.com/images/turgon37/glpi "Get your own image badge on microbadger.com") 5 | [![](https://images.microbadger.com/badges/version/turgon37/glpi.svg)](https://microbadger.com/images/turgon37/glpi "Get your own version badge on microbadger.com") 6 | 7 | This images contains an instance of GLPI web application served by nginx and php5-fpm on port 80 8 | 9 | :warning: Take care of the [changelogs](CHANGELOG.md) because some breaking changes may happen between versions. 10 | 11 | ## Supported tags, image variants and respective Dockerfile links 12 | 13 | * nginx and PHP7.2 embedded [Dockerfile](https://github.com/Turgon37/docker-glpi/blob/master/Dockerfile_nginx-72) 14 | 15 | * `nginx-72-9.5.5-latest`, `nginx-72-latest` 16 | * `nginx-72-9.5.4-latest`, `nginx-72-latest` 17 | 18 | ## Docker Informations 19 | 20 | * This image expose the following ports 21 | 22 | | Port | Usage | 23 | | -------------- | -------------------- | 24 | | 80/tcp | HTTP web application | 25 | 26 | [see https part to known about ssl](#https---ssl-encryption) 27 | 28 | * This image takes theses environnements variables as parameters 29 | 30 | | Environment | Type | Usage | 31 | | ------------------------------ | ---------------- | ------------------------------------------------------------------------- | 32 | | TZ | String | Contains the timezone | 33 | | GLPI_REMOVE_INSTALLER | Boolean (yes/no) | Set to yes if it's not the first installation of glpi | 34 | | GLPI_CHMOD_PATHS_FILES | Boolean (yes/no) | Set to yes to apply chmod/chown on /var/www/files (useful for host mount) | 35 | | GLPI_INSTALL_PLUGINS | String | Comma separated list of plugins to install (see below) | 36 | | PHP_MEMORY_LIMIT | String | see PHP memory_limit configuration | 37 | | PHPFPM_PM | String | see PHPFPM pm configuration | 38 | | PHPFPM_PM_MAX_CHILDREN | Integer | see PHPFPM pm.max_children configuration | 39 | | PHPFPM_PM_START_SERVERS | Integer | see PHPFPM pm.start_servers configuration | 40 | | PHPFPM_PM_MIN_SPARE_SERVERS | Integer | see PHPFPM pm.min_spare_servers configuration | 41 | | PHPFPM_PM_MAX_SPARE_SERVERS | Integer | see PHPFPM pm.max_spare_servers configuration | 42 | | PHPFPM_PM_PROCESS_IDLE_TIMEOUT | Mixed | see PHPFPM pm.process_idle_timeout configuration | 43 | | PHPFPM_PM_MAX_REQUEST | Integer | see PHPFPM pm.max_request configuration | 44 | 45 | The GLPI_INSTALL_PLUGINS variable must contains the list of plugins to install (download and extract) before starting glpi. 46 | This environment variable is a comma separated list of plugins definitions. Each plugin definition must be like this "PLUGINNAME|URL". 47 | The PLUGINNAME is the name of the first folder in plugin archive and will be the glpi's name of the plugin. 48 | The URL is the full URL from which to download the plugin. This url can contains some compressed file extensions, in some case the installer script will not be able to extract it, so you can create an issue with specifying the unhandled file extension. 49 | These two items are separated by a pipe symbol. 50 | 51 | To summarize, the GLPI_INSTALL_PLUGINS variable must follow the following skeleton GLPI_INSTALL_PLUGINS="name1|url1,name2|url2" 52 | For better example see at the end of this file. 53 | 54 | * The following volumes are exposed by this image 55 | 56 | | Volume | Usage | 57 | | ------------------ | ------------------------------------------------ | 58 | | /var/www/files | The data path of GLPI | 59 | | /var/www/config | The configuration path of GLPI | 60 | 61 | 62 | ## Application Informations 63 | 64 | 65 | ### HTTPS - SSL encryption 66 | 67 | There are many different possibilities to introduce encryption depending on your setup. 68 | 69 | As most of available docker image on the internet, I recommend using a reverse proxy in front of this image. 70 | This prevent me to introduce all ssl configurations parameters and also to prevent a limitation of the available parameters. 71 | 72 | For example, you can use the popular nginx-proxy and docker-letsencrypt-nginx-proxy-companion containers or Traefik to handle this. 73 | 74 | 75 | ### GLPI Cronjob 76 | 77 | GLPI require a job to be run periodically. Starting from 3.0.0 release, this image does not provide any solution to handle this. I've choose to remove cron task from this image to respect docker convention and to prevent a clustered deploiement to run the cron on all cluster instances. 78 | 79 | As compensation I provide a wrapper script that wrap the batch execution and return a json object with job execution details at ```/opt/scripts/cronwrapper.py``` 80 | 81 | To ensure correct GLPI running please put this job in your common cron scheduler. 82 | On linux you can use the /etc/crontab file with a content similar to this one : 83 | 84 | ``` 85 | */15 * * * * root docker ps | grep --quiet 'glpi' && docker exec --user www-data glpi /opt/scripts/cronwrapper.py --forward-stderr 86 | ``` 87 | 88 | 89 | ### Timezone issues 90 | 91 | Timezone is handled at PHP level in the image since 2.4.2 version, but you might encounter issues if you use different timezone in your database engine. 92 | Please refer to the GLPI documentations to handle this at database level https://glpi-install.readthedocs.io/en/develop/timezones.html. 93 | 94 | 95 | ## Todo 96 | 97 | * Normalize log output 98 | * Propose splitted nginx/fpm images 99 | * Add prometheus exporter (https://github.com/vozlt/nginx-module-vts, https://github.com/bakins/php-fpm-exporter) 100 | 101 | ## Installation 102 | 103 | ``` 104 | docker pull turgon37/glpi:nginx-72-latest 105 | ``` 106 | 107 | 108 | ## Usage 109 | 110 | The first time you run this image, set the GLPI_REMOVE_INSTALLER variable to 'no', then after this first installation set it to 'yes' to remove the installer. 111 | 112 | ### Without database link (you can use an ip address or a domain name in the installer gui) 113 | 114 | ``` 115 | docker run --name glpi --publish 8000:80 --volume data-glpi:/var/www/files --volume data-glpi-config:/var/www/config turgon37/glpi:nginx-56-latest 116 | ``` 117 | 118 | ### With database link (if you have any MySQL/MariaDB as a docker container) 119 | 120 | #### Create dedicated network 121 | 122 | ``` 123 | docker network create glpi-network 124 | ``` 125 | 126 | #### Start a MySQL instance 127 | 128 | ``` 129 | docker run --name mysql -d --net glpi-network -e MYSQL_DATABASE=glpi -e MYSQL_USER=glpi -e MYSQL_PASSWORD=glpi -e MYSQL_ROOT_PASSWORD=root_password mysql 130 | ``` 131 | 132 | #### Start a GLPI instance 133 | 134 | ``` 135 | docker run --name glpi --publish 8000:80 --volume data-glpi:/var/www/files --volume data-glpi-config:/var/www/config --net glpi-network turgon37/glpi:nginx-56-latest 136 | ``` 137 | 138 | ### Docker-compose Specific configuration examples 139 | 140 | * Production configuration with already installed GLPI with FusionInventory and dashboard plugin : 141 | 142 | ``` 143 | version: '2.1' 144 | services: 145 | 146 | glpi: 147 | image: turgon37/glpi:nginx-72-latest 148 | environment: 149 | GLPI_REMOVE_INSTALLER: 'no' 150 | GLPI_INSTALL_PLUGINS: " 151 | fusioninventory|https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi9.4%2B2.4/fusioninventory-9.4+2.4.tar.bz2,\ 152 | dumpentity|https://forge.glpi-project.org/attachments/download/2089/glpi-dumpentity-1.4.0.tar.gz\ 153 | " 154 | ports: 155 | - 127.0.0.1:8008:80 156 | volumes: 157 | - data-glpi-files:/var/www/files 158 | - data-glpi-config:/var/www/config 159 | depends_on: 160 | mysqldb: 161 | condition: service_healthy 162 | restart: always 163 | networks: 164 | glpi-network: 165 | aliases: 166 | - glpi 167 | 168 | mysqldb: 169 | image: mysql 170 | healthcheck: 171 | test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] 172 | interval: 10s 173 | timeout: 5s 174 | retries: 5 175 | restart: always 176 | command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 177 | environment: 178 | MYSQL_ROOT_PASSWORD: root 179 | volumes: 180 | - mysql-glpi-db:/var/lib/mysql 181 | restart: always 182 | networks: 183 | glpi-network: 184 | aliases: 185 | - mysqldb 186 | 187 | networks: 188 | glpi-network: 189 | driver: bridge 190 | 191 | volumes: 192 | data-glpi-files: 193 | data-glpi-config: 194 | mysql-glpi-db: 195 | ``` 196 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.3.0 2 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Global settings 4 | # image name 5 | DOCKER_IMAGE="${DOCKER_REPO:-glpi}" 6 | # use dockefile 7 | DOCKERFILE_PATH="Dockerfile_${IMAGE_VARIANT}" 8 | 9 | ## Initialization 10 | set -e 11 | 12 | # If empty version, fetch the latest from repository 13 | if [ -z "$GLPI_VERSION" ]; then 14 | if ! GLPI_VERSION=$(curl --fail -s https://api.github.com/repos/glpi-project/glpi/releases/latest | \ 15 | grep --perl-regexp --only-matching '(?<=tag_name": ")[a-z0-9.-]+'); then 16 | echo 'Error during fetch last glpi version' 17 | exit 1 18 | fi 19 | test -n "$GLPI_VERSION" 20 | fi 21 | echo "-> selected GLPI version '${GLPI_VERSION}'" 22 | 23 | # If empty commit, fetch the current from local git rpo 24 | if [[ -n "${SOURCE_COMMIT}" ]]; then 25 | VCS_REF="${SOURCE_COMMIT}" 26 | elif [[ -n "${TRAVIS_COMMIT}" ]]; then 27 | VCS_REF="${TRAVIS_COMMIT}" 28 | else 29 | VCS_REF="$(git rev-parse --short HEAD)" 30 | fi 31 | test -n "${VCS_REF}" 32 | echo "-> current vcs reference '${VCS_REF}'" 33 | 34 | # Get the current image static version 35 | image_version=$(cat VERSION) 36 | echo "-> use image version '${image_version}'" 37 | 38 | # Compute variant from dockerfile name 39 | if ! [[ -f ${DOCKERFILE_PATH} ]]; then 40 | echo 'You must select a valid dockerfile with DOCKERFILE_PATH' 1>&2 41 | exit 1 42 | fi 43 | if [[ -n ${IMAGE_VARIANT} ]]; then 44 | image_building_name="${DOCKER_IMAGE}:building_${IMAGE_VARIANT}" 45 | echo "-> set image variant '${IMAGE_VARIANT}' for build" 46 | else 47 | image_building_name="${DOCKER_IMAGE}:building" 48 | fi 49 | echo "-> use image name '${image_building_name}' for build" 50 | 51 | ## Build image 52 | echo "=> building '${image_building_name}' with image version '${image_version}'" 53 | docker build --build-arg "GLPI_VERSION=${GLPI_VERSION}" \ 54 | --label "org.label-schema.build-date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ 55 | --label 'org.label-schema.name=glpi' \ 56 | --label 'org.label-schema.description=GLPI web application' \ 57 | --label 'org.label-schema.url=https://github.com/Turgon37/docker-glpi' \ 58 | --label "org.label-schema.vcs-ref=${VCS_REF}" \ 59 | --label 'org.label-schema.vcs-url=https://github.com/Turgon37/docker-glpi' \ 60 | --label 'org.label-schema.vendor=Pierre GINDRAUD' \ 61 | --label "org.label-schema.version=${image_version}" \ 62 | --label 'org.label-schema.schema-version=1.0' \ 63 | --label "application.glpi.version=${GLPI_VERSION}" \ 64 | --tag "${image_building_name}" \ 65 | --file "${DOCKERFILE_PATH}" \ 66 | . 67 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | services: 3 | 4 | glpi: 5 | image: turgon37/glpi:nginx-72-latest 6 | environment: 7 | GLPI_REMOVE_INSTALLER: 'no' 8 | GLPI_INSTALL_PLUGINS: "\ 9 | fusioninventory|https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi9.2%2B1.0/glpi-fusioninventory-9.2.1.0.tar.bz2,\ 10 | dumpentity|https://forge.glpi-project.org/attachments/download/2089/glpi-dumpentity-1.4.0.tar.gz\ 11 | " 12 | ports: 13 | - 127.0.0.1:8008:80 14 | volumes: 15 | - data-glpi-files:/var/www/files 16 | - data-glpi-config:/var/www/config 17 | depends_on: 18 | mysqldb: 19 | condition: service_healthy 20 | restart: always 21 | networks: 22 | glpi-network: 23 | aliases: 24 | - glpi 25 | 26 | mysqldb: 27 | image: mysql 28 | healthcheck: 29 | test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] 30 | interval: 10s 31 | timeout: 5s 32 | retries: 5 33 | restart: always 34 | command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 35 | environment: 36 | MYSQL_ROOT_PASSWORD: root 37 | volumes: 38 | - mysql-glpi-db:/var/lib/mysql 39 | restart: always 40 | networks: 41 | glpi-network: 42 | aliases: 43 | - mysqldb 44 | 45 | networks: 46 | glpi-network: 47 | driver: bridge 48 | 49 | volumes: 50 | data-glpi-files: 51 | data-glpi-config: 52 | mysql-glpi-db: 53 | -------------------------------------------------------------------------------- /docker-entrypoint.d/01timezone: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | ## Configure timezone 6 | if [ -n "${TZ}" ]; then 7 | echo "Configuring timezone to ${TZ}..." 8 | if [ ! -f "/usr/share/zoneinfo/${TZ}" ]; then 9 | echo "...#ERROR# failed to link timezone data from /usr/share/zoneinfo/${TZ}" 1>&2 10 | exit 1 11 | fi 12 | ln -snf "/usr/share/zoneinfo/${TZ}" /etc/localtime 13 | echo "${TZ}" > /etc/timezone 14 | 15 | cat >/usr/local/etc/php/conf.d/zzz-timezone.ini <&2 27 | return 1 28 | fi 29 | fi 30 | 31 | # extract the archive according to the extension 32 | echo "..extracting plugin '${plugin_tmp_file}'" 33 | tar_options="--directory=${GLPI_PATHS_PLUGINS}" 34 | case "$plugin_tmp_file" in 35 | *.tar.gz) 36 | # shellcheck disable=SC2086 37 | tar ${tar_options} -xz -f "${plugin_tmp_file}" 38 | ;; 39 | *.tar.bz2) 40 | # shellcheck disable=SC2086 41 | tar ${tar_options} -xj -f "${plugin_tmp_file}" 42 | ;; 43 | *.zip) 44 | unzip "${plugin_tmp_file}" -d "${GLPI_PATHS_PLUGINS}" 45 | ;; 46 | *) 47 | echo "..#ERROR# unknown extension for ${file}. Please open an issue or make a PR to https://github.com/Turgon37/docker-glpi" 1>&2 48 | false 49 | ;; 50 | esac 51 | # shellcheck disable=SC2181 52 | if [ $? -ne 0 ]; then 53 | echo "..#ERROR# failed to extract plugin ${plugin}" 1>&2 54 | return 1 55 | fi 56 | 57 | # remove source and set file permissions 58 | rm -f "${plugin_tmp_file}" 59 | chown -R www-data:www-data "${plugin_root_dir}" 60 | chmod -R g=rX,o=--- "${plugin_root_dir}" 61 | } 62 | 63 | 64 | echo "Installing GLPI plugins in ${GLPI_PATHS_PLUGINS}..." 65 | 66 | # Use the new syntax with comma separated list 67 | if [ -n "${GLPI_INSTALL_PLUGINS}" ]; then 68 | OLDIFS=$IFS 69 | IFS=',' 70 | for item in ${GLPI_INSTALL_PLUGINS}; do 71 | IFS=$OLDIFS 72 | name="${item%|*}" 73 | url="${item#*|}" 74 | installPlugin "${name}" "${url}" 75 | done 76 | fi 77 | 78 | # Old deprecated plugins settings 79 | if [ -n "${GLPI_PLUGINS}" ]; then 80 | echo "..#error# GLPI_PLUGINS is deprecated use the new GLPI_INSTALL_PLUGINS instead" 1>&2 81 | exit 1 82 | fi 83 | -------------------------------------------------------------------------------- /docker-entrypoint.d/21glpifiles: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | basedir="${GLPI_PATHS_ROOT}" 6 | 7 | echo 'Configuring GLPI files...' 8 | 9 | ## Remove installer 10 | # used to remove the installer after first installation 11 | if [ "x${GLPI_REMOVE_INSTALLER}" = 'xyes' ]; then 12 | echo 'Removing installer if needed...' 13 | rm -f "${basedir}/install/install.php" 14 | fi 15 | 16 | ## Files structure 17 | echo "Create file structure..." 18 | for f in _cache _cron _dumps _graphs _lock _log _pictures _plugins _rss _sessions _tmp _uploads; do 19 | dir="${basedir}/files/${f}" 20 | if [ ! -d "${dir}" ]; then 21 | mkdir -p "${dir}" 22 | chown www-data:www-data "${dir}" 23 | chmod u=rwX,g=rwX,o=--- "${dir}" 24 | fi 25 | done 26 | 27 | ## Files permissions 28 | # address issue https://github.com/Turgon37/docker-glpi/issues/2 29 | if [ "x${GLPI_CHMOD_PATHS_FILES}" = 'xyes' ]; then 30 | echo 'Set files permissions...' 31 | chown -R www-data:www-data "${basedir}/files" 32 | chmod -R u=rwX,g=rX,o=--- "${basedir}/files" 33 | fi 34 | 35 | # address issue https://github.com/Turgon37/docker-glpi/issues/27 36 | # shellcheck disable=SC2046 37 | if [ $(stat -c %u "${basedir}/config") != $(id -u www-data) ]; then 38 | # shellcheck disable=SC2038 39 | find . -maxdepth 1 -not -name files | xargs -r chown -R www-data:www-data 40 | fi 41 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | DIR=/docker-entrypoint.d 6 | 7 | if [ -d "$DIR" ]; then 8 | /bin/run-parts --exit-on-error "$DIR" 1>&2 9 | fi 10 | 11 | exec "$@" 12 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | ## Global settings 5 | # image name 6 | DOCKER_IMAGE="${DOCKER_REPO:-glpi}" 7 | # "production" branch 8 | PRODUCTION_BRANCH=${PRODUCTION_BRANCH:-master} 9 | 10 | 11 | ## Initialization 12 | set -e 13 | 14 | if [[ ${DOCKER_IMAGE} =~ ([^/]+)/([^/]+) ]]; then 15 | username=${BASH_REMATCH[1]} 16 | repo=${BASH_REMATCH[2]} 17 | echo "-> set username to '${username}'" 18 | echo "-> set repository to '${repo}'" 19 | else 20 | echo 'ERROR: unable to extract username and repo from environment' 1>&2 21 | exit 1 22 | fi 23 | 24 | if [[ -z "$DOCKERHUB_REGISTRY_USERNAME" || -z "$DOCKERHUB_REGISTRY_PASSWORD" ]]; then 25 | echo 'ERROR: missing one of the registry credential DOCKERHUB_REGISTRY_USERNAME DOCKERHUB_REGISTRY_PASSWORD' 1>&2 26 | exit 1 27 | fi 28 | 29 | image_version=$(cat VERSION) 30 | 31 | if [[ -n ${IMAGE_VARIANT} ]]; then 32 | image_building_name="${DOCKER_IMAGE}:building_${IMAGE_VARIANT}" 33 | image_tags_prefix="${IMAGE_VARIANT}-" 34 | echo "-> set image variant '${IMAGE_VARIANT}' for build" 35 | else 36 | image_building_name="${DOCKER_IMAGE}:building" 37 | fi 38 | echo "-> use image name '${image_building_name}' for publish" 39 | 40 | # If empty branch, fetch the current from local git rpo 41 | if [[ -n "${SOURCE_BRANCH}" ]]; then 42 | VCS_BRANCH="${SOURCE_BRANCH}" 43 | elif [[ -n "${TRAVIS_BRANCH}" ]]; then 44 | VCS_BRANCH="${TRAVIS_BRANCH}" 45 | else 46 | VCS_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 47 | fi 48 | test -n "${VCS_BRANCH}" 49 | echo "-> current vcs branch '${VCS_BRANCH}'" 50 | 51 | # set the docker publish logic per branch 52 | application_version=$(docker inspect -f '{{ index .Config.Labels "application.glpi.version" }}' "${image_building_name}") 53 | publish=false 54 | if [[ "${VCS_BRANCH}" == "${PRODUCTION_BRANCH}" ]]; then 55 | image_tags=("${image_tags_prefix}${application_version}-${image_version}") 56 | if [[ -z "${GLPI_VERSION}" || -n "${UPDATE_LATEST}" ]]; then 57 | image_tags+=("${image_tags_prefix}latest" "${image_tags_prefix}${application_version}-latest") 58 | fi 59 | if ! curl -s "https://hub.docker.com/v2/repositories/${username}/${repo}/tags/?page_size=100" \ 60 | | grep --quiet "\"name\": *\"${image_tags_prefix}${application_version}-${image_version}\""; then 61 | publish=true 62 | fi 63 | elif [[ "${VCS_BRANCH}" == "develop" ]]; then 64 | image_tags=("develop-${image_tags_prefix}${application_version}-${image_version}") 65 | if [[ -z "${GLPI_VERSION}" || -n "${UPDATE_LATEST}" ]]; then 66 | image_tags+=("develop-${image_tags_prefix}latest") 67 | fi 68 | publish=true 69 | fi 70 | echo "-> use image tags '${image_tags[*]}'" 71 | 72 | 73 | ## Publish image 74 | if [[ "${publish}" != "true" ]]; then 75 | echo "-> No need to Push to Registry" 76 | else 77 | echo "-> Pushing to registry.." 78 | 79 | ## Login to registry 80 | echo "$DOCKERHUB_REGISTRY_PASSWORD" | docker login --username="$DOCKERHUB_REGISTRY_USERNAME" --password-stdin 81 | 82 | ## Push images 83 | for tag in ${image_tags[*]}; do 84 | echo "=> tag image '${image_building_name}' as '${DOCKER_IMAGE}:${tag}'" 85 | docker tag "${image_building_name}" "${DOCKER_IMAGE}:${tag}" 86 | echo "=> push image '${DOCKER_IMAGE}:${tag}'" 87 | docker push "${DOCKER_IMAGE}:${tag}" 88 | done 89 | 90 | ## Logout from registry 91 | docker logout 92 | fi 93 | 94 | 95 | ## Publish README 96 | # only for production branch 97 | if [[ "${VCS_BRANCH}" == "${PRODUCTION_BRANCH}" && -n "${UPDATE_README}" ]]; then 98 | set -o pipefail 99 | TOKEN=$(curl --fail --silent -H "Content-Type: application/json" -X POST -d "{\"username\": \"${DOCKERHUB_REGISTRY_USERNAME}\", \"password\": \"${DOCKERHUB_REGISTRY_PASSWORD}\"}" https://hub.docker.com/v2/users/login/ | grep --perl-regexp --only-matching '(?<=token": ")[^"]+') 100 | curl --fail --silent -H "Authorization: JWT $TOKEN" -X PATCH "https://hub.docker.com/v2/repositories/${username}/${repo}/" --data-urlencode full_description@./README.md 101 | set +o pipefail 102 | fi 103 | -------------------------------------------------------------------------------- /root/etc/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | 3 | user nginx; 4 | 5 | # Set number of worker processes automatically based on number of CPU cores. 6 | #worker_processes auto; 7 | worker_processes 1; 8 | 9 | # Configures default error logger. 10 | error_log stderr error; 11 | 12 | events { 13 | # The maximum number of simultaneous connections that can be opened by 14 | # a worker process. 15 | worker_connections 1024; 16 | } 17 | 18 | http { 19 | include mime.types; 20 | default_type application/octet-stream; 21 | 22 | # send access log into standard output 23 | access_log /proc/self/fd/1; 24 | 25 | # Don't tell nginx version to clients. 26 | server_tokens off; 27 | 28 | # Timeout for keep-alive connections. Server will close connections after 29 | # this time. 30 | keepalive_timeout 65; 31 | 32 | # Sendfile copies data between one FD and other from within the kernel, 33 | # which is more efficient than read() + write(). 34 | sendfile on; 35 | 36 | # Don't buffer data-sends (disable Nagle algorithm). 37 | # Good for sending frequent small bursts of data in real time. 38 | tcp_nodelay on; 39 | 40 | # Causes nginx to attempt to send its HTTP response head in one packet, 41 | # instead of using partial frames. 42 | #tcp_nopush on; 43 | 44 | # Enable gzipping of responses. 45 | #gzip on; 46 | 47 | # Set the Vary HTTP header as defined in the RFC 2616. 48 | gzip_vary on; 49 | 50 | # Enable checking the existence of precompressed files. 51 | #gzip_static on; 52 | 53 | server { 54 | ## HTTP configuration 55 | listen 80 default_server; 56 | listen [::]:80 default_server; 57 | 58 | ## NETWORK LIMITATIONS 59 | client_max_body_size 30M; 60 | client_body_buffer_size 128k; 61 | 62 | ## DIRECTORY 63 | root /var/www; 64 | index index.php; 65 | 66 | ## LOCATION 67 | location / { 68 | try_files $uri $uri/ =404; 69 | } 70 | 71 | location = /api/ { 72 | if ($http_x_forwarded_proto ~ "^https?$") { 73 | return 301 $http_x_forwarded_proto://$host/apirest.php; 74 | } 75 | return 301 $scheme://$host/apirest.php; 76 | } 77 | 78 | location /api { 79 | rewrite ^/api/(.*)$ /apirest.php/$1 last; 80 | } 81 | 82 | location = /nginx-status { 83 | allow 127.0.0.1; 84 | deny all; 85 | stub_status; 86 | } 87 | 88 | location ~ ^/fpm-(status|ping)$ { 89 | allow 127.0.0.1; 90 | deny all; 91 | include fastcgi_params; 92 | fastcgi_pass unix:/var/run/php-fpm.sock; 93 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 94 | fastcgi_intercept_errors on; 95 | } 96 | 97 | location ~ [^/]\.php(/|$) { 98 | # regex to split $uri to $fastcgi_script_name and $fastcgi_path 99 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 100 | 101 | # Check that the PHP script exists before passing it 102 | try_files $fastcgi_script_name =404; 103 | 104 | include fastcgi_params; 105 | 106 | # Bypass the fact that try_files resets $fastcgi_path_info 107 | # # see: http://trac.nginx.org/nginx/ticket/321 108 | set $path_info $fastcgi_path_info; 109 | fastcgi_param PATH_INFO $path_info; 110 | 111 | fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name; 112 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 113 | fastcgi_param SERVER_NAME $host; 114 | 115 | # allow directory index 116 | fastcgi_index index.php; 117 | fastcgi_pass unix:/var/run/php-fpm.sock; 118 | } 119 | 120 | # deny access to some ressources 121 | location ~ /(config|files)/ { 122 | deny all; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /root/etc/php-fpm.d/custom.ini.j2: -------------------------------------------------------------------------------- 1 | file_uploads=on 2 | max_execution_time=600 3 | register_globals=off 4 | magic_quotes_sybase=off 5 | session.auto_start=off 6 | session.use_trans_sid=0 7 | display_errors=stderr 8 | display_startup_errors=On 9 | memory_limit={{ env('PHP_MEMORY_LIMIT') }} 10 | -------------------------------------------------------------------------------- /root/etc/php-fpm.d/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | [www] 2 | listen = /var/run/php-fpm.sock 3 | listen.owner = www-data 4 | listen.group = nginx 5 | listen.mode = 6 | pm.status_path = /fpm-status 7 | ping.path = /fpm-ping 8 | ping.response = pong 9 | pm = {{ env('PHPFPM_PM') }} 10 | pm.max_children = {{ env('PHPFPM_PM_MAX_CHILDREN') }} 11 | pm.start_servers = {{ env('PHPFPM_PM_START_SERVERS') }} 12 | pm.min_spare_servers = {{ env('PHPFPM_PM_MIN_SPARE_SERVERS') }} 13 | pm.max_spare_servers = {{ env('PHPFPM_PM_MAX_SPARE_SERVERS') }} 14 | pm.process_idle_timeout = {{ env('PHPFPM_PM_PROCESS_IDLE_TIMEOUT') }} 15 | pm.max_requests = {{ env('PHPFPM_PM_MAX_REQUEST') }} 16 | -------------------------------------------------------------------------------- /root/etc/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | logfile=/proc/1/fd/1 4 | loglevel=info 5 | logfile_maxbytes=0 6 | pidfile=/run/supervisord.pid 7 | minfds=1024 8 | user=root 9 | 10 | [unix_http_server] 11 | file=/var/run/supervisor.sock 12 | 13 | [supervisorctl] 14 | serverurl=unix:///var/run/supervisor.sock 15 | 16 | [rpcinterface:supervisor] 17 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 18 | 19 | 20 | [program:php] 21 | command=php-fpm 22 | stdout_logfile=/proc/1/fd/1 23 | stderr_logfile=/proc/1/fd/2 24 | stdout_logfile_maxbytes=0 25 | stderr_logfile_maxbytes=0 26 | priority=10 27 | 28 | 29 | [program:nginx] 30 | command=/usr/sbin/nginx 31 | stdout_logfile=/proc/1/fd/1 32 | stderr_logfile=/proc/1/fd/2 33 | stdout_logfile_maxbytes=0 34 | stderr_logfile_maxbytes=0 35 | priority=20 36 | -------------------------------------------------------------------------------- /root/opt/scripts/cronwrapper.py: -------------------------------------------------------------------------------- 1 | /usr/local/bin/cronwrapper.py -------------------------------------------------------------------------------- /root/usr/local/bin/cronwrapper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import os 5 | import re 6 | import subprocess 7 | import sys 8 | import time 9 | 10 | # Try to use the fastest json lib available 11 | # Resort back to stdlib if necessary (slower) 12 | try: 13 | import ujson as json 14 | except ImportError: 15 | try: 16 | import simplejson as json 17 | except ImportError: 18 | import json 19 | 20 | 21 | re_backspaces = re.compile('(\b)+') 22 | 23 | 24 | def filterOutputString(string): 25 | return re_backspaces.sub('', string) 26 | 27 | 28 | # MAIN 29 | if __name__ == '__main__': 30 | parser = argparse.ArgumentParser(description='Simple execution wrapper for cron type jobs', 31 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 32 | parser.add_argument('-c', '--command', dest='command', action='store', 33 | default='/usr/local/bin/php', 34 | help='The path to the final cron') 35 | parser.add_argument('--forward-stderr', dest='forward_stderr', action='store_true', 36 | default=False, 37 | help='If True, forward script stderr to caller shell stderr') 38 | parser.add_argument('args', nargs='*', 39 | default=[os.path.join(os.getenv('GLPI_PATHS_ROOT', '/'), 'front/cron.php')], 40 | help='The arguments list') 41 | args = parser.parse_args() 42 | command_path = os.path.realpath(args.command) 43 | command_args = args.args 44 | if '--' in command_args: 45 | command_args.remove('--') 46 | 47 | log = dict( 48 | stdout='', 49 | stdout_size=0, 50 | stderr='', 51 | stderr_size=0, 52 | wrapped_command=args.command, 53 | wrapped_command_fullpath=command_path, 54 | return_code=None, 55 | arguments=' '.join(command_args), 56 | full_command=' '.join([command_path] + command_args), 57 | ) 58 | 59 | raw_stdout = '' 60 | raw_stderr = '' 61 | try: 62 | log['start_time'] = time.time() 63 | result = subprocess.Popen([command_path] + command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 64 | raw_stdout, raw_stderr = result.communicate() 65 | log['stdout'] = filterOutputString(raw_stdout) 66 | log['stderr'] = filterOutputString(raw_stderr) 67 | log['return_code'] = result.returncode 68 | except subprocess.CalledProcessError as ex: 69 | log['stderr'] = str(ex) 70 | except OSError as ex: 71 | log['stderr'] = str(ex) 72 | finally: 73 | log['end_time'] = time.time() 74 | log['execution_time'] = log['end_time'] - log['start_time'] 75 | 76 | log['stdout_size'] = len(log['stdout']) 77 | log['stderr_size'] = len(log['stderr']) 78 | sys.stdout.write(json.dumps(log)+'\n') 79 | if args.forward_stderr and len(log['stderr']): 80 | sys.stderr.write(log['stderr']+'\n') 81 | sys.exit(0) 82 | -------------------------------------------------------------------------------- /tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Global settings 4 | # image name 5 | DOCKER_IMAGE="${DOCKER_REPO:-glpi}" 6 | 7 | ## Initialization 8 | set -e 9 | 10 | if [[ -n ${IMAGE_VARIANT} ]]; then 11 | image_building_name="${DOCKER_IMAGE}:building_${IMAGE_VARIANT}" 12 | echo "-> set image variant '${IMAGE_VARIANT}' for build" 13 | else 14 | image_building_name="${DOCKER_IMAGE}:building" 15 | fi 16 | docker_run_options='--detach' 17 | # string that proove that container is up 18 | container_up_string='GET /fpm-ping' 19 | echo "-> use image name '${image_building_name}' for tests" 20 | 21 | 22 | ## Prepare 23 | if [[ -z $(command -v container-structure-test 2>/dev/null) ]]; then 24 | echo "Retrieving structure-test binary...." 25 | if [[ -n "${TRAVIS_OS_NAME}" && "$TRAVIS_OS_NAME" != 'linux' ]]; then 26 | echo "container-structure-test only released for Linux at this time." 27 | echo "To run on OSX, clone the repository and build using 'make'." 28 | exit 1 29 | else 30 | curl -sSLO https://storage.googleapis.com/container-structure-test/latest/container-structure-test-linux-amd64 \ 31 | && chmod +x container-structure-test-linux-amd64 \ 32 | && mv container-structure-test-linux-amd64 container-structure-test 33 | fi 34 | fi 35 | 36 | # Download tools shim. 37 | if [[ ! -f _tools.sh ]]; then 38 | curl -L -o "${PWD}/_tools.sh" https://gist.github.com/Turgon37/2ba8685893807e3637ea3879ef9d2062/raw 39 | fi 40 | # shellcheck disable=SC1090 41 | source "${PWD}/_tools.sh" 42 | 43 | 44 | ## Test 45 | 46 | # shell scripts tests 47 | # shellcheck disable=SC2038 48 | find . -name '*.sh' | xargs shellcheck docker-entrypoint.d/* 49 | 50 | # Image tests 51 | ./container-structure-test \ 52 | test --image "${image_building_name}" --config ./tests.yml 53 | 54 | ## Ensure that required php extensions are installed 55 | extensions=$(docker run --rm "${image_building_name}" php -m) 56 | for ext in apcu \ 57 | ctype \ 58 | curl \ 59 | dom \ 60 | gd \ 61 | imap \ 62 | json \ 63 | ldap \ 64 | mysqli \ 65 | openssl \ 66 | opcache \ 67 | soap \ 68 | xml \ 69 | xmlreader \ 70 | xmlrpc \ 71 | zlib; do 72 | if ! echo "${extensions}" | grep -qi $ext; then 73 | echo "missing PHP extension '$ext'" 1>&2 74 | exit 1 75 | fi 76 | done 77 | 78 | 79 | #2 Test plugins installation with tar.bz2 80 | echo '-> 2 Test plugins installation with tar.bz2' 81 | image_name=glpi_2 82 | docker run $docker_run_options --name "${image_name}" --env='GLPI_INSTALL_PLUGINS=fusioninventory|https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi9.3%2B1.1/fusioninventory-9.3.1.1.tar.bz2' "${image_building_name}" 83 | wait_for_string_in_container_logs "${image_name}" "${container_up_string}" 84 | # test 85 | if ! docker exec "${image_name}" test -d plugins/fusioninventory; then 86 | docker logs "${image_name}" 87 | false 88 | fi 89 | stop_and_remove_container "${image_name}" 90 | 91 | 92 | #3 Test plugins installation with tar.gz 93 | echo '-> 3 Test plugins installation with tar.gz' 94 | image_name=glpi_3 95 | docker run $docker_run_options --name "${image_name}" --env='GLPI_INSTALL_PLUGINS=fusioninventory|https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi9.3%2B1.2/fusioninventory-9.3+1.2.tar.gz' "${image_building_name}" 96 | wait_for_string_in_container_logs "${image_name}" "${container_up_string}" 97 | # test 98 | if ! docker exec "${image_name}" test -d plugins/fusioninventory; then 99 | docker logs "${image_name}" 100 | false 101 | fi 102 | stop_and_remove_container "${image_name}" 103 | 104 | 105 | #4 Test timezone setting 106 | echo '-> 4 Test timezone' 107 | image_name=glpi_4 108 | docker run $docker_run_options --name "${image_name}" --env='TZ=Europe/Paris' "${image_building_name}" 109 | wait_for_string_in_container_logs "${image_name}" "${container_up_string}" 110 | # test 111 | if ! [[ $(docker exec "${image_name}" readlink -f /etc/localtime) =~ Europe/Paris$ ]]; then 112 | docker logs "${image_name}" 113 | false 114 | fi 115 | stop_and_remove_container "${image_name}" 116 | 117 | 118 | #5 Test web access 119 | echo '-> 5 Test web access' 120 | image_name=glpi_5 121 | docker run $docker_run_options --name "${image_name}" --publish 8000:80 "${image_building_name}" 122 | wait_for_string_in_container_logs "${image_name}" 'nginx entered RUNNING state' 123 | sleep 5 124 | # test 125 | if ! curl -v http://localhost:8000 2>&1 | grep --quiet 'install/install.php'; then 126 | docker logs "${image_name}" 127 | false 128 | fi 129 | stop_and_remove_container "${image_name}" 130 | 131 | 132 | #6 Test plugins installation with zip 133 | echo '-> 6 Test plugins installation with zip' 134 | image_name=glpi_6 135 | docker run $docker_run_options --name "${image_name}" --env='GLPI_INSTALL_PLUGINS=timezones|https://github.com/tomolimo/timezones/releases/download/2.4.1/timezones-2.4.1.zip' "${image_building_name}" 136 | wait_for_string_in_container_logs "${image_name}" "${container_up_string}" 137 | # test 138 | if ! docker exec "${image_name}" test -d plugins/timezones; then 139 | docker logs "${image_name}" 140 | false 141 | fi 142 | stop_and_remove_container "${image_name}" 143 | -------------------------------------------------------------------------------- /tests.yml: -------------------------------------------------------------------------------- 1 | schemaVersion: 2.0.0 2 | 3 | metadataTest: 4 | exposedPorts: ["80"] 5 | volumes: ["/var/www/files", "/var/www/config"] 6 | 7 | commandTests: 8 | - name: GLPI successfully installed 9 | command: test 10 | args: 11 | - '-f' 12 | - index.php 13 | exitCode: 0 14 | --------------------------------------------------------------------------------