#
# Cloud CMS Docker Kits
#

The Cloud CMS Docker Kits provide sample files that you can use with Docker and Docker Compose to easily launch
Cloud CMS in a variety of configurations.  These include a basic quickstart as well as more advanced cluster
configurations that you might use in production.

These sample files are production-ready and only serve as a template for understanding how to work with Cloud CMS
and Docker.  Docker is a very configurable technology and proper Docker education and training should be utilized to
configure Cloud CMS and any other containers neede for production purposes.


## License / Support

In order to use the Cloud CMS Docker Kits, you must first be a Cloud CMS subscriber with Docker support.  If you do
not have Docker support as part of your subscription, you may request it by visiting:

    https://www.cloudcms.com/support.html
    
Or by writing directly to support@cloudcms.com.

Subscribers will receive a license key that can be dropped into the Docker configuration ahead of launch.  Docker
will pick up this license key and then start up.

If you do not have a license key, Cloud CMS will fail to start.  If you do have a license key and it expires, then
Cloud CMS will revert to read-only.

Cloud CMS does not provide support for MongoDB and/or Elastic Search.  For technical assistance in configuring
MongoDB replica sets or shards or Elastic Search scale out, please consult those respective communities or
support organizations.


## Prerequisites

The Cloud CMS Docker Kits require that you install and are technically familiar with Docker and Docker Compose.  
Please download and install both.


## Containers

Cloud CMS consists of a multi-tier architecture with the following components:

    - Cloud CMS API
    - Cloud CMS UI
    - Cloud CMS Web Shot (optional)
    - Cloud CMS Virtual Server (optional)

Each of these tiers can run as a single container or as multiple containers configured in a cluster.  Clustering
each tier is generally fairly straightforward and the Kits provided herein aim to assist with understanding how to do 
so.

The docker-compose.yml files provided in the Kits show how one might configure these individual containers to work
together in harmony.  Please use this as a template for your own Docker configurations.

The "webshot" and "virtual" servers are not required.  They handle web page screenshot capture and virtualized hosting
for multi-tenant applications, respectively.

In addition, Cloud CMS requires two additional containers in order to work:

    - MongoDB
    - Elasticsearch

The images backing these containers are -not- produced by Cloud CMS.  Rather, this kit uses the official Docker
images produced by MongoDB and Elastic.io.

These are connected like this:

              |                       |               |
              |-->        UI        --|-->          --|--> Mongo DB
    browser --|-->     Web Shot     --|-->   API    --|
              |-->  Virtual Server  --|-->          --|--> Elastic Search
              |                       |               |

In a production environment, each tier (ui, webshot, virtual, api, mongodb, elasticsearch) has it's own
cluster and is configured according to its throughput needs.  For example, you may run MongoDB in a sharded
configuration and run the API in a cluster of 4 containers.

In development environments, a single container is typically launched for each tier.  


## Kits

The following kits are provided:

1. quickstart - launches Cloud CMS on a single host
2. oem - development installation for oem partners who are building custom API java beans or UI components
3. api-cluster - an example of how to cluster the API servers using a load balancer
4. api-cluster-workers - extends the api-cluster sample with worker API processes
5. api-worker - launches Cloud CMS on a single host with a dedicated worker API process


## "quickstart"

The best way to get started is to look at the "quickstart" Kit in the /quickstart directory.  This provides a sample 
configuration for running on a single host. 

By default, the docker-compose.yml file will launch in a minimal container configuration that includes only the
following containers:

- api-server
- cloudcms-ui-server

If you wish to launch with the "virtual" and "webshot" servers as well, you can utilize this file:

    docker-compose-full.yml
    
Simply append "-f docker-compose-full.yml" to all of your commands, for example:

    docker-compose -f docker-compose-full.yml up -d


### Install your License File

The license file that you receive from Cloud CMS support will end with .lic.  Drop this file into the
following path:

    ./api/classes/gitana/license
    
    
### Adjust your Admin password

