Skip to content
This repository was archived by the owner on Feb 13, 2020. It is now read-only.

Docker for production #513

Open
wants to merge 21 commits into
base: release/CalendarServer-9.3-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
*.egg-info/
*.o
*.py[co]
*.so
_trial_temp*/
build/
dropin.cache
*~
*.lock
.git
.gitignore
.gitmodules
*.pyc
.develop/
data/
bin/calendarserver_*
calendarserver/version.py
conf/caldavd-dev.plist
subprojects/
_run/

# Otherwise any change to the Dockerfile itself means a complete rebuild
Dockerfile
72 changes: 72 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
FROM ubuntu:16.04

LABEL maintainer = "[email protected]" \
io.openshift.tags = caldavd,ccs \
io.openshift.wants = memcached,postgres \
io.k8s.description = "Calendar and Contacts Server is a CalDAV implementation" \
io.openshift.expose-services = 8080:http

# Straight from CCS GitHub install guide
# except for gettext-base, which we need for "envsubst"
RUN apt-get update && \
apt-get -y install \
build-essential \
curl \
gettext-base \
git \
libffi-dev \
libkrb5-dev \
libldap2-dev \
libreadline6-dev \
libsasl2-dev \
libssl-dev \
python-dev \
python-pip \
python-setuptools \
zlib1g-dev

# All of the source code is in here
ADD . /home/ccs

WORKDIR /home/ccs

# Dependencies are retrieved and CCS installed in /usr/local
RUN pip install -r requirements-default.txt

# Create all runtime directories and ensure right permissions for OC
RUN mkdir -p /var/db/caldavd \
/var/log/caldavd \
/var/run/caldavd \
/etc/caldavd && \
chmod -R g+rwX /home/ccs \
/var/db/caldavd \
/var/log/caldavd \
/var/run/caldavd \
/etc/caldavd && \
chmod g=u /etc/passwd

# TODO Check if everything is in this dir
VOLUME [ "/var/db/caldavd" ]

# For user defined complex configuration (e.g. accounts.xml, resources.xml)
# A configuration file can be placed at /etc/caldavd/caldavd.ext.plist
VOLUME [ "/etc/caldavd" ]

# This can be edited in docker/caldavd.plist.template > HTTPPort
EXPOSE 8080

# Some sensible defaults for config
ENV POSTGRES_HOST tcp:postgres:5432
ENV POSTGRES_DB postgres
ENV POSTGRES_USER postgres
ENV POSTGRES_PASS password
ENV MEMCACHED_HOST memcached
ENV MEMCACHED_PORT 11211

# To avoid errors with OpenShift, could be any
USER 1000

# This entry point simply creates /tmp/caldavd.plist,
# using the given ENV as placeholders
ENTRYPOINT [ "/home/ccs/contrib/docker/docker_entrypoint.sh" ]
CMD [ "caldavd", "-X", "-L", "-f", "/tmp/caldavd.plist" ]
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,16 @@ Start the server using the bin/run script, and use the -n option to bypass depen
Starting server...

The server should then start up and bind to port 8008 for HTTP and 8443 for HTTPS. You should then be able to connect to the server using your web browser (eg. Safari, Firefox) or with a CalDAV client (eg. Calendar).


==========================
Docker
==========================

A Dockerfile is provided to build an image that may be run in production.
An example docker-compose file is provided in contrib/docker.

PostgreSQL and Memcached are required as external services.

Configuration may be altered to make use of an LDAP server,
or XML files, as noted above.
44 changes: 44 additions & 0 deletions contrib/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# CCS dockerised

