mirror of
https://github.com/senaite/senaite.docker.git
synced 2024-09-20 06:56:03 +08:00
Added v2.1.0
This commit is contained in:
parent
f44e8c338e
commit
6bc1a60677
70
2.1.0/Dockerfile
Normal file
70
2.1.0/Dockerfile
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Use an official Python runtime as a parent image
|
||||
FROM python:2.7-stretch
|
||||
|
||||
# Set one or more individual labels
|
||||
LABEL maintainer="Ramon Bartl"
|
||||
LABEL email="rb@ridingbytes.com"
|
||||
LABEL senaite.core.version="2.1.0"
|
||||
|
||||
# Set environment variables
|
||||
ENV PLONE_MAJOR=5.2 \
|
||||
PLONE_VERSION=5.2.6 \
|
||||
PLONE_MD5=51613c5271064bea1bf6d10aa1fec58c \
|
||||
PLONE_UNIFIED_INSTALLER=Plone-5.2.6-UnifiedInstaller-1.0 \
|
||||
SENAITE_HOME=/home/senaite \
|
||||
SENAITE_USER=senaite \
|
||||
SENAITE_INSTANCE_HOME=/home/senaite/senaitelims \
|
||||
SENAITE_DATA=/data \
|
||||
SENAITE_FILESTORAGE=/data/filestorage \
|
||||
SENAITE_BLOBSTORAGE=/data/blobstorage
|
||||
|
||||
# Create the senaite user
|
||||
RUN useradd --system -m -d $SENAITE_HOME -U -u 500 $SENAITE_USER
|
||||
|
||||
# Create direcotries
|
||||
RUN mkdir -p $SENAITE_INSTANCE_HOME $SENAITE_FILESTORAGE $SENAITE_BLOBSTORAGE
|
||||
|
||||
# Copy the package config
|
||||
COPY packages.txt /
|
||||
|
||||
# Install package dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends $(grep -vE "^\s*#" /packages.txt | tr "\n" " ")
|
||||
|
||||
# Fetch unified installer
|
||||
RUN wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/$PLONE_UNIFIED_INSTALLER.tgz \
|
||||
&& echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \
|
||||
&& tar -xzf Plone.tgz \
|
||||
&& cp -rv /$PLONE_UNIFIED_INSTALLER/base_skeleton/* $SENAITE_INSTANCE_HOME \
|
||||
&& cp -v /$PLONE_UNIFIED_INSTALLER/buildout_templates/buildout.cfg $SENAITE_INSTANCE_HOME/buildout-base.cfg \
|
||||
&& cd $SENAITE_HOME \
|
||||
&& rm -rf /$PLONE_UNIFIED_INSTALLER /Plone.tgz
|
||||
|
||||
# Change working directory
|
||||
WORKDIR $SENAITE_INSTANCE_HOME
|
||||
|
||||
# Copy Buildout
|
||||
COPY requirements.txt buildout.cfg ./
|
||||
|
||||
# Buildout
|
||||
RUN pip install -r requirements.txt \
|
||||
&& buildout \
|
||||
&& ln -s $SENAITE_FILESTORAGE/ var/filestorage \
|
||||
&& ln -s $SENAITE_BLOBSTORAGE/ var/blobstorage \
|
||||
&& chown -R senaite:senaite $SENAITE_HOME $SENAITE_DATA
|
||||
|
||||
# Mount external volume
|
||||
VOLUME /data
|
||||
|
||||
# Copy startup scripts
|
||||
COPY docker-initialize.py docker-entrypoint.sh /
|
||||
|
||||
# Expose instance port
|
||||
EXPOSE 8080
|
||||
|
||||
# REMOVED: https://github.com/senaite/senaite.docker/issues/4
|
||||
# Add instance healthcheck
|
||||
# HEALTHCHECK --interval=1m --timeout=5s --start-period=1m \
|
||||
# CMD nc -z -w5 127.0.0.1 8080 || exit 1
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["start"]
|
52
2.1.0/buildout.cfg
Normal file
52
2.1.0/buildout.cfg
Normal file
|
@ -0,0 +1,52 @@
|
|||
[buildout]
|
||||
extends =
|
||||
buildout-base.cfg
|
||||
https://dist.plone.org/release/5.2.6/versions.cfg
|
||||
find-links +=
|
||||
https://dist.plone.org/release/5.2.6/
|
||||
https://dist.plone.org/thirdparty/
|
||||
|
||||
extensions =
|
||||
|
||||
index = https://pypi.python.org/simple/
|
||||
|
||||
var-dir=/data
|
||||
user=admin:admin
|
||||
|
||||
effective-user = senaite
|
||||
buildout-user = senaite
|
||||
|
||||
eggs-directory=../buildout-cache/eggs
|
||||
download-cache=../buildout-cache/downloads
|
||||
|
||||
parts +=
|
||||
zeo
|
||||
plonesite
|
||||
|
||||
|
||||
eggs +=
|
||||
senaite.lims
|
||||
|
||||
[client1]
|
||||
recipe =
|
||||
|
||||
[zeo]
|
||||
<= zeoserver_base
|
||||
recipe = plone.recipe.zeoserver
|
||||
zeo-address = 8080
|
||||
|
||||
[plonesite]
|
||||
recipe = collective.recipe.plonesite
|
||||
instance = instance
|
||||
site-id = senaite
|
||||
profiles-initial = Products.CMFPlone:dependencies
|
||||
profiles =
|
||||
senaite.lims:default
|
||||
upgrade-portal = False
|
||||
upgrade-all-profiles = False
|
||||
enabled = False
|
||||
|
||||
[versions]
|
||||
setuptools=42.0.2
|
||||
zc.buildout=2.13.3
|
||||
senaite.lims=2.1.0
|
11
2.1.0/docker-compose.yml
Normal file
11
2.1.0/docker-compose.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
version: "2"
|
||||
services:
|
||||
senaite:
|
||||
image: senaite
|
||||
volumes:
|
||||
- data:/data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
||||
volumes:
|
||||
data:
|
41
2.1.0/docker-entrypoint.sh
Executable file
41
2.1.0/docker-entrypoint.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
COMMANDS="adduser debug fg foreground help kill logreopen logtail reopen_transcript run show status stop wait"
|
||||
START="console start restart"
|
||||
|
||||
# Fixing permissions for external /data volumes
|
||||
mkdir -p /data/blobstorage /data/cache /data/filestorage /data/instance /data/log /data/zeoserver
|
||||
mkdir -p /home/senaite/senaitelims/src
|
||||
find /data -not -user senaite -exec chown senaite:senaite {} \+
|
||||
find /home/senaite -not -user senaite -exec chown senaite:senaite {} \+
|
||||
|
||||
# Initializing from environment variables
|
||||
gosu senaite python /docker-initialize.py
|
||||
|
||||
if [ -e "custom.cfg" ]; then
|
||||
if [ ! -e "bin/develop" ]; then
|
||||
buildout -c custom.cfg
|
||||
find /data -not -user senaite -exec chown senaite:senaite {} \+
|
||||
find /home/senaite -not -user senaite -exec chown senaite:senaite {} \+
|
||||
gosu senaite python /docker-initialize.py
|
||||
fi
|
||||
fi
|
||||
|
||||
# ZEO Server
|
||||
if [[ "$1" == "zeo"* ]]; then
|
||||
exec gosu senaite bin/$1 fg
|
||||
fi
|
||||
|
||||
# Instance start
|
||||
if [[ $START == *"$1"* ]]; then
|
||||
exec gosu senaite bin/instance console
|
||||
fi
|
||||
|
||||
# Instance helpers
|
||||
if [[ $COMMANDS == *"$1"* ]]; then
|
||||
exec gosu senaite bin/instance "$@"
|
||||
fi
|
||||
|
||||
# Custom
|
||||
exec "$@"
|
265
2.1.0/docker-initialize.py
Executable file
265
2.1.0/docker-initialize.py
Executable file
|
@ -0,0 +1,265 @@
|
|||
#!/usr/local/bin/python
|
||||
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
class Environment(object):
|
||||
""" Configure container via environment variables
|
||||
"""
|
||||
def __init__(
|
||||
self, env=os.environ,
|
||||
zope_conf="/home/senaite/senaitelims/parts/instance/etc/zope.conf",
|
||||
custom_conf="/home/senaite/senaitelims/custom.cfg",
|
||||
zeopack_conf="/home/senaite/senaitelims/bin/zeopack",
|
||||
zeoserver_conf="/home/senaite/senaitelims/parts/zeoserver/etc/zeo.conf",
|
||||
cors_conf="/home/senaite/senaitelims/parts/instance/etc/package-includes/999-additional-overrides.zcml"
|
||||
):
|
||||
self.env = env
|
||||
self.zope_conf = zope_conf
|
||||
self.custom_conf = custom_conf
|
||||
self.zeopack_conf = zeopack_conf
|
||||
self.zeoserver_conf = zeoserver_conf
|
||||
self.cors_conf = cors_conf
|
||||
|
||||
def zeoclient(self):
|
||||
""" ZEO Client
|
||||
"""
|
||||
server = self.env.get("ZEO_ADDRESS", None)
|
||||
if not server:
|
||||
return
|
||||
|
||||
config = ""
|
||||
with open(self.zope_conf, "r") as cfile:
|
||||
config = cfile.read()
|
||||
|
||||
# Already initialized
|
||||
if "<blobstorage>" not in config:
|
||||
return
|
||||
|
||||
read_only = self.env.get("ZEO_READ_ONLY", "false")
|
||||
zeo_ro_fallback = self.env.get("ZEO_CLIENT_READ_ONLY_FALLBACK", "false")
|
||||
shared_blob_dir = self.env.get("ZEO_SHARED_BLOB_DIR", "off")
|
||||
zeo_storage = self.env.get("ZEO_STORAGE", "1")
|
||||
zeo_client_cache_size = self.env.get("ZEO_CLIENT_CACHE_SIZE", "128MB")
|
||||
zeo_conf = ZEO_TEMPLATE.format(
|
||||
zeo_address=server,
|
||||
read_only=read_only,
|
||||
zeo_client_read_only_fallback=zeo_ro_fallback,
|
||||
shared_blob_dir=shared_blob_dir,
|
||||
zeo_storage=zeo_storage,
|
||||
zeo_client_cache_size=zeo_client_cache_size
|
||||
)
|
||||
|
||||
pattern = re.compile(r"<blobstorage>.+</blobstorage>", re.DOTALL)
|
||||
config = re.sub(pattern, zeo_conf, config)
|
||||
|
||||
with open(self.zope_conf, "w") as cfile:
|
||||
cfile.write(config)
|
||||
|
||||
def zeopack(self):
|
||||
""" ZEO Pack
|
||||
"""
|
||||
server = self.env.get("ZEO_ADDRESS", None)
|
||||
if not server:
|
||||
return
|
||||
|
||||
if ":" in server:
|
||||
host, port = server.split(":")
|
||||
else:
|
||||
host, port = (server, "8100")
|
||||
|
||||
with open(self.zeopack_conf, 'r') as cfile:
|
||||
text = cfile.read()
|
||||
text = text.replace('address = "8100"', 'address = "%s"' % server)
|
||||
text = text.replace('host = "127.0.0.1"', 'host = "%s"' % host)
|
||||
text = text.replace('port = "8100"', 'port = "%s"' % port)
|
||||
|
||||
with open(self.zeopack_conf, 'w') as cfile:
|
||||
cfile.write(text)
|
||||
|
||||
def zeoserver(self):
|
||||
""" ZEO Server
|
||||
"""
|
||||
pack_keep_old = self.env.get("ZEO_PACK_KEEP_OLD", '')
|
||||
if pack_keep_old.lower() in ("false", "no", "0", "n", "f"):
|
||||
with open(self.zeoserver_conf, 'r') as cfile:
|
||||
text = cfile.read()
|
||||
if 'pack-keep-old' not in text:
|
||||
text = text.replace(
|
||||
'</filestorage>',
|
||||
' pack-keep-old false\n</filestorage>'
|
||||
)
|
||||
|
||||
with open(self.zeoserver_conf, 'w') as cfile:
|
||||
cfile.write(text)
|
||||
|
||||
def cors(self):
|
||||
""" Configure CORS Policies
|
||||
"""
|
||||
if not [e for e in self.env if e.startswith("CORS_")]:
|
||||
return
|
||||
|
||||
allow_origin = self.env.get("CORS_ALLOW_ORIGIN",
|
||||
"http://localhost:3000,http://127.0.0.1:3000")
|
||||
allow_methods = self.env.get("CORS_ALLOW_METHODS",
|
||||
"DELETE,GET,OPTIONS,PATCH,POST,PUT")
|
||||
allow_credentials = self.env.get("CORS_ALLOW_CREDENTIALS", "true")
|
||||
expose_headers = self.env.get("CORS_EXPOSE_HEADERS",
|
||||
"Content-Length,X-My-Header")
|
||||
allow_headers = self.env.get("CORS_ALLOW_HEADERS",
|
||||
"Accept,Authorization,Content-Type,X-Custom-Header")
|
||||
max_age = self.env.get("CORS_MAX_AGE", "3600")
|
||||
cors_conf = CORS_TEMPLACE.format(
|
||||
allow_origin=allow_origin,
|
||||
allow_methods=allow_methods,
|
||||
allow_credentials=allow_credentials,
|
||||
expose_headers=expose_headers,
|
||||
allow_headers=allow_headers,
|
||||
max_age=max_age
|
||||
)
|
||||
with open(self.cors_conf, "w") as cfile:
|
||||
cfile.write(cors_conf)
|
||||
|
||||
def buildout(self):
|
||||
""" Buildout from environment variables
|
||||
"""
|
||||
# Already configured
|
||||
if os.path.exists(self.custom_conf):
|
||||
return
|
||||
|
||||
findlinks = self.env.get("FIND_LINKS", "").strip().split()
|
||||
|
||||
eggs = self.env.get("PLONE_ADDONS",
|
||||
self.env.get("ADDONS", "")).strip().split()
|
||||
|
||||
zcml = self.env.get("PLONE_ZCML",
|
||||
self.env.get("ZCML", "")).strip().split()
|
||||
|
||||
develop = self.env.get("PLONE_DEVELOP",
|
||||
self.env.get("DEVELOP", "")).strip().split()
|
||||
|
||||
site = self.env.get("PLONE_SITE",
|
||||
self.env.get("SITE", "")).strip()
|
||||
|
||||
profiles = self.env.get("PLONE_PROFILES",
|
||||
self.env.get("PROFILES", "")).strip().split()
|
||||
|
||||
versions = self.env.get("PLONE_VERSIONS",
|
||||
self.env.get("VERSIONS", "")).strip().split()
|
||||
|
||||
sources = self.env.get("SOURCES", "").strip().split(",")
|
||||
|
||||
# If profiles not provided. Install ADDONS :default profiles
|
||||
if not profiles:
|
||||
for egg in eggs:
|
||||
base = egg.split("=")[0]
|
||||
profiles.append("%s:default" % base)
|
||||
|
||||
enabled = bool(site)
|
||||
if not (eggs or zcml or develop or enabled):
|
||||
return
|
||||
|
||||
buildout = BUILDOUT_TEMPLATE.format(
|
||||
findlinks="\n\t".join(findlinks),
|
||||
eggs="\n\t".join(eggs),
|
||||
zcml="\n\t".join(zcml),
|
||||
develop="\n\t".join(develop),
|
||||
profiles="\n\t".join(profiles),
|
||||
versions="\n".join(versions),
|
||||
sources="\n".join(sources),
|
||||
site=site or "senaite",
|
||||
enabled=enabled,
|
||||
)
|
||||
|
||||
# If we need to create a senaitesite and we have a zeo setup
|
||||
# configure collective.recipe.senaitesite properly
|
||||
server = self.env.get("ZEO_ADDRESS", None)
|
||||
if server:
|
||||
buildout += ZEO_INSTANCE_TEMPLATE.format(
|
||||
zeoaddress=server,
|
||||
)
|
||||
|
||||
with open(self.custom_conf, 'w') as cfile:
|
||||
cfile.write(buildout)
|
||||
|
||||
def setup(self, **kwargs):
|
||||
self.buildout()
|
||||
self.cors()
|
||||
self.zeoclient()
|
||||
self.zeopack()
|
||||
self.zeoserver()
|
||||
|
||||
__call__ = setup
|
||||
|
||||
|
||||
ZEO_TEMPLATE = """
|
||||
<zeoclient>
|
||||
read-only {read_only}
|
||||
read-only-fallback {zeo_client_read_only_fallback}
|
||||
blob-dir /data/blobstorage
|
||||
shared-blob-dir {shared_blob_dir}
|
||||
server {zeo_address}
|
||||
storage {zeo_storage}
|
||||
name zeostorage
|
||||
var /home/senaite/senaitelims/parts/instance/var
|
||||
cache-size {zeo_client_cache_size}
|
||||
</zeoclient>
|
||||
""".strip()
|
||||
|
||||
CORS_TEMPLACE = """<configure
|
||||
xmlns="http://namespaces.zope.org/zope">
|
||||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:plone="http://namespaces.plone.org/plone">
|
||||
<plone:CORSPolicy
|
||||
allow_origin="{allow_origin}"
|
||||
allow_methods="{allow_methods}"
|
||||
allow_credentials="{allow_credentials}"
|
||||
expose_headers="{expose_headers}"
|
||||
allow_headers="{allow_headers}"
|
||||
max_age="{max_age}"
|
||||
/>
|
||||
</configure>
|
||||
</configure>
|
||||
"""
|
||||
|
||||
BUILDOUT_TEMPLATE = """
|
||||
[buildout]
|
||||
extends = develop.cfg
|
||||
find-links += {findlinks}
|
||||
develop += {develop}
|
||||
eggs += {eggs}
|
||||
zcml += {zcml}
|
||||
|
||||
[plonesite]
|
||||
enabled = {enabled}
|
||||
site-id = {site}
|
||||
profiles += {profiles}
|
||||
|
||||
[versions]
|
||||
{versions}
|
||||
|
||||
[sources]
|
||||
{sources}
|
||||
"""
|
||||
|
||||
ZEO_INSTANCE_TEMPLATE = """
|
||||
|
||||
[instance]
|
||||
zeo-client = true
|
||||
zeo-address = {zeoaddress}
|
||||
shared-blob = off
|
||||
http-fast-listen = off
|
||||
"""
|
||||
|
||||
|
||||
def initialize():
|
||||
""" Configure Instance as ZEO Client
|
||||
"""
|
||||
environment = Environment()
|
||||
environment.setup()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
initialize()
|
28
2.1.0/packages.txt
Normal file
28
2.1.0/packages.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
dpkg-dev
|
||||
gcc
|
||||
gosu
|
||||
libbz2-dev
|
||||
libc6-dev
|
||||
libcairo2
|
||||
libffi-dev
|
||||
libgdk-pixbuf2.0-0
|
||||
libjpeg62
|
||||
libjpeg62-turbo-dev
|
||||
libopenjp2-7
|
||||
libopenjp2-7-dev
|
||||
libpango-1.0-0
|
||||
libpangocairo-1.0-0
|
||||
libpcre3-dev
|
||||
libssl-dev
|
||||
libtiff5
|
||||
libtiff5-dev
|
||||
libxml2
|
||||
libxml2-dev
|
||||
libxslt1-dev
|
||||
libxslt1.1
|
||||
lynx
|
||||
netcat
|
||||
rsync
|
||||
wget
|
||||
wv
|
||||
zlib1g-dev
|
3
2.1.0/requirements.txt
Normal file
3
2.1.0/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
setuptools==42.0.2
|
||||
zc.buildout==2.13.3
|
||||
wheel
|
26
README.md
26
README.md
|
@ -32,7 +32,7 @@ Build and start the latest SENAITE container, based on [Debian](https://www.debi
|
|||
|
||||
```bash
|
||||
$ git clone https://github.com/senaite/senaite.docker
|
||||
$ cd senaite.docker/1.3.3
|
||||
$ cd senaite.docker/2.1.0
|
||||
$ docker build -t senaite .
|
||||
$ docker run --rm --name senaite -p 8080:8080 senaite
|
||||
```
|
||||
|
@ -124,16 +124,16 @@ image on docker hub.
|
|||
Copy an existing version structure:
|
||||
|
||||
```console
|
||||
$ cp -r 1.3.2 1.3.3
|
||||
$ cd 1.3.3
|
||||
$ docker build --tag=senaite:v1.3.3 .
|
||||
$ cp -r 2.0.0 2.1.0
|
||||
$ cd 2.1.0
|
||||
$ docker build --tag=senaite:v2.1.0 .
|
||||
|
||||
[...]
|
||||
Successfully built 7af3395db8f6
|
||||
Successfully tagged senaite:v1.3.3
|
||||
Successfully tagged senaite:v2.1.0
|
||||
```
|
||||
|
||||
Note that the the image will automatically tagged as `v1.3.3`.
|
||||
Note that the the image will automatically tagged as `v2.1.0`.
|
||||
|
||||
|
||||
### Run the container
|
||||
|
@ -141,7 +141,7 @@ Note that the the image will automatically tagged as `v1.3.3`.
|
|||
Start a container based on your new image:
|
||||
|
||||
```
|
||||
docker container run --publish 9999:8080 --detach --name s133 senaite:v1.3.3
|
||||
docker container run --publish 9999:8080 --detach --name s210 senaite:v2.1.0
|
||||
```
|
||||
|
||||
We used a couple of common flags here:
|
||||
|
@ -161,29 +161,29 @@ We used a couple of common flags here:
|
|||
|
||||
$ docker container ls
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
ecf514d717ba senaite:v1.3.3 "/docker-entrypoint.…" 26 seconds ago Up 24 seconds (health: starting) 0.0.0.0:9999->8080/tcp s133
|
||||
ecf514d717ba senaite:v2.1.0 "/docker-entrypoint.…" 26 seconds ago Up 24 seconds (health: starting) 0.0.0.0:9999->8080/tcp s210
|
||||
```
|
||||
|
||||
Go to http://localhost:9999 to install senaite.
|
||||
|
||||
Stop the container with `docker container stop s133`.
|
||||
Stop the container with `docker container stop s210`.
|
||||
|
||||
|
||||
### Publish the container on Docker Hub
|
||||
|
||||
Images must be namespaced correctly to share on Docker Hub. Specifically, images
|
||||
must be named like `<Docker Hub ID>/<Repository Name>:<tag>.` We can relabel our
|
||||
`senaite:1.3.3` image like this:
|
||||
`senaite:2.1.0` image like this:
|
||||
|
||||
```console
|
||||
$ docker image tag senaite:v1.3.3 ramonski/senaite:v1.3.3
|
||||
$ docker image tag senaite:v1.3.3 ramonski/senaite:latest
|
||||
$ docker image tag senaite:v2.1.0 ramonski/senaite:v2.1.0
|
||||
$ docker image tag senaite:v2.1.0 ramonski/senaite:latest
|
||||
```
|
||||
|
||||
Finally, push the image to Docker Hub:
|
||||
|
||||
```console
|
||||
docker image push ramonski/senaite:v1.3.3
|
||||
docker image push ramonski/senaite:v2.1.0
|
||||
docker image push ramonski/senaite:latest
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in a new issue