It is generally advisable that you change your root "admin" user's password.  You can do so by editing

    ./api/classes/gitana/custom-docker.properties

The default password is "admin".


### Docker Compose

All of the examples provided in this kit utilize Docker Compose.  Docker Compose is a command line tool that makes it
easy to launch complex, multi-container applications based on a recipe (a docker-compose.yml file).

The kit provides several examples or recipes that you can either use straight away or customize for your own application
purposes.  Most of the time, you will want to look to these recipes as a starting point.  What we provide here is
meant to be interesting and useful and you will generally want to use these as a reference for your own Docker
configurations.

Everything provided in our sample docker-compose.yml files consist of standard Docker file configuration syntax.

### Docker Compose Commands

In case you're not a Docker Compose ninja, we provide here an overview of some sample commands you can use to
work with Docker Compose.

#### Build your Images

Foremost, you will want to build the Docker images for your chosen example.  The examples use the "build" keyword to
define custom images that build on top of the standard and formally released Cloud CMS images.  A build step is thus
necessary to prep these images.

    docker-compose build

You should do this build step every time you make changes to the configuration files within the subdirectories.
Docker Compose will do its best to optimize the build process.  However, if you ever need to have Docker really build
up from scratch, you can do so like this:

    docker-compose build --force-rm

#### Manage your Infrastructure

The "up" command will instantiate Docker containers for all of your images and wire them up to go.  This will also
create any volumes and network bindings for your containers.  Running this command will bind your containers to their
respective ports.

    docker-compose up -d
    
Docker Compose will bring your containers online in the background as a detached process (using the -d option).      

The "stop" command will stop the containers, releasing the ports they are bound to.  Your containers are not deleted,
they are merely stopped.

    docker-compose stop
    
You can also stop a specific container for a given service:

    docker-compose stop <serviceName>
    
The "start" command will start the containers again, binding to the ports once more:

    docker-compose start
    
You can also start a specific service:

    docker-compose start <serviceName>
    
And the "restart" command can be used to stop and start all at once:

    docker-compose restart
    
Or restart a specific container for a given serviec:

    docker-compose restart <serviceName>
    
The "down" command will stop your containers and delete them.  This will free up allocated disk space within Docker itself.
If you bring your environment up again, all of the containers will be re-created.  Also, if Docker created the volumes to
back your containers, those volumes will be deleted automatically.

    docker-compose down
    
To force teardown of any volume data:

    docker-compose down --volumes
    
And to absolutely go all in and tear down everything related to anything in the Docker Compose recipe:

    docker-compose kill

#### Watch the Logs

To tail the logs for all service containers:

    docker-compose logs -f

To tail the logs for a specific service:
    
    docker-compose logs -f <serviceName>

#### Bash into a Running Container

You may at times wish to bash (shell) into a running container for a given service:

    docker-compose exec --privileged <serviceName> bash

### Example: Getting Started

To get started, you can do:

    docker-compose build
    docker-compose up -d

And then watch the logs:

    docker-compose logs -f

This will result in a lot of data.  In general, on startup, you'll want to watch the API.
To do so, you could run something like this:

    docker-compose logs -f api

#### User Interface

Once started, you will be able to login as admin/admin here:

    http://localhost
    
You can change the admin password in the api/custom-docker.properties file.


#### API Access

The API comes online on port 8080.  You can access it here:

    http://localhost:8080
    
If you wish to test manual authentication with a known client and username/password API key set, you can do that here:

    http://localhost:8080/login

    
#### Web Shot Server

The Web Shot server is used by Cloud CMS to take snapshots of web pages.  You can utilize it like this:

    http://localhost:8081/snapshot?url=http://www.cnn.com
    
This server also support more advanced operations for capturing DOM elements and rendering HTML fragments.


#### Virtual Server

The Virtual hosting server is used by Cloud CMS to dynamically host web applications that run on top of the Cloud CMS
application server.  You can access it here:

    http://localhost:8082