This container of [Calendar and Contacts Server](https://github.com/apple/ccs-calendarserver/)
is thought to be run in production (in Kubernetes or OpenShift).

It uses `setup.py` and expects external __Postgres__ and __Memcached__.

__Postgres__ schema must be manually defined during the first run,
using [current.sql](https://github.com/apple/ccs-calendarserver/blob/master/txdav/common/datastore/sql_schema/current.sql).

What is being done in our `docker-compose.yml` is adding the SQL file in
`/docker-entrypoint-initdb.d` as suggested
[here](https://hub.docker.com/_/postgres/), at chapter:
*How to extend this image*.

## Running

### Docker Swarm
```bash
$ docker stack deploy -c docker-compose.yml ccs-stack
```

### K8s / OpenShift
__TODO__


## Configuration

Configuration of CCS is done in multiple layers:

1. `caldavd.envsubst.plist`, on which env variable are replaced by `docker_entrypoint.sh`. This takes care of loading:
2. `/etc/caldavd/caldavd.ext.plist`, which may be added via a *VOLUME*, envsubst is __NOT__ applied to this.
3. `/etc/caldavd/caldavd.writable.plist`, as a writable config file is required by CCS.


### XML example
In `contrib/docker/samples/xml` is a sample Docker stack where
XML is used to define accounts.

### LDAP example
__TODO__

In `contrib/docker/samples/ldap` a stack with Apache DS is defined
to test getting resources via LDAP.
187 changes: 187 additions & 0 deletions contrib/docker/caldavd.envsubst.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<!--
Copyright (c) 2006-2017 Apple Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<!--
Docker specific

caldavd.envsubst.plist is substituted at runtime by
/home/ccs/contrib/docker/docker_entrypoint.sh,
and env variables are inserted e.g. in $POSTGRES_HOST.

This file is placed to $CCS_CONF_FILE by the ENTRYPOINT script,
it includes /home/ccs/contrib/docker/caldavd.base.plist
for sensible defaults,
and imports /etc/caldavd/caldavd.ext.plist (mapped to a volume),
for users to override settings.

Do not edit this file directly!
Please add /etc/caldavd/caldavd.ext.plist via volumes instead
-->
<plist version="1.0">
<dict>

<!-- Docker: Must be above 1024 for OpenShift -->
<!-- HTTP port (0 to disable HTTP) -->
<key>HTTPPort</key>
<integer>8080</integer>

<!-- True: database; False: files (deprecated) -->
<key>UseDatabase</key>
<true/>

<!-- Possible values: empty, meaning 'spawn postgres yourself', or 'postgres'
or 'oracle', meaning 'connect to a postgres or Oracle database as
specified by the 'DSN' configuration key. -->
<key>DBType</key>
<string>postgres</string>

<!-- Features supported by the database

'skip-locked': SKIP LOCKED available with SELECT (remove if using postgres
&lt; v9.5) -->
<key>DBFeatures</key>
<array>
<string>skip-locked</string>
</array>

<!-- Set to True to prevent the server or utility tools from running if the
database needs a schema upgrade. -->
<key>FailIfUpgradeNeeded</key>
<true/>

<!-- Set to True to check the current database schema against the schema file
matching the database schema version. -->
<key>CheckExistingSchema</key>
<true/>

<!-- Data store -->

<!-- The top level directory, contains (by default) ConfigRoot and DataRoot -->
<key>ServerRoot</key>
<string>/var/db/caldavd</string>

<!-- Config directory, contains additional config files -->
<key>ConfigRoot</key>
<string>/etc/caldavd</string>

<!-- These three keys are relative to ConfigRoot: -->

<!-- Other plists to parse after this one; note that an Include can change the
ServerRoot and/or ConfigRoot, thereby affecting the locations of the
following Includes in the list. (Useful for service directory relocation) -->
<key>Includes</key>
<array>
<string>/etc/caldavd/caldavd.ext.plist</string>
<string>/etc/caldavd/caldavd.writable.plist</string>
</array>

<!-- Which config file calendarserver_config should write to for changes;
empty string means the main config file -->
<key>WritableConfigFile</key>
<string>/etc/caldavd/caldavd.writable.plist</string>

<!-- Used to connect to an external database if DBType is non-empty -->
<key>DatabaseConnection</key>
<dict>
<!-- Database connection endpoint -->
<key>endpoint</key>
<string>$POSTGRES_HOST</string>
<!-- <string>tcp:postgres:5432</string> -->

<!-- Name of database or Oracle SID -->
<key>database</key>
<string>$POSTGRES_DB</string>
<!-- <string>postgres</string> -->

<!-- User name to connect as -->
<key>user</key>
<string>$POSTGRES_USER</string>
<!-- <string>postgres</string> -->

<!-- Password to use -->
<key>password</key>
<string>$POSTGRES_PASS</string>
<!-- <string>password</string> -->

<!-- Set to True to require SSL (pg8000 only). -->
<key>ssl</key>
<false/>
</dict>

<key>Memcached</key>
<dict>
<key>MaxClients</key>
<integer>5</integer>

<key>Pools</key>
<dict>
<key>Default</key>
<dict>
<!-- A unix socket used for communication with memcached. If MemcacheSocket
is empty string, an AF_INET socket is used. -->
<key>MemcacheSocket</key>
<string></string>

<key>ClientEnabled</key>
<true/>

<!-- The server is handled outside our containers -->
<key>ServerEnabled</key>
<false/>

<key>BindAddress</key>
<string>$MEMCACHED_HOST</string>
<!-- <string>memcached</string> -->

<key>Port</key>
<integer>$MEMCACHED_PORT</integer>
<!-- <integer>11211</integer> -->

<!-- Possible types: "OpenDirectoryBacker", "ImplicitUIDLock",
"RefreshUIDLock", "DIGESTCREDENTIALS", "resourceInfoDB", "pubsubnodes",
"FBCache", "ScheduleAddressMapper", "SQL.props", "SQL.calhome",
"SQL.adbkhome", -->
<key>HandleCacheTypes</key>
<array>
<string>Default</string>
</array>
</dict>

<!-- "Shared": { "ClientEnabled": True, "ServerEnabled": True, "BindAddress":
"127.0.0.1", "Port": 11211, "HandleCacheTypes": [ "ProxyDB",
"DelegatesDB", "PrincipalToken", ] }, -->
</dict>

<!-- Find in PATH -->
<key>memcached</key>
<string>memcached</string>

<!-- Megabytes -->
<key>MaxMemory</key>
<integer>0</integer>

<key>Options</key>
<array>
</array>

<key>ProxyDBKeyNormalization</key>
<true/>
</dict>
</dict>
</plist>
Loading