diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..7a710aaa3a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +zdsenv +*.log +.git +node_modules +dist +contents-private +contents-public +data_mysql +doc/build +media +.sass-cache diff --git a/back.Dockerfile b/back.Dockerfile new file mode 100644 index 0000000000..4e510e364b --- /dev/null +++ b/back.Dockerfile @@ -0,0 +1,159 @@ +FROM python:3.9 + +ENV PYTHONUNBUFFERED 1 + +# ----- +# LATEX +# ----- + +# Install packages +RUN apt-get update +RUN apt-get install -y texlive texlive-luatex texlive-lang-french texlive-latex-extra texlive-fonts-extra xzdec librsvg2-bin imagemagick + +# Init tree +RUN mkdir /root/texmf +RUN tlmgr init-usertree + +# Install packages +RUN tlmgr option repository "$(echo http://ftp.math.utah.edu/pub/tex/historic/systems/texlive/`echo -n $(tlmgr --version) | tail -c 4`/tlnet-final)" +RUN updmap-user +RUN tlmgr update --list +RUN tlmgr install adjustbox +RUN tlmgr install blindtext +RUN tlmgr install capt-of +RUN tlmgr install catoptions +RUN tlmgr install chemgreek +#RUN tlmgr install cm-super +RUN tlmgr install collectbox +RUN tlmgr install ctablestack +RUN tlmgr install datatool +RUN tlmgr install environ +RUN tlmgr install etoolbox +RUN tlmgr install fontspec +RUN tlmgr install framed +RUN tlmgr install fvextra +RUN tlmgr install geometry +RUN tlmgr install ifmtarg +RUN tlmgr install ifplatform +RUN tlmgr install luacode +RUN tlmgr install menukeys +RUN tlmgr install mfirstuc +RUN tlmgr install mhchem +RUN tlmgr install minted +RUN tlmgr install multirow +RUN tlmgr install ntheorem +RUN tlmgr install pagecolor +RUN tlmgr install relsize +RUN tlmgr install substr +RUN tlmgr install tcolorbox +RUN tlmgr install tracklang +RUN tlmgr install trimspaces +RUN tlmgr install varwidth +RUN tlmgr install xfor +RUN tlmgr install xifthen +RUN tlmgr install xpatch +RUN tlmgr install xstring + + +# Install Tabu +RUN mkdir -p /src/texmf/tex/latex/tabu/ +RUN wget -q https://raw.githubusercontent.com/tabu-issues-for-future-maintainer/tabu/master/tabu.sty -O /src/texmf/tex/latex/tabu/tabu.sty + +RUN mkdir -p /src/texmf/tex/generic + +# Get template + +RUN wget -q https://github.com/zestedesavoir/latex-template/archive/master.tar.gz -O template.tar.gz +RUN tar -xf template.tar.gz +RUN cp -rp latex-template-master/* /root/texmf/tex/generic/ +RUN rm -rf latex-template-master template.tar.gz + +RUN texhash /root/texmf + +# Get fonts + +RUN mkdir -p /usr/local/share/fonts/opentype/source-code-pro +RUN mkdir -p /usr/local/share/fonts/opentype/source-sans-pro +RUN mkdir -p /usr/local/share/fonts/truetype/source-code-pro +RUN mkdir -p /usr/local/share/fonts/truetype/source-sans-pro + + +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-Black.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-Black.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-BlackIt.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-BlackIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-Bold.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-Bold.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-BoldIt.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-BoldIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-ExtraLight.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-ExtraLight.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-ExtraLightIt.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-ExtraLightIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-It.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-It.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-Light.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-Light.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-LightIt.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-LightIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-Regular.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-Regular.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-Semibold.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-Semibold.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/OTF/SourceCodePro-SemiboldIt.otf -O /usr/local/share/fonts/opentype/source-code-pro/SourceCodePro-SemiboldIt.otf + +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Black.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-Black.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-BlackIt.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-BlackIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Bold.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-Bold.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-BoldIt.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-BoldIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-ExtraLight.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-ExtraLight.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-ExtraLightIt.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-ExtraLightIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-It.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-It.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Light.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-Light.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-LightIt.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-LightIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Regular.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-Regular.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-Semibold.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-Semibold.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-code-pro/release/TTF/SourceCodePro-SemiboldIt.ttf -O /usr/local/share/fonts/truetype/source-code-pro/SourceCodePro-SemiboldIt.ttf + +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-Black.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-Black.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-BlackIt.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-BlackIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-Bold.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-Bold.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-BoldIt.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-BoldIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-ExtraLight.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-ExtraLight.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-ExtraLightIt.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-ExtraLightIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-It.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-It.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-Light.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-Light.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-LightIt.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-LightIt.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-Regular.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-Regular.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-Semibold.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-Semibold.otf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/OTF/SourceSans3-SemiboldIt.otf -O /usr/local/share/fonts/opentype/source-sans-pro/SourceSansPro-SemiboldIt.otf + +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Black.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-Black.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-BlackIt.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-BlackIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Bold.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-Bold.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-BoldIt.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-BoldIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-ExtraLight.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-ExtraLight.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-ExtraLightIt.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-ExtraLightIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-It.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-It.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Light.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-Light.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-LightIt.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-LightIt.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Regular.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-Regular.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-Semibold.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-Semibold.ttf +RUN wget -q https://raw.githubusercontent.com/adobe-fonts/source-sans/release/TTF/SourceSans3-SemiboldIt.ttf -O /usr/local/share/fonts/truetype/source-sans-pro/SourceSansPro-SemiboldIt.ttf + +RUN fc-cache -f + + +# ------ +# WEBAPP +# ------ + +ENV DOCKERIZE_VERSION v0.6.1 +RUN wget -q https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ + && tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ + && rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz + +WORKDIR /src + +COPY requirements.txt /src/requirements.txt +COPY requirements-dev.txt /src/requirements-dev.txt +COPY requirements-prod.txt /src/requirements-prod.txt + +RUN pip3 install --upgrade pip +RUN pip3 -q install -r /src/requirements-dev.txt +RUN pip3 -q install -r /src/requirements-prod.txt + + + +#COPY ./settings_docker.py /zds/zds/settings/docker.py +#COPY ./service/zds-watchdog.sh /zds/zds-watchdog.sh +#COPY ./service/zds-index.sh /zds/zds-index.sh diff --git a/doc/source/install/install-docker.rst b/doc/source/install/install-docker.rst index 2666e68e74..0c5baf0719 100644 --- a/doc/source/install/install-docker.rst +++ b/doc/source/install/install-docker.rst @@ -2,6 +2,104 @@ Installation dans Docker ======================== +Installation via docker-compose +=============================== + +.. note:: + + L'installation à partir de docker-compose est entièrement containeurisée. + Ce qui signifie que seules les sources de zds-site se trouvent sur votre système + et tout le reste (dépendances back, front) tournent dans des containeurs séparés. + +Installation d'une instance locale vide +--------------------------------------- + +.. note:: + + Cette installation déploie zds sur votre poste local au plus proche de ce qu'on peut avoir sur la production. + La base de donnée utilisée est mariadb. + +Deux prérequis sont necessaires pour installer zds-site par ce moyen. + +- `docker-compose <https://docs.docker.com/compose/install/>`_ +- `docker <https://docs.docker.com/get-docker/>`_ + +Après avoir cloné le dépôt du code source, installer ZdS via docker-compose est relativement simple. +En effet, il suffit de lancer la commande suivante (qui se chargera d'installer ce qui est nécessaire sans polluer votre système): + +.. sourcecode:: bash + + docker-compose up + +.. warning:: + La première fois, la commande sera très longue, le temps de télécharger et construire les images nécessaires. + Au deuxième lancement, la commande sera beaucoup plus rapide. + +Une fois installé et démarré vous pouvez ouvrir votre navigateur à l'addresse suivante : ``http://localhost:8000/`` pour consulter votre version locale de ZdS. + +Chargement des fixtures +----------------------- + +Une fois zds installé et démarré, vous aurez certainement besoin de charger des fixtures pour avoir des données prêtes à l'emploi. +Pour cela, il suffit de lancer la commande ci-dessous dans un second terminal. + +.. sourcecode:: bash + + docker-compose up fixtures + +Cette commande permet de charger des données de test. + +Toutes les commandes docker-compose +----------------------------------- + +Voici la liste des services docker-compose exposés, les ports que ces services exposent sur votre poste local, les dossiers dans lesquels chaque service écrivent sur votre système. + +.. list-table:: Liste des services + :header-rows: 1 + + * - Service + - Port exposés sur l'hote + - Dossier local en écriture + - Description + * - back + - 8000 + - ``.`` + - Serveur back django + * - front + - + - ``./dist`` + - Service en écoute sur les éléments de front, et build le front à chaque modification. + * - indexer + - + - + - Service d'indexation des nouveaux contenus dans Elasticsearch. + * - fixtures + - + - ``./contents-private``, ``./contents-public`` + - Service de chargement des fixtures. + * - doc + - + - ``./doc`` + - Service de génération de la documentation. + * - cache + - + - + - Service de gestion du cache du back-end. + * - database + - + - ``./data_mysql`` + - Service de gestion de la base de donnée mariadb. + * - elasticsearch + - + - + - Service de gestion du moteur d'indexation Elasticsearch. + * - watchdog + - + - + - Service de génération des exports de contenus. + +Installation dans un container docker +===================================== .. note:: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..cbad21ff3b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,152 @@ +version: '3.1' + +services: + back: + build: + context: . + dockerfile: back.Dockerfile + ports: + - "8000:8000" + expose: + - "8000" + command: > + bash -c "dockerize -wait tcp://database:3306 -wait tcp://cache:11211 -wait tcp://elasticsearch:9200 -wait tcp://zmd:27272 -timeout 60s + && python manage.py migrate --settings zds.settings.docker + && python manage.py runserver 0.0.0.0:8000 --settings zds.settings.docker" + depends_on: + - front + - database + - cache + - zmd + links: + - database + - elasticsearch + - cache + - zmd + volumes: + - .:/src:rw + watchdog: + build: + context: . + dockerfile: back.Dockerfile + command: > + bash -c "dockerize -wait tcp://back:8000 -timeout 120s + && python manage.py publication_watchdog --settings zds.settings.docker" + depends_on: + - back + links: + - database + - elasticsearch + - cache + - zmd + volumes: + - .:/src:rw + indexer: + build: + context: . + dockerfile: back.Dockerfile + command: > + bash -c "dockerize -wait tcp://back:8000 -timeout 240s + && python manage.py es_manager index_flagged --settings zds.settings.docker + && sleep 60" + restart: always + depends_on: + - back + links: + - database + - elasticsearch + - cache + - zmd + volumes: + - .:/src:ro + profiles: + - donotstart + index-setup: + build: + context: . + dockerfile: back.Dockerfile + command: > + bash -c "dockerize -wait tcp://back:8000 -wait tcp://elasticsearch:9200 -timeout 240s + && python manage.py es_manager setup --settings zds.settings.docker + && python manage.py es_manager index_all --settings zds.settings.docker" + depends_on: + - back + - elasticsearch + links: + - database + - elasticsearch + - cache + - zmd + volumes: + - .:/src:rw + fixtures: + build: + context: . + dockerfile: back.Dockerfile + command: > + bash -c "dockerize -wait tcp://back:8000 -timeout 120s + && python manage.py loaddata fixtures/*.yaml --settings zds.settings.docker + && python manage.py load_factory_data fixtures/advanced/aide_tuto_media.yaml --settings zds.settings.docker + && python manage.py load_fixtures --size=low --all --settings zds.settings.docker + && python manage.py es_manager index_all --settings zds.settings.docker" + depends_on: + - back + links: + - database + - elasticsearch + - cache + - zmd + volumes: + - .:/src:rw + profiles: + - donotstart + front: + build: + context: . + dockerfile: front.Dockerfile + command: "yarn run watch" + volumes: + - ./assets:/src/assets:ro + - ./dist:/src/dist:rw + doc: + build: + context: . + dockerfile: back.Dockerfile + command: bash -c "cd doc && make html" + volumes: + - .:/src:rw + profiles: + - donotstart + zmd: + build: + context: . + dockerfile: zmd.Dockerfile + command: bash -c "cd ./node_modules/zmarkdown && npm run server && pm2 monit" + expose: + - "27272" + cache: + image: memcached:1.5-alpine + expose: + - "11211" + database: + image: mariadb:10.4 + expose: + - "3306" + restart: always + environment: + MYSQL_DATABASE: zds_docker + MYSQL_ROOT_PASSWORD: 'zds_password' + volumes: + - ./data_mysql:/var/lib/mysql + elasticsearch: + image: elasticsearch:5.5.2 + expose: + - "9200" + environment: + - "http.host=0.0.0.0" + - "xpack.security.enabled=false" + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - "discovery.type=single-node" + + + diff --git a/front.Dockerfile b/front.Dockerfile new file mode 100644 index 0000000000..79d8022e67 --- /dev/null +++ b/front.Dockerfile @@ -0,0 +1,15 @@ +FROM node:14-slim + +ENV NODE_ENV=development + +WORKDIR /src + +COPY package.json ./package.json +COPY Gulpfile.js ./Gulpfile.js + +RUN apt-get update +RUN apt-get install -y dh-autoreconf + +RUN yarn install + +VOLUME ["/src/assets"] diff --git a/zds/settings/docker.py b/zds/settings/docker.py new file mode 100644 index 0000000000..1b5615c63f --- /dev/null +++ b/zds/settings/docker.py @@ -0,0 +1,46 @@ +from .abstract_base import * + +DEBUG = True + +USE_L10N = True + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": "zds_docker", + "USER": "root", + "PASSWORD": "zds_password", + "HOST": "database", + "PORT": "3306", + "CONN_MAX_AGE": 600, + "OPTIONS": { + "charset": "utf8mb4", + "init_command": "SET sql_mode='STRICT_TRANS_TABLES'", + }, + } +} + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache", + "LOCATION": "cache:11211", + } +} + +INSTALLED_APPS += ( + "debug_toolbar", + "django_extensions", +) + +ZDS_APP["zmd"]["server"] = "http://zmd:27272" +ZDS_APP["visual_changes"] = ["snow"] + +ES_CONNECTIONS["default"]["hosts"] = ["elasticsearch:9200"] + +ZDS_APP["very_top_banner"] = { + "background_color": "#666", + "border_color": "#353535", + "color": "white", + "message": "Version locale (docker)", + "slug": "version-locale", +} diff --git a/zmd.Dockerfile b/zmd.Dockerfile new file mode 100644 index 0000000000..349942bf3d --- /dev/null +++ b/zmd.Dockerfile @@ -0,0 +1,8 @@ +FROM node:14-slim + +COPY zmd/package.json ./package.json + +RUN npm -g install pm2 + +RUN npm install --production +