To fully utilize the virtual server, you must either utilize an Echo DNS or utilize a wildcard CNAME mapping within
your DNS configuration to route *.cloudcms.net (or *.something) addresses into the virtual server.  We recommend
using Amazon's Route 53 service for this.
    
    
#### MongoDB Server

The MongoDB server used by default within this compose file binds to port 27017.


#### Elastic Search Server

The Elastic Search server used by default within this compose file binds to port 9300.


## Developer Notes

### Multiple docker-compose.yml files

In some examples, you may find multiple docker-compose.yml files.  For example, in the "quickstart" example, there is
the default docker-compose.yml file as well as docker-compose-full.yml.  To run Docker Compose with a different
Docker Compose recipe, do this:

    docker-compose -f <dockerComposeFile> [commands]
    
For example, to build images for an alternative Docker Compose file, you might run this:

    docker-compose -f docker-compose-full.yml build

### OEM - Development of UI, Extensions and API

The "oem" Kit provides a docker-compose.yml file that you can use for the development of Cloud CMS plugins, extensions 
or API code.  This is primarily intended for use by Cloud CMS internal staff developers as well as partners or SI's 
who are working on Cloud CMS features.

This requires that you run your Docker containers locally.  This is because it uses a local volume
mapping so that your changes can be made on your laptop and picked up right away.

In the docker-compose.yml file, you'll see that the UI Server has it's current directory mapped to:

    ~/projects/cloudcms-ui-server

Which is an assumed location on local disk where you have Cloud CMS UI Server source code checked out.
If not, feel free to edit the file to adjust this location.

You can then bring your containers up and they'll launch with your local code in place:

    docker-compose up -d
    
Note that the ui.env file for the Cloud CMS UI Server is set up so that NODE_ENV=development.  This launches the
UI Server in development mode.

A similar volume mapping is in place within docker-compose.yml for the API Server's ROOT.war file:

    - ~/projects/gitana/gitana-webapp-rest-docker/target/gitana-webapp-rest-docker-1.0.0-SNAPSHOT.war:/opt/tomcat/webapps/ROOT.war


## Docker Machine - Local Virtualbox Host

With Docker Machine, you can create your own virtual box instances on Mac and Windows.  Each virtual box instance runs
Linux and can be used to host your Cloud CMS environments inside of the virtual box instance of within your OS.  This
frees up your "physical" ports and also allows you to run multiple Cloud CMS environments at once.

This creates a new Docker Machine locally and launches Cloud CMS within it.

1.  Create the Docker Machine (test1)

    docker-machine create --driver virtualbox test1
        
2.  Make the "test1" Docker Machine active

    eval $(docker-machine env test1)
    
3.  Launch Cloud CMS within the Docker Machine    
    
    docker-compose build
    docker-compose up -d
    
4.  Watch the API logs and wait for the API to finish booting up

    docker-compose logs -f api
    
5.  Once the API starts, look up the IP address of your Docker Machine:
    
    docker-machine ls

6.  Open a web browser to the IP address of the Docker Machine (port 80):

    http://<ipAddress>
    

## Docker Machine - Amazon AWS EC2 Host

You can also use Docker Machine to host your Cloud CMS environments within an EC2 instance.
This is identical to a locally running machine except the machine will run on a new EC2 instance.

This requires you set up an ~/.aws/credentials file first.  See:
https://docs.docker.com/machine/drivers/aws/

Commands:

    docker-machine -D create \
        --driver amazonec2 \
        --amazonec2-vpc-id <vpcId> \
        --amazonec2-zone c \
        --amazonec2-instance-type m3.large \
        test5
        
    eval $(docker-machine env test5)
    docker-compose build
    docker-compose up -d
    
Then wait for the API to start up:

    docker-compose logs -f api

Once it starts, you can find the IP address of the docker machine like this:

    docker-machine ls
    
Open a web browser to:

    http://<ipAddress>

In this case, make sure that the AWS security group for your instance has port 80 open to the outside world.
If you run into trouble, make sure your VPC has a subnet and that the VPC also has an internet gateway defined for it.
Make sure that a route exists for the VPC and that the route maps 0.0.0.0/0 to the internet gateway.
    
As per:
    https://github.com/docker/machine/issues/964#issuecomment-124059808
        
        
## Virtual Server and Echo DNS

The Cloud CMS Virtual Server is a Node server that runs on port 8082 and is designed to pay attention to wildcard
domains that come in.  For example, one request might arrive from domain abc.mycompany.net and another request might
arrive from def.mycompany.net.  When these requests arrive, the virtual server will contact Cloud CMS to retrieve the
gitana.json to use for that respective domain name.

Cloud CMS API allows you to map domain names to API keys (client / auth grants).  Whenever you create a new Application
within Cloud CMS, these mappings can be created for you automatically.  Your application can be bound to a deployed
host domain (such as def.mycompany.net).

In this way, a single Cloud CMS Virtual Server instance can serve back multiple web sites or custom APIs with each
request virtualizing into it's own storage space and using it's own separate and isolated set of API keys.

To use this, you must set things up so that *.sample.net will route to your virtual server.

In a production usage sense, this is pretty easy to do.  You simply set up your DNS so that all subdomains route to
a common, public hosted server (the virtual server).

In development, this is trickier since your laptop isn't on a public IP nor would you want to configure a DNS record
to route requests publically to your laptop.  Instead, the answer is to use an Echo DNS service.

We recommend Echo IP DNS which you can set up like this:

1.  Install Echo IP DNS by running:

    sudo npm install -g echoipdns
    
2.  In a separate terminal window, start up Echo IP DNS like this:

    sudo echoipdns mycompany.net
     
When Echo IP DNS is running, any browser requests to <code>*.mycompany.net</code> will route to your virtual server.
If you press CTRL-C to break out, your DNS settings will restore to normal.

Note that the Echo IP DNS server redirects matching requests to 127.0.0.1 by default.  You will need to either have
your Docker port match here (port 80) on Linux.  If you're using a Mac, you'll need to have an Apache server or
similar running on port 80 on localhost that proxies to your Docker host.


## Load Balancing

One or more of the kits uses a load balancer called HAProxy to distribute requests either at the UI and/or the API
level to one or more downstream servers.  HAProxy is very powerful and can be configured a million different ways
to do many things.

For more information on HAProxy, see:
https://serversforhackers.com/load-balancing-with-haproxy


## ActiveMQ

For typical production deplyoments, you will configure a message broker between the Cloud CMS API and any front-end
applications to allow cache invalidation messages to propagate from the back-end to the front-end.  Cloud CMS production
installations typically use Amazon SNS and Amazon SQS to achieve this.  However, you can use other message brokers
and the some cases (such as Quick Start), we've configured Apache ActiveMQ to serve as this message broker.

To enable ActiveMQ in QuickStart -

1. In the API, include the classes/gitana/distributions/cloudcms-docker-context.xml file and its respective XML block.  You will also need to define ActiveMQ properties in docker.properties.
2. In the UI, make sure to include the following in ui.env:

CLOUDCMS_NOTIFICATIONS_STOMP_HOST=activemq
CLOUDCMS_NOTIFICATIONS_STOMP_PORT=61613
CLOUDCMS_NOTIFICATIONS_STOMP_USERNAME=
CLOUDCMS_NOTIFICATIONS_STOMP_PASSWORD=
CLOUDCMS_NOTIFICATIONS_STOMP_QUEUE_URL=/queue/cloudcms.ui.queue

Note that 61613 is the STOMP port (which is the communication protocol used).

For reference, the ActiveMQ administration console is accessible here:

http://localhost:8161/admin
(username: admin, password: admin)


## Getting Help

If you're using these Cloud CMS Kits, then you must have a Cloud CMS support subscription in place.  As such,
any questions you have may be sent to support@cloudcms.com.  Please contact us with any issues and we will be happy
to assist you.

