├── README.md ├── backup ├── Dockerfile ├── README.md └── files │ └── bin │ ├── backup │ ├── entrypoint │ └── restore ├── carina_saas_example ├── .gitignore ├── DOCKERFILE ├── README.md ├── access │ └── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── carina_saas_example │ │ ├── controller │ │ └── ContainerController.java │ │ └── util │ │ └── Utils.java │ └── webapp │ ├── WEB-INF │ └── web.xml │ ├── listcontainer.jsp │ └── newcontainer.jsp ├── cf-backup ├── Dockerfile ├── README.md └── files │ └── bin │ ├── cron-job.sh │ ├── run-rack.sh │ └── start-cron.sh ├── cf-restore ├── Dockerfile ├── README.md └── files │ └── bin │ └── run-rack.sh ├── ci-cd-product ├── Dockerfile └── productws.js ├── ci-cd-watcher ├── Dockerfile ├── README.md └── whwatch.py ├── guestbook-mongo ├── .gitignore ├── Dockerfile ├── README.md ├── app.py ├── requirements.txt └── templates │ └── index.html ├── guestbook-mysql ├── Dockerfile ├── README.md ├── app.py ├── requirements.txt └── templates │ └── index.html ├── guestbook-redis ├── .gitignore ├── Dockerfile ├── README.md ├── app.py ├── requirements.txt └── templates │ └── index.html ├── hello-world-app ├── Dockerfile ├── README.md ├── app.py ├── build └── requirements.txt ├── hello-world-web ├── .gitignore ├── Dockerfile ├── README.md ├── build ├── requirements.txt └── web.py ├── magento ├── Dockerfile ├── docker-compose.yml ├── env ├── install-data.bash └── setup-config.bash ├── nginx-fpm ├── Dockerfile └── wordpress-fpm.conf ├── nginx-proxy ├── Dockerfile └── entrypoint.sh ├── python-web-app ├── .gitignore ├── app │ ├── Dockerfile │ ├── app.py │ ├── requirements.txt │ ├── templates │ │ └── index.html │ └── tests.py ├── db │ ├── Dockerfile │ └── mysql.cnf ├── docker-compose-common.yml ├── docker-compose-prod.yml ├── docker-compose.yml └── lb │ ├── Dockerfile │ └── nginx.conf ├── rails └── Dockerfile ├── try-rails ├── Dockerfile ├── README.md ├── build ├── carina.png └── helloworld.html.erb ├── wordpress ├── Dockerfile ├── entrypoint.sh ├── env └── set-config.php └── znc ├── Dockerfile ├── Dockerfile.mkconf ├── README.md ├── docker-entrypoint.sh └── znc.conf.default /README.md: -------------------------------------------------------------------------------- 1 | # Examples for Carina 2 | 3 | You can find the images built from these examples in the [Carina Marina org](https://hub.docker.com/u/carinamarina/) on hub.docker.com. 4 | -------------------------------------------------------------------------------- /backup/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rackspace/rack:1.1.1 2 | 3 | RUN apk add --update --no-cache bash 4 | 5 | COPY files/bin/ /usr/bin/ 6 | 7 | ENTRYPOINT ["/usr/bin/entrypoint"] 8 | -------------------------------------------------------------------------------- /backup/README.md: -------------------------------------------------------------------------------- 1 | # Back up Container Data 2 | 3 | This image will create an archive file of a single directory in a data volume, and will either upload the archive to a Rackspace Cloud Files container or output the contents of the archive to `stdout`. 4 | 5 | ### Build the image 6 | 7 | ``` 8 | docker build -t carinamarina/backup . 9 | ``` 10 | 11 | ### Usage 12 | 13 | ```bash 14 | docker run [OPTIONS] carinamarina/backup 15 | ``` 16 | 17 | `COMMAND` can be one of `backup` or `restore`. 18 | 19 | `backup` accepts several arguments: 20 | 21 | * `-c, --container` The name of the Cloud Files container in which to store the backup. Ignored if `--stdout` is used. 22 | * `-h, --help` Show help information 23 | * `-s, --source` The source directory for the backup. All files in this directory will be added to the archive. 24 | * `--stdout` Output the archive to stdout instead of uploading it to a Cloud Files container. 25 | * `-z, --zip` Compress the archive using gzip. 26 | 27 | `restore` accepts the following arguments: 28 | 29 | * `-c, --container ` Name of a Cloud Files container 30 | * `-d, --destination ` Restore destination for archive contents 31 | * `-h, --help` Show help information 32 | * `-o, --object ` Name of archive object in a container 33 | * `--stdin` Read from stdin instead of Cloud Files 34 | * `-z, --zip` Use gzip to uncompress archive 35 | 36 | ### Examples 37 | 38 | #### Back up a data volume container to Rackspace Cloud Files 39 | 40 | Assume you've created a container named `mysql-data` with a data volume at `/data`. Also assume that you have set the environment variables `RS_USERNAME`, `RS_API_KEY`, and `RS_REGION_NAME` to your Rackspace username, Rackspace API key, and preferred Rackspace region, respectively. To upload the contents of the data volume to Cloud Files, run the following command: 41 | 42 | ```bash 43 | $ docker run \ 44 | --rm \ 45 | --env RS_USERNAME=${RS_USERNAME} \ 46 | --env RS_API_KEY=${RS_API_KEY} \ 47 | --env RS_REGION_NAME=${RS_REGION_NAME} \ 48 | --volumes-from mysql-data \ 49 | carinamarina/backup \ 50 | backup \ 51 | --source /data/ \ 52 | --container mysql-backups \ 53 | --zip 54 | 55 | tar: removing leading '/' from member names 56 | Successfully uploaded object [2016/03/09/20-06-data.tar.gz] to container [mysql-backups] 57 | ``` 58 | 59 | Note that the uploaded object is named with the following format: 60 | 61 | `{{ year }}/{{ month }}/{{ day }}/{{ hour }}-{{ minute }}-{{ pathToSource }}.tar.gz` 62 | 63 | #### Back up a data volume container locally 64 | 65 | If you don’t have a Rackspace cloud account or if you want to do something with your backups other than upload them to Cloud Files, you can pipe the contents of the backup archive to your local filesystem: 66 | 67 | ```bash 68 | $ docker run \ 69 | --rm \ 70 | --volumes-from mysql-data \ 71 | carinamarina/backup \ 72 | backup \ 73 | --source /data/ \ 74 | --stdout \ 75 | --zip \ 76 | > mysql-backup.tar.gz 77 | ``` 78 | 79 | This will create a file named `mysql-backup.tar.gz` in the directory from which you ran the command. Note the use of `> mysql-backup.tar.gz`, which redirects the output of the command (the contents of the compressed archive) directly to a file. 80 | 81 | #### Restore a backup from Cloud Files 82 | 83 | Assume that you have set the environment variables `RS_USERNAME`, `RS_API_KEY`, and `RS_REGION_NAME` to your Rackspace username, Rackspace API key, and preferred Rackspace region, respectively. To download the backup from Cloud Files and write them to `/data/`, run the following command: 84 | 85 | ```bash 86 | $ docker run \ 87 | --rm \ 88 | --env RS_USERNAME=${RS_USERNAME} \ 89 | --env RS_API_KEY=${RS_API_KEY} \ 90 | --env RS_REGION_NAME=${RS_REGION_NAME} \ 91 | --volumes-from mysql-data \ 92 | carinamarina/backup \ 93 | restore \ 94 | --container mysql-backups \ 95 | --object 2016/03/10/01-30-data.tar.gz \ 96 | --destination /data/ \ 97 | --zip 98 | Reading and unzipping archive... 99 | Done. 100 | ``` 101 | 102 | #### Restore a local backup 103 | 104 | If you have a backup archive on your local machine, you can restore it by piping it into the `docker run` command: 105 | 106 | ```bash 107 | $ docker run \ 108 | --rm \ 109 | --interactive \ 110 | --volumes-from mysql-data \ 111 | carinamarina/backup \ 112 | restore \ 113 | --destination /data/ \ 114 | --stdin \ 115 | --zip \ 116 | < mysql-backup.tar.gz 117 | Reading and unzipping archive... 118 | Done. 119 | ``` 120 | -------------------------------------------------------------------------------- /backup/files/bin/backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ueo pipefail 4 | 5 | # Either output directly, or pipe to rack. 6 | output_archive () { 7 | if ${STDOUT}; then 8 | cat /dev/stdin 9 | else 10 | echo "Uploading archive to Cloud Files..." 11 | cat /dev/stdin | rack files large-object upload --size-pieces 64 --container ${CONTAINER} --stdin content --name ${object_name} 12 | fi 13 | 14 | return 0 15 | } 16 | 17 | # Removes non-alphanumeric characters and downcases a string 18 | slugify () { 19 | string=${1:-} 20 | echo $string | sed -r s/[^a-zA-Z0-9]+/-/g | sed -r s/^-+\|-+$//g | tr A-Z a-z 21 | 22 | return 0 23 | } 24 | 25 | usage () { 26 | echo "Usage: backup [options]" 27 | echo "" 28 | echo "Backup an directory as a tarball to stdout or Cloud Files" 29 | echo "" 30 | echo " Options:" 31 | echo " -c, --container Name of a Cloud Files container" 32 | echo " -h, --help Show help information" 33 | echo " -s, --source Path to source directory" 34 | echo " --stdout Use stdout instead of Cloud Files" 35 | echo " -z, --zip Use gzip to compress archive" 36 | echo " " 37 | } 38 | 39 | # Set default values for each of the options 40 | CONTAINER="" 41 | ZIP=false 42 | HELP=false 43 | SOURCE="" 44 | STDOUT=false 45 | 46 | # Get options 47 | args=$(getopt -o "c:h::s:z::" --long "container:,help::,source:,stdout::,zip::" -n $(basename "${0}") -- "$@") 48 | if [ $? != 0 ] ; then echo "Unable to parse options." >&2 ; exit 1 ; fi 49 | eval set -- "$args" 50 | 51 | # Assign options to variables, override defaults 52 | while true; do 53 | param=${1:-} 54 | value=${2:-} 55 | 56 | case "$param" in 57 | -c | --container ) CONTAINER="$value"; shift; shift ;; 58 | -h | --help ) HELP=true; shift; shift ;; 59 | -s | --source ) SOURCE="$value"; shift; shift ;; 60 | --stdout ) STDOUT=true; shift; shift ;; 61 | -z | --zip ) ZIP=true; shift; shift ;; 62 | -- ) shift; break ;; 63 | * ) break ;; 64 | esac 65 | done 66 | 67 | # Exit early and show usage if requested 68 | if ${HELP}; then 69 | usage 70 | exit 0 71 | fi 72 | 73 | # After assigning variables, make sure we're in a good state to proceed. 74 | if [[ -z ${SOURCE} ]]; then 75 | >&2 echo "Error: No backup source specified." 76 | exit 1 77 | fi 78 | 79 | if [[ -z ${CONTAINER} ]] && ! ${STDOUT}; then 80 | >&2 echo "Error: No Cloud Files container specified. Did you mean to use -o?" 81 | exit 1 82 | fi 83 | 84 | # (silently) Ensure the Cloud Files container exists 85 | if [[ -n ${CONTAINER} ]]; then 86 | rack files container create --name ${CONTAINER} > /dev/null 87 | fi 88 | 89 | # Assign year/month/day/time to variables 90 | date_year=$(date +%Y) 91 | date_month=$(date +%m) 92 | date_day=$(date +%d) 93 | date_time=$(date +%H-%M) 94 | 95 | # Remove all the non-alphanumeric characters from the source directory and use 96 | # the result as the archive's file name 97 | file_slug=$(slugify ${date_time}-${SOURCE}) 98 | file_name=${file_slug}.tar 99 | 100 | # If compressing the archive, add the customary `.gz` file extension. 101 | if ${ZIP}; then 102 | file_name=${file_name}.gz 103 | fi 104 | 105 | # Format the Cloud Files object name. 106 | object_name=${date_year}/${date_month}/${date_day}/${file_name} 107 | 108 | # Run the appropriate invocation of `tar` 109 | if ! ${STDOUT}; then 110 | echo "Bundling archive..." 111 | fi 112 | 113 | if ${ZIP}; then 114 | tar -czf - -C ${SOURCE} . | output_archive 115 | else 116 | tar -cf - -C ${SOURCE} . | output_archive 117 | fi 118 | 119 | if ! ${STDOUT}; then 120 | echo "Done." 121 | fi 122 | 123 | exit 0 124 | -------------------------------------------------------------------------------- /backup/files/bin/entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ueo pipefail 4 | 5 | run_command=${1:-} 6 | run_args=$(echo "$@" | cut -d ' ' -f2-) 7 | 8 | # Let's not run just any arbitrary command 9 | if [[ ${run_command} = "backup" ]] || [[ ${run_command} = "restore" ]]; then 10 | ${run_command} ${run_args} 11 | else 12 | >&2 echo "" 13 | >&2 echo "Usage: docker run [options] carinamarina/backup " 14 | >&2 echo "" 15 | exit 1 16 | fi 17 | -------------------------------------------------------------------------------- /backup/files/bin/restore: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ueo pipefail 4 | 5 | # Either reads from stdin or rack. Needs to be piped somewhere. 6 | get_archive () { 7 | if ${STDIN}; then 8 | cat /dev/stdin 9 | else 10 | rack files object download --container ${CONTAINER} --name ${OBJECT} 11 | fi 12 | } 13 | 14 | usage () { 15 | echo "Usage: restore [options]" 16 | echo "" 17 | echo "Restore an archive from stdin or Cloud Files" 18 | echo "" 19 | echo " Options:" 20 | echo " -c, --container Name of a Cloud Files container" 21 | echo " -d, --destination Destination for archive contents" 22 | echo " -h, --help Show help information" 23 | echo " -o, --object Name of archive object in a container" 24 | echo " --stdin Use stdin instead of Cloud Files" 25 | echo " -z, --zip Use gzip to uncompress archive" 26 | echo " " 27 | } 28 | 29 | CONTAINER="" 30 | DESTINATION="" 31 | HELP=false 32 | OBJECT="" 33 | STDIN=false 34 | ZIP=false 35 | 36 | # Get options 37 | args=$(getopt -o "c:d:h::o:z::" --long "container:,destination:,help::,object:,stdin::,zip::" -n $(basename "${0}") -- "$@") 38 | if [ $? != 0 ] ; then echo "Unable to parse options." >&2 ; exit 1 ; fi 39 | eval set -- "$args" 40 | 41 | # Assign options to variables, override defaults 42 | while true; do 43 | param=${1:-} 44 | value=${2:-} 45 | 46 | case "$param" in 47 | -c | --container ) CONTAINER="$value"; shift; shift ;; 48 | -d | --destination ) DESTINATION="$value"; shift; shift ;; 49 | -h | --help ) HELP=true; shift; shift ;; 50 | -o | --object ) OBJECT="$value"; shift; shift ;; 51 | --stdin ) STDIN=true; shift; shift ;; 52 | -z | --zip ) ZIP=true; shift; shift ;; 53 | -- ) shift; break ;; 54 | * ) break ;; 55 | esac 56 | done 57 | 58 | # Exit early and show usage if requested 59 | if ${HELP}; then 60 | usage 61 | exit 0 62 | fi 63 | 64 | # After assigning variables, make sure we're in a good state to proceed. 65 | if [[ -z ${DESTINATION} ]]; then 66 | >&2 echo "Error: No restore destination specified." 67 | exit 1 68 | fi 69 | 70 | if [ -z ${CONTAINER} ] || [ -z ${OBJECT} ]; then 71 | if ! ${STDIN}; then 72 | >&2 echo "Error: No Cloud Files container/object specified. Did you mean to use --stdin?" 73 | exit 1 74 | fi 75 | else 76 | # Check to be sure the object exists before trying to download it 77 | object=$(rack files object get --container ${CONTAINER} --name ${OBJECT} 2>&1) 78 | 79 | if [[ -n $(echo ${object} | grep -e "^error") ]];then 80 | >&2 echo "Error: Unable to retrieve object from Cloud Files." 81 | exit 1 82 | fi 83 | fi 84 | 85 | if ${ZIP}; then 86 | echo "Reading and unzipping archive..." 87 | get_archive | tar -xzf - -C ${DESTINATION} 88 | else 89 | echo "Reading and extracting archive..." 90 | get_archive | tar -xf - -C ${DESTINATION} 91 | fi 92 | 93 | echo "Done." 94 | exit 0 95 | -------------------------------------------------------------------------------- /carina_saas_example/.gitignore: -------------------------------------------------------------------------------- 1 | # use glob syntax. 2 | syntax: glob 3 | target/ 4 | test-output/ 5 | bin/ 6 | .settings/ 7 | .classpath 8 | .project 9 | .idea/ 10 | *.iml 11 | *.eml 12 | *.ipr 13 | *.iws 14 | *.DS_STORE 15 | TAGS 16 | .metadata/ 17 | atlassian-ide-plugin.xml 18 | .DS_Store 19 | .java-version 20 | .factorypath 21 | .apt_generated 22 | .checkstyle 23 | nb-configuration.xml 24 | nbactions.xml 25 | access/*.* 26 | !access/README.md 27 | -------------------------------------------------------------------------------- /carina_saas_example/DOCKERFILE: -------------------------------------------------------------------------------- 1 | FROM tomcat:8 2 | MAINTAINER zack 3 | 4 | ADD target/cse.war /usr/local/tomcat/webapps/ 5 | ADD access/docker.ps1 /usr/local/access/ 6 | ADD access/cert.pem /usr/local/access/ 7 | ADD access/key.pem /usr/local/access/ 8 | 9 | CMD ["catalina.sh", "run"] 10 | -------------------------------------------------------------------------------- /carina_saas_example/README.md: -------------------------------------------------------------------------------- 1 | This example demonstrates how to use a web application to provide a Software as a Service solution with Carina. This example uses: 2 | 3 | - Tomcat for the web application server 4 | - maven for packaging and testing 5 | - The jclouds Docker API to deploy, remove, and list containers on Carina 6 | - Mumble for the service being provided 7 | 8 | ##### Before you start: 9 | 10 | This example requires Java and maven. 11 | 12 | You need to download and extract your Carina access file to the access directory. This is the file specified in this guide: 13 | 14 | https://getcarina.com/docs/getting-started/getting-started-on-carina/#connect-to-your-cluster 15 | 16 | ##### Deploy to docker: 17 | 18 | The application sets up and runs containers on Docker, but the application itself is also designed to run on Docker. To run it on Carina, having followed the [Getting Started on Carina](https://getcarina.com/docs/getting-started/getting-started-on-carina/#connect-to-your-cluster) guide, you can: 19 | 20 | `mvn clean package` 21 | 22 | `docker build -t cse .` 23 | 24 | `docker run --name cse -d -p 8080:8080 cse` 25 | 26 | ##### Testing: 27 | 28 | `mvn tomcat7:run-war` 29 | 30 | This will run the web application at `localhost:8080/cse` 31 | 32 | ##### Debugging: 33 | 34 | `mvndebug tomcat7:run-war` -------------------------------------------------------------------------------- /carina_saas_example/access/README.md: -------------------------------------------------------------------------------- 1 | Place Carina access files in this directory. -------------------------------------------------------------------------------- /carina_saas_example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | carina 8 | cse 9 | 1.0-SNAPSHOT 10 | war 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | apache-snapshots 19 | https://repository.apache.org/content/repositories/snapshots 20 | 21 | false 22 | 23 | 24 | true 25 | 26 | 27 | 28 | 29 | 30 | 31 | javax.servlet 32 | jstl 33 | 1.2 34 | 35 | 36 | 37 | javax.servlet 38 | javax.servlet-api 39 | 3.0.1 40 | provided 41 | 42 | 43 | 44 | 45 | org.apache.jclouds.api 46 | docker 47 | 48 | 2.0.0-SNAPSHOT 49 | 50 | 51 | 52 | org.apache.commons 53 | commons-lang3 54 | 3.4 55 | 56 | 57 | 58 | 59 | cse 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-war-plugin 64 | 2.6 65 | 66 | 67 | org.apache.tomcat.maven 68 | tomcat7-maven-plugin 69 | 2.2 70 | 71 | 72 | 73 | true 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /carina_saas_example/src/main/java/com/carina_saas_example/controller/ContainerController.java: -------------------------------------------------------------------------------- 1 | package com.carina_saas_example.controller; 2 | 3 | import static com.carina_saas_example.util.Utils.filter; 4 | import static com.carina_saas_example.util.Utils.getDockerApiFromCarinaDirectory; 5 | 6 | import java.io.IOException; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.UUID; 11 | 12 | import javax.servlet.RequestDispatcher; 13 | import javax.servlet.ServletException; 14 | import javax.servlet.http.HttpServlet; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | 18 | import org.jclouds.docker.DockerApi; 19 | import org.jclouds.docker.domain.Config; 20 | import org.jclouds.docker.domain.Container; 21 | import org.jclouds.docker.domain.HostConfig; 22 | 23 | import com.carina_saas_example.util.Utils; 24 | import com.google.common.collect.ImmutableList; 25 | 26 | public class ContainerController extends HttpServlet { 27 | private static final long serialVersionUID = 1L; 28 | 29 | private static String INSERT = "/newcontainer.jsp"; 30 | private static String LIST = "/listcontainer.jsp"; 31 | private DockerApi dockerApi; 32 | 33 | public ContainerController() throws IOException { 34 | super(); 35 | // get API 36 | if("true".equals( System.getProperties().getProperty("cse.embeddedTomcat") )) { 37 | dockerApi = getDockerApiFromCarinaDirectory("access"); // From maven 38 | } else { 39 | dockerApi = getDockerApiFromCarinaDirectory("/usr/local/access"); // From docker 40 | } 41 | } 42 | 43 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 44 | String forward=""; 45 | String action = request.getParameter("action"); 46 | 47 | if ("delete".equalsIgnoreCase(action)){ 48 | String containerId = request.getParameter("containerId"); 49 | dockerApi.getContainerApi().stopContainer(containerId); 50 | dockerApi.getContainerApi().removeContainer(containerId); 51 | forward = LIST; 52 | request.setAttribute("containers", filter(dockerApi.getContainerApi().listContainers(), Utils.isMumble)); 53 | } else if ("create".equalsIgnoreCase(action)){ 54 | forward = INSERT; 55 | String password = Utils.getSecurePassword(); 56 | Container container = dockerApi.getContainerApi().createContainer("mumble" + UUID.randomUUID().toString(), 57 | Config.builder() 58 | .image("extra/mumble") 59 | .hostConfig( 60 | HostConfig.builder() 61 | .publishAllPorts(true) 62 | .build()) 63 | .env( 64 | ImmutableList.of( 65 | "MAX_USERS=50", 66 | "SERVER_TEXT=Welcome to My Mumble Server", 67 | "SUPW=" + password 68 | )) 69 | .build()); 70 | String id = container.id(); 71 | dockerApi.getContainerApi().startContainer(id); 72 | 73 | StringBuilder address = new StringBuilder(); 74 | for(Entry>> portList : dockerApi.getContainerApi().inspectContainer(id).networkSettings().ports().entrySet()) { 75 | for(Map port: portList.getValue()) { 76 | address.append(portList.getKey()); 77 | address.append(" to "); 78 | address.append(port.get("HostIp")); 79 | address.append(":"); 80 | address.append(port.get("HostPort")); 81 | address.append(","); 82 | } 83 | } 84 | 85 | request.setAttribute("ports", dockerApi.getContainerApi().inspectContainer(id).networkSettings().ports()); 86 | request.setAttribute("password", password); 87 | } else if ("list".equalsIgnoreCase(action)){ 88 | forward = LIST; 89 | request.setAttribute("containers", filter(dockerApi.getContainerApi().listContainers(), Utils.isMumble)); 90 | } else { 91 | forward = LIST; 92 | request.setAttribute("containers", filter(dockerApi.getContainerApi().listContainers(), Utils.isMumble)); 93 | } 94 | 95 | RequestDispatcher view = request.getRequestDispatcher(forward); 96 | view.forward(request, response); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /carina_saas_example/src/main/java/com/carina_saas_example/util/Utils.java: -------------------------------------------------------------------------------- 1 | package com.carina_saas_example.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | import java.security.SecureRandom; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Properties; 10 | 11 | import org.apache.commons.lang3.RandomStringUtils; 12 | import org.jclouds.ContextBuilder; 13 | import org.jclouds.docker.DockerApi; 14 | import org.jclouds.docker.domain.ContainerSummary; 15 | import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; 16 | 17 | import com.google.common.base.Predicate; 18 | import com.google.common.collect.ImmutableSet; 19 | import com.google.common.io.Files; 20 | import com.google.inject.Module; 21 | 22 | public class Utils { 23 | public static DockerApi getDockerApiFromCarinaDirectory(String path) throws IOException { 24 | 25 | // docker.ps1 contains the endpoint 26 | String endpoint = "https://" + 27 | Files.readFirstLine(new File(joinPath(path, "docker.ps1")), 28 | Charset.forName("UTF-8")).split("=")[1].replace("\"", "").substring(6); 29 | 30 | // enable logging 31 | Iterable modules = ImmutableSet. of(new SLF4JLoggingModule()); 32 | Properties overrides = new Properties(); 33 | 34 | // disable certificate checking for Carina 35 | overrides.setProperty("jclouds.trust-all-certs", "true"); 36 | 37 | return ContextBuilder.newBuilder("docker") 38 | // Use the unencrypted credentials 39 | .credentials(joinPath(path, "cert.pem"), joinPath(path, "key.pem")) 40 | .overrides(overrides) 41 | .endpoint(endpoint) 42 | .modules(modules) 43 | .buildApi(DockerApi.class); 44 | } 45 | 46 | // Concatenate two different paths 47 | public static String joinPath(String path1, String path2) { 48 | return new File(path1, path2).toString(); 49 | } 50 | 51 | public static Collection filter(Collection target, Predicate predicate) { 52 | Collection result = new ArrayList(); 53 | for (T element: target) { 54 | if (predicate.apply(element)) { 55 | result.add(element); 56 | } 57 | } 58 | return result; 59 | } 60 | 61 | public static Predicate isMumble = new Predicate() { 62 | public boolean apply(ContainerSummary container) { 63 | if (container.names().get(0) != null && container.names().get(0).contains("mumble")) { 64 | return true; 65 | } else { 66 | return false; 67 | } 68 | } 69 | }; 70 | 71 | public static String getSecurePassword() { 72 | String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 73 | return RandomStringUtils.random( 10, 0, 0, false, false, characters.toCharArray(), new SecureRandom() ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /carina_saas_example/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | ContainerController 9 | com.carina_saas_example.controller.ContainerController 10 | 11 | 12 | 13 | ContainerController 14 | / 15 | 16 | 17 | 18 | 19 | 30 20 | 21 | 22 | 23 | 24 | ContainerController 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /carina_saas_example/src/main/webapp/listcontainer.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html" pageEncoding="UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 4 | 5 | 6 | 7 | 8 | Show All Users 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 34 |
NameIDConnect toDelete?
:, 26 | : 27 | 29 | ">DELETE 30 |
35 |

Add Another Instance

36 | 37 | -------------------------------------------------------------------------------- /carina_saas_example/src/main/webapp/newcontainer.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 | <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 4 | 5 | 6 | New Container Details 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 |
Address 16 | 17 | 19 | : 20 |
Password 27 | 28 |
32 |

Back

33 | 34 | 35 | -------------------------------------------------------------------------------- /cf-backup/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | #ENV RS_USERNAME RS_USERNAME 4 | #ENV RS_API_KEY RS_API_KEY 5 | #ENV RS_REGION_NAME RS_REGION_NAME 6 | #ENV DIRECTORY DIRECTORY 7 | #ENV CONTAINER CONTAINER 8 | #ENV SCHEDULE SCHEDULE - defaults to * * * * * if not set (every minute) for the cron setup. 9 | #ENV NOCOMPRESSION NOCOMPRESSION 10 | 11 | ADD https://ec4a542dbf90c03b9f75-b342aba65414ad802720b41e8159cf45.ssl.cf5.rackcdn.com/1.1.0-beta1/Linux/amd64/rack /usr/bin/rack 12 | 13 | RUN apt-get -y install rsyslog ca-certificates 14 | 15 | #ADD files/etc/crontab /etc/crontab 16 | ADD files/bin/start-cron.sh /usr/bin/start-cron.sh 17 | ADD files/bin/cron-job.sh /usr/bin/cron-job.sh 18 | ADD files/bin/run-rack.sh /usr/bin/run-rack.sh 19 | RUN chmod +x /usr/bin/start-cron.sh 20 | RUN chmod +x /usr/bin/cron-job.sh 21 | RUN chmod +x /usr/bin/run-rack.sh 22 | RUN chmod +x /usr/bin/rack 23 | RUN touch /var/log/cron.log 24 | 25 | CMD /usr/bin/start-cron.sh -------------------------------------------------------------------------------- /cf-backup/README.md: -------------------------------------------------------------------------------- 1 | # Rackspace Cloud Files backup Docker image 2 | 3 | This image will upload (backup) a directory to Cloud Files every minute using cron and [rack](https://developer.rackspace.com/docs/rack-cli/ "rack"). If you want to provide a different schedule, set the SCHEDULE environment variable to the cron string you want (defaults to * * * * *). 4 | 5 | Building the image: 6 | 7 | ``` 8 | docker build -t carinamarina/cf-backup cf-backup 9 | ``` 10 | 11 | Example run. Bash: 12 | 13 | ``` 14 | docker run \ 15 | --name backup \ 16 | --env RS_USERNAME='[redacted]' \ 17 | --env RS_API_KEY='[redacted]' \ 18 | --env RS_REGION_NAME='DFW' \ 19 | --env DIRECTORY='/config' \ 20 | --env CONTAINER='quassel-backup' \ 21 | --env SCHEDULE='*/2 * * * *' \ 22 | --volumes-from quassel-data \ 23 | carinamarina/cf-backup 24 | ``` 25 | 26 | PowerShell: 27 | 28 | ``` 29 | docker run ` 30 | --name backup ` 31 | --env RS_USERNAME='[redacted]' ` 32 | --env RS_API_KEY='[redacted]' ` 33 | --env RS_REGION_NAME='DFW' ` 34 | --env DIRECTORY='/config' ` 35 | --env CONTAINER='quassel-backup' ` 36 | --env SCHEDULE='*/2 * * * *' ` 37 | --volumes-from quassel-data ` 38 | carinamarina/cf-backup 39 | ``` 40 | 41 | `RS_USERNAME` - Rackspace username 42 | 43 | `RS_API_KEY` - Rackspace API key 44 | 45 | `RS_REGION_NAME` - Rackspace region 46 | 47 | `DIRECTORY` - Directory to backup from the container 48 | 49 | `CONTAINER` - The container name to upload to 50 | 51 | `SCHEDULE` - (optional) cron schedule string 52 | 53 | `NOCOMPRESSION` - set this to 'true' to upload individual files instead of a single compressed archive. Defaults to using a single compressed archive by default. Not using an archive will also ignore hidden files in $DIRECTORY. 54 | 55 | `--volumes-from` - the data volume container to mount -------------------------------------------------------------------------------- /cf-backup/files/bin/cron-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | env $(cat /etc/env.sh | xargs -0) run-rack.sh >> /var/log/cron.log 2>&1 3 | -------------------------------------------------------------------------------- /cf-backup/files/bin/run-rack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | if [ "$NOCOMPRESSION" = "true" ]; 3 | then 4 | rack files object upload-dir --container $CONTAINER --dir $DIRECTORY 5 | else 6 | tar -zcvf backup.tar.gz $DIRECTORY 7 | rack files object upload --container $CONTAINER --name backup.tar.gz --file backup.tar.gz 8 | fi 9 | -------------------------------------------------------------------------------- /cf-backup/files/bin/start-cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | echo "${SCHEDULE:-* * * * *} root /usr/bin/cron-job.sh >> /var/log/cron.log 2>&1" > /etc/crontab 3 | rsyslogd 4 | cron 5 | #env | grep -v '$SCHEDULE' | sed 's/\(.*\)=\(.*\)/\1="\2"/' > /etc/env.sh 6 | env | grep -v SCHEDULE > /etc/env.sh 7 | touch /var/log/cron.log 8 | tail -f /var/log/syslog /var/log/cron.log -------------------------------------------------------------------------------- /cf-restore/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | #ENV RS_USERNAME RS_USERNAME 4 | #ENV RS_API_KEY RS_API_KEY 5 | #ENV RS_REGION_NAME RS_REGION_NAME 6 | #ENV VOLUME VOLUME 7 | #ENV CONTAINER CONTAINER 8 | #ENV NOCOMPRESSION NOCOMPRESSION 9 | 10 | ADD https://ec4a542dbf90c03b9f75-b342aba65414ad802720b41e8159cf45.ssl.cf5.rackcdn.com/1.1.0-beta1/Linux/amd64/rack /usr/bin/rack 11 | ADD files/bin/run-rack.sh /usr/bin/run-rack.sh 12 | 13 | RUN apt-get -y install ca-certificates 14 | 15 | RUN chmod +x /usr/bin/rack 16 | RUN chmod +x /usr/bin/run-rack.sh 17 | 18 | CMD run-rack.sh -------------------------------------------------------------------------------- /cf-restore/README.md: -------------------------------------------------------------------------------- 1 | # Rackspace Cloud Files restore Docker image 2 | 3 | This image will download (restore) a Cloud Files container to a local directory once, using [rack](https://developer.rackspace.com/docs/rack-cli/ "rack"). 4 | 5 | Building the image: 6 | 7 | ``` 8 | docker build -t carinamarina/cf-restore cf-restore 9 | ``` 10 | 11 | Example run with bash: 12 | 13 | ``` 14 | docker run \ 15 | --name restore \ 16 | --rm \ 17 | --env RS_USERNAME='[redacted]' \ 18 | --env RS_API_KEY='[redacted]' \ 19 | --env RS_REGION_NAME='DFW' \ 20 | --env DIRECTORY='/config' \ 21 | --env CONTAINER='quassel-backup' \ 22 | --volumes-from quassel-data \ 23 | carinamarina/cf-restore 24 | ``` 25 | PowerShell: 26 | 27 | ``` 28 | docker run ` 29 | --name restore ` 30 | --rm ` 31 | --env RS_USERNAME='[redacted]' ` 32 | --env RS_API_KEY='[redacted]' ` 33 | --env RS_REGION_NAME='DFW' ` 34 | --env DIRECTORY='/config' ` 35 | --env CONTAINER='quassel-backup' ` 36 | --volumes-from quassel-data ` 37 | carinamarina/cf-restore 38 | ``` 39 | 40 | `RS_USERNAME` - Rackspace username 41 | 42 | `RS_API_KEY` - Rackspace API key 43 | 44 | `RS_REGION_NAME` - Rackspace region 45 | 46 | `DIRECTORY` - Directory to restore to from the container 47 | 48 | `CONTAINER` - The container name to download from 49 | 50 | `--volumes-from` - the data volume container to mount 51 | 52 | `NOCOMPRESSION` - set this to download full files instead of a compressed archive. Use the same setting as your backup setting, if using the cf-backup image. Does not work with hidden files. -------------------------------------------------------------------------------- /cf-restore/files/bin/run-rack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | if [ "$NOCOMPRESSION" = "true" ]; 3 | then 4 | for i in $(rack files object list --container $CONTAINER --no-header --output csv | cut -d ',' -f 1); do 5 | rack files object download --container $CONTAINER --name $i > $DIRECTORY/$i; 6 | done 7 | else 8 | rack files object download --container $CONTAINER --name backup.tar.gz > backup.tar.gz 9 | tar -zxvf backup.tar.gz -C $DIRECTORY/.. 10 | fi 11 | -------------------------------------------------------------------------------- /ci-cd-product/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:0.10-onbuild 2 | 3 | RUN mkdir -p /usr/local/src 4 | WORKDIR /usr/local/src 5 | 6 | RUN apt-get update && apt-get install -y npm 7 | RUN npm install restify 8 | RUN npm install request 9 | 10 | COPY productws.js productws.js 11 | 12 | EXPOSE 8080 13 | 14 | ENTRYPOINT node productws.js 15 | -------------------------------------------------------------------------------- /ci-cd-product/productws.js: -------------------------------------------------------------------------------- 1 | var restify = require('restify'); 2 | var request = require('request'); 3 | function listProducts(req, res, next) { 4 | request('http://10.176.11.153:5984/kixx/_all_docs', function(error, response, body){ 5 | if (!error && response.statusCode == 200) { 6 | var rows = JSON.parse(body); 7 | var tablerows = rows.rows; 8 | var output; 9 | res.send(rows); 10 | next(); 11 | } 12 | }) 13 | } 14 | function getProduct(req, res, next) { 15 | request('http://10.176.11.153:5984/kixx/' + req.params.id, function(error, response, body){ 16 | if (!error && response.statusCode == 200) { 17 | var rows = JSON.parse(body); 18 | var tablerows = rows.rows; 19 | var output; 20 | res.send(rows); 21 | next(); 22 | } 23 | }) 24 | } 25 | function getVersion(req, res, next) { 26 | res.send("1.0.2"); 27 | } 28 | var server = restify.createServer({ 29 | name: 'productws', 30 | }); 31 | server.use(restify.bodyParser()); 32 | server.get('/version', getVersion); 33 | server.get('/product', listProducts); 34 | server.get('/product/:id', getProduct); 35 | server.listen(8080, function() { 36 | console.log('%s listening at %s', server.name, server.url); 37 | }); 38 | -------------------------------------------------------------------------------- /ci-cd-watcher/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4.3 2 | 3 | COPY whwatch.py /usr/local/src/whwatch.py 4 | 5 | RUN pip install flask simplejson docker-py 6 | 7 | EXPOSE 5000 8 | 9 | ENTRYPOINT python /usr/local/src/whwatch.py 10 | -------------------------------------------------------------------------------- /ci-cd-watcher/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | docker run -d \ 3 | --volumes-from swarm-data \ 4 | -p 5000:5000 \ 5 | --name watcher \ 6 | 7 | ``` 8 | -------------------------------------------------------------------------------- /ci-cd-watcher/whwatch.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, session, redirect, url_for, escape, request 2 | import docker 3 | import sys 4 | 5 | app = Flask(__name__) 6 | app.debug = True 7 | 8 | @app.route("/version", methods=['GET']) 9 | def hello(): 10 | return "1.0.0" 11 | 12 | @app.route('/webhook', methods=['POST']) 13 | def webhook(): 14 | try: 15 | tls_config = docker.tls.TLSConfig( 16 | client_cert=('/etc/docker/server-cert.pem', '/etc/docker/server-key.pem'), 17 | verify='/etc/docker/ca.pem') 18 | cli = docker.Client(base_url='https://swarm-manager:2376', tls=tls_config) 19 | 20 | host_config = cli.create_host_config(port_bindings={8080: 8080}) 21 | container = cli.create_container(image="donschenck/productws", detach=True, host_config=host_config) 22 | response = cli.start(container=container.get('Id')) 23 | 24 | except Exception: 25 | return "

Error: %s

" % sys.exc_info()[0] 26 | else: 27 | return "started!" 28 | 29 | if __name__ == "__main__": 30 | app.run(host='0.0.0.0', port=5000) 31 | -------------------------------------------------------------------------------- /guestbook-mongo/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /guestbook-mongo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | ADD . /src 6 | 7 | WORKDIR /src 8 | 9 | RUN pip install -r requirements.txt 10 | 11 | EXPOSE 5000 12 | 13 | CMD python app.py 14 | -------------------------------------------------------------------------------- /guestbook-mongo/README.md: -------------------------------------------------------------------------------- 1 | # guestbook-mongo 2 | -------------------------------------------------------------------------------- /guestbook-mongo/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from flask import Flask, render_template, request, redirect, url_for 5 | 6 | from pymongo import MongoClient 7 | 8 | 9 | logging.basicConfig( 10 | level=logging.DEBUG, 11 | format='%(levelname)s: %(message)s') 12 | logger = logging.getLogger(__name__) 13 | logger.info("Welcome to Guestbook: Mongo Edition") 14 | 15 | 16 | host = os.getenv('MONGO_HOST') 17 | port = int(os.getenv('MONGO_PORT')) 18 | ssl = os.getenv('MONGO_SSL') == 'True' 19 | db = os.getenv('MONGO_DATABASE') 20 | username = os.getenv('MONGO_USER') 21 | password = os.getenv('MONGO_PASSWORD') 22 | 23 | 24 | logger.debug("The log statement below is for educational purposes only. " 25 | "Do not log credentials.") 26 | logger.debug('mongodb://%s:%s@%s:%s/%s?ssl=%s', 27 | username, password, host, port, db, ssl) 28 | 29 | 30 | app = Flask(__name__) 31 | client = MongoClient(host, port, ssl=ssl) 32 | db = client.get_database(db) 33 | db.authenticate(username, password) 34 | guests = db.guests 35 | 36 | 37 | @app.route('/', methods=['GET', 'POST']) 38 | def index(): 39 | if request.method == 'POST': 40 | name = request.form['name'] 41 | guests.insert_one({'name': name}) 42 | return redirect(url_for('index')) 43 | 44 | return render_template('index.html', guests=guests.find()) 45 | 46 | if __name__ == '__main__': 47 | app.run(host='0.0.0.0', debug=True) 48 | -------------------------------------------------------------------------------- /guestbook-mongo/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask~=0.10 2 | pymongo~=3.0 3 | -------------------------------------------------------------------------------- /guestbook-mongo/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mongo Guestbook 6 | 7 | 8 |

Mongo Guestbook

9 |

Sign the Guestbook!

10 |
11 | 12 | 13 |

14 | 15 |
16 |

Previous Guests:

17 |
    18 | {% for guest in guests %} 19 |
  1. {{ guest.name }}
  2. 20 | {% endfor %} 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /guestbook-mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | ADD . /src 6 | 7 | WORKDIR /src 8 | 9 | RUN pip install -r requirements.txt 10 | 11 | EXPOSE 5000 12 | 13 | CMD python app.py runserver --host 0.0.0.0 14 | -------------------------------------------------------------------------------- /guestbook-mysql/README.md: -------------------------------------------------------------------------------- 1 | # guestbook-mysql 2 | -------------------------------------------------------------------------------- /guestbook-mysql/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from flask import Flask, render_template, request, redirect, url_for 5 | from flask.ext.script import Manager 6 | from flask.ext.sqlalchemy import SQLAlchemy 7 | 8 | 9 | logging.basicConfig( 10 | level=logging.DEBUG, 11 | format='%(levelname)s: %(message)s') 12 | logger = logging.getLogger(__name__) 13 | logger.info("Welcome to Guestbook: MySQL Edition") 14 | 15 | SQLALCHEMY_DATABASE_URI = \ 16 | '{engine}://{username}:{password}@{host}:{port}/{database}'.format( 17 | engine='mysql+pymysql', 18 | username=os.getenv('MYSQL_USER'), 19 | password=os.getenv('MYSQL_PASSWORD'), 20 | host=os.getenv('MYSQL_HOST'), 21 | port=os.getenv('MYSQL_PORT'), 22 | database=os.getenv('MYSQL_DATABASE')) 23 | 24 | logger.debug("The log statement below is for educational purposes only. Do not log credentials.") 25 | logger.debug("%s", SQLALCHEMY_DATABASE_URI) 26 | 27 | app = Flask(__name__) 28 | app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI 29 | app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 30 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 31 | 32 | manager = Manager(app) 33 | db = SQLAlchemy(app) 34 | 35 | 36 | @app.route('/', methods=['GET', 'POST']) 37 | def index(): 38 | if request.method == 'POST': 39 | name = request.form['name'] 40 | guest = Guest(name=name) 41 | db.session.add(guest) 42 | db.session.commit() 43 | return redirect(url_for('index')) 44 | 45 | return render_template('index.html', guests=Guest.query.all()) 46 | 47 | 48 | class Guest(db.Model): 49 | __tablename__ = 'guests' 50 | 51 | id = db.Column(db.Integer, primary_key=True) 52 | name = db.Column(db.String(256), nullable=False) 53 | 54 | def __repr__(self): 55 | return "[Guest: id={}, name={}]".format(self.id, self.name) 56 | 57 | 58 | @manager.command 59 | def create_tables(): 60 | app.config['SQLALCHEMY_ECHO'] = True 61 | db.create_all() 62 | 63 | 64 | if __name__ == '__main__': 65 | manager.run() 66 | -------------------------------------------------------------------------------- /guestbook-mysql/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask~=0.10 2 | Flask-Script~=2.0 3 | Flask-SQLAlchemy~=2.0 4 | 5 | PyMySQL~=0.6 6 | -------------------------------------------------------------------------------- /guestbook-mysql/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MySQL Guestbook 6 | 7 | 8 |

MySQL Guestbook

9 |

Sign the Guestbook!

10 |
11 | 12 | 13 |

14 | 15 |
16 |

Previous Guests:

17 |
    18 | {% for guest in guests %} 19 |
  1. {{ guest.name }}
  2. 20 | {% endfor %} 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /guestbook-redis/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /guestbook-redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | ADD . /src 6 | 7 | WORKDIR /src 8 | 9 | RUN pip install -r requirements.txt 10 | 11 | EXPOSE 5000 12 | 13 | CMD python app.py 14 | -------------------------------------------------------------------------------- /guestbook-redis/README.md: -------------------------------------------------------------------------------- 1 | # guestbook-redis 2 | -------------------------------------------------------------------------------- /guestbook-redis/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from flask import Flask, render_template, request, redirect, url_for 5 | 6 | from redis import Redis 7 | 8 | 9 | logging.basicConfig( 10 | level=logging.DEBUG, 11 | format='%(levelname)s: %(message)s') 12 | logger = logging.getLogger(__name__) 13 | logger.info("Welcome to Guestbook: Redis Edition") 14 | 15 | 16 | host = os.getenv('REDIS_HOST') 17 | port = int(os.getenv('REDIS_PORT')) 18 | 19 | app = Flask(__name__) 20 | redis = Redis(host=host, port=port, charset='utf-8', decode_responses=True) 21 | 22 | 23 | @app.route('/', methods=['GET', 'POST']) 24 | def index(): 25 | if request.method == 'POST': 26 | name = request.form['name'] 27 | redis.lpush('guests', name) 28 | return redirect(url_for('index')) 29 | 30 | return render_template('index.html', guests=redis.lrange('guests', 0, -1)) 31 | 32 | if __name__ == '__main__': 33 | app.run(host='0.0.0.0', debug=True) 34 | -------------------------------------------------------------------------------- /guestbook-redis/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask~=0.10 2 | redis~=2.10 3 | -------------------------------------------------------------------------------- /guestbook-redis/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redis Guestbook 6 | 7 | 8 |

Redis Guestbook

9 |

Sign the Guestbook!

10 |
11 | 12 | 13 |

14 | 15 |
16 |

Previous Guests:

17 |
    18 | {% for guest in guests %} 19 |
  1. {{ guest }}
  2. 20 | {% endfor %} 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /hello-world-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-onbuild 2 | EXPOSE 5000 3 | CMD ["python", "app.py"] 4 | -------------------------------------------------------------------------------- /hello-world-app/README.md: -------------------------------------------------------------------------------- 1 | # Hello World App 2 | 3 | This is a sample Python web application, running on port 5000, 4 | which prints `Hello World!`. 5 | 6 | 1. Run the `carinamarina/hello-world-app` container. 7 | 8 | ```bash 9 | docker run --detach --name app --publish-all carinamarina/hello-world-app 10 | ``` 11 | 12 | 2. Identity the port where the app container was published. In the example below, 13 | the port is 32770. 14 | 15 | ```bash 16 | $ docker port app 17 | 5000/tcp -> 0.0.0.0:32770 18 | ``` 19 | 20 | 3. Open http://<dockerHost>:<containerPort>, for example **http://localhost:32770**. 21 | You should see the following output: 22 | 23 | ``` 24 | Hello World! 25 | ``` 26 | -------------------------------------------------------------------------------- /hello-world-app/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/') 8 | def hello(): 9 | return 'Hello World!' 10 | 11 | if __name__ == '__main__': 12 | app.run(host='0.0.0.0', port=5000) 13 | -------------------------------------------------------------------------------- /hello-world-app/build: -------------------------------------------------------------------------------- 1 | set +v 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | docker build --tag carinamarina/hello-world-app $DIR 6 | -------------------------------------------------------------------------------- /hello-world-app/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | -------------------------------------------------------------------------------- /hello-world-web/.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *.pyc 3 | -------------------------------------------------------------------------------- /hello-world-web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-onbuild 2 | EXPOSE 5000 3 | CMD ["python", "web.py"] 4 | -------------------------------------------------------------------------------- /hello-world-web/README.md: -------------------------------------------------------------------------------- 1 | # Hello World Web 2 | 3 | This is a sample Python web application, running on port 5000, 4 | which prints data retrieved from the linked `carinamarina/hello-world-app` container. 5 | 6 | 1. Run the `carinamarina/hello-world-app` container. 7 | 8 | ```bash 9 | docker run --detach --name app carinamarina/hello-world-app 10 | ``` 11 | 12 | 2. Run the `carinamarina/hello-world-web` container, linking to the app container using 13 | the alias **helloapp**. 14 | 15 | ```bash 16 | docker run --detach --name web --link app:helloapp --publish-all carinamarina/hello-world-web 17 | ``` 18 | 19 | 3. Identity the port where the web container was published. In the example below, 20 | the port is 32770. 21 | 22 | ```bash 23 | $ docker port web 24 | 5000/tcp -> 0.0.0.0:32770 25 | ``` 26 | 27 | 4. Open http://<dockerHost>:<appContainerPort>, for example **http://localhost:32770**. 28 | You should see the following output: 29 | 30 | ``` 31 | The linked container says ... "Hello World!" 32 | ``` 33 | -------------------------------------------------------------------------------- /hello-world-web/build: -------------------------------------------------------------------------------- 1 | set +v 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | docker build --tag carinamarina/hello-world-web $DIR 6 | -------------------------------------------------------------------------------- /hello-world-web/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | requests 3 | -------------------------------------------------------------------------------- /hello-world-web/web.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | from flask import Flask 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/') 8 | def index(): 9 | data = get_app_data() 10 | return 'The linked container said... "{0}"'.format(data) 11 | 12 | 13 | def get_app_data(): 14 | # the web container MUST be run with --link :helloapp 15 | link_alias = 'helloapp' 16 | 17 | # Request data from the app container 18 | response = requests.get('http://{0}:5000'.format(link_alias)) 19 | return response.text 20 | 21 | 22 | if __name__ == '__main__': 23 | app.run(host='0.0.0.0', port=5000) 24 | -------------------------------------------------------------------------------- /magento/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:5.6-apache 2 | 3 | RUN apt-get update && apt-get install -y git 4 | 5 | RUN requirements="libpng12-dev libmcrypt-dev libmcrypt4 libcurl3-dev libfreetype6 libjpeg62-turbo libpng12-dev libfreetype6-dev libjpeg62-turbo-dev" \ 6 | && apt-get update && apt-get install -y $requirements && rm -rf /var/lib/apt/lists/* \ 7 | && docker-php-ext-install pdo_mysql \ 8 | && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ 9 | && docker-php-ext-install gd \ 10 | && docker-php-ext-install mcrypt \ 11 | && docker-php-ext-install mbstring \ 12 | && requirementsToRemove="libpng12-dev libmcrypt-dev libcurl3-dev libpng12-dev libfreetype6-dev libjpeg62-turbo-dev" \ 13 | && apt-get purge --auto-remove -y $requirementsToRemove 14 | 15 | RUN cd /tmp \ 16 | && curl -O https://www.magentocommerce.com/downloads/assets/1.9.1.0/magento-1.9.1.0.tar.gz \ 17 | && tar xvf magento-1.9.1.0.tar.gz \ 18 | && mv magento/* magento/.htaccess /var/www/html 19 | 20 | RUN curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/2.2.7.tar.gz \ 21 | && tar xfz /tmp/redis.tar.gz \ 22 | && rm -r /tmp/redis.tar.gz \ 23 | && mv phpredis-2.2.7 /usr/src/php/ext/redis \ 24 | && docker-php-ext-install redis 25 | 26 | WORKDIR /var/www/html 27 | 28 | RUN curl -Ss https://raw.githubusercontent.com/colinmollenhour/modman/master/modman-installer | bash \ 29 | && ~/bin/modman init \ 30 | && ~/bin/modman clone https://github.com/colinmollenhour/Cm_Cache_Backend_Redis \ 31 | && ~/bin/modman clone https://github.com/colinmollenhour/Cm_RedisSession 32 | 33 | COPY ./setup-config.bash /opt/ 34 | COPY ./install-data.bash /opt/ 35 | 36 | RUN chown -R www-data:www-data . 37 | RUN usermod -u 1000 www-data 38 | RUN a2enmod rewrite 39 | -------------------------------------------------------------------------------- /magento/docker-compose.yml: -------------------------------------------------------------------------------- 1 | web: 2 | image: jamiehannaford/magento 3 | ports: 4 | - "80:80" 5 | links: 6 | - redis 7 | container_name: web 8 | env_file: 9 | - env 10 | redis: 11 | image: redis 12 | container_name: redis 13 | -------------------------------------------------------------------------------- /magento/env: -------------------------------------------------------------------------------- 1 | MYSQL_HOST= 2 | MYSQL_USER=magento 3 | MYSQL_PASSWORD= 4 | MYSQL_DATABASE=magento 5 | 6 | MAGENTO_LOCALE=en_GB 7 | MAGENTO_TIMEZONE=Europe/Berlin 8 | MAGENTO_DEFAULT_CURRENCY=EUR 9 | MAGENTO_URL=http://foo.com 10 | 11 | MAGENTO_ADMIN_FIRSTNAME=Admin 12 | MAGENTO_ADMIN_LASTNAME=MyStore 13 | MAGENTO_ADMIN_EMAIL=admin@foo.com 14 | MAGENTO_ADMIN_USERNAME=admin 15 | MAGENTO_ADMIN_PASSWORD=password1 16 | -------------------------------------------------------------------------------- /magento/install-data.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Installing MySQL" 4 | apt-get update; apt-get install -y mysql-client 5 | 6 | echo "Download sample-data file. This could take a while..." 7 | cd /tmp 8 | curl -SO https://www.magentocommerce.com/downloads/assets/1.9.1.0/magento-sample-data-1.9.1.0.tar.gz 9 | tar xvf magento-sample-data-1.9.1.0.tar.gz 10 | 11 | echo "Copying over assets" 12 | cp -R magento-sample-data-1.9.1.0/media/* /var/www/html/media/ 13 | cp -R magento-sample-data-1.9.1.0/skin/* /var/www/html/skin/ 14 | chown -R www-data:www-data /var/www/html/media 15 | 16 | echo "Importing mysqldump" 17 | mysql -h $MYSQL_HOST \ 18 | -u $MYSQL_USER \ 19 | -p$MYSQL_PASSWORD \ 20 | $MYSQL_DATABASE < magento-sample-data-1.9.1.0/magento_sample_data_for_1.9.1.0.sql 21 | -------------------------------------------------------------------------------- /magento/setup-config.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | php -f /var/www/html/install.php -- \ 4 | --license_agreement_accepted "yes" \ 5 | --locale $MAGENTO_LOCALE \ 6 | --timezone $MAGENTO_TIMEZONE \ 7 | --default_currency $MAGENTO_DEFAULT_CURRENCY \ 8 | --db_host $MYSQL_HOST \ 9 | --db_name $MYSQL_DATABASE \ 10 | --db_user $MYSQL_USER \ 11 | --db_pass $MYSQL_PASSWORD \ 12 | --url $MAGENTO_URL \ 13 | --skip_url_validation "yes" \ 14 | --use_rewrites "no" \ 15 | --use_secure "no" \ 16 | --secure_base_url "" \ 17 | --use_secure_admin "no" \ 18 | --admin_firstname $MAGENTO_ADMIN_FIRSTNAME \ 19 | --admin_lastname $MAGENTO_ADMIN_LASTNAME \ 20 | --admin_email $MAGENTO_ADMIN_EMAIL \ 21 | --admin_username $MAGENTO_ADMIN_USERNAME \ 22 | --admin_password $MAGENTO_ADMIN_PASSWORD 23 | 24 | data=" 25 | \n 26 | Cm_Cache_Backend_Redis\n 27 | \n 28 | redis\n 29 | 6379\n 30 | \n 31 | 0\n 32 | \n 33 | 0\n 34 | 1\n 35 | 10\n 36 | 0\n 37 | 1\n 38 | 1\n 39 | 20480\n 40 | gzip\n 41 | 0\n 42 | \n 43 | \n 44 | \n 45 | \n 46 | redis\n 47 | 6379\n 48 | \n 49 | 2.5\n 50 | \n 51 | 0\n 52 | 2048\n 53 | gzip\n 54 | 1\n 55 | 6\n 56 | 5\n 57 | 30\n 58 | 600\n 59 | 60\n 60 | 7200\n 61 | 0\n 62 | 60\n 63 | 2592000\n 64 | 65 | " 66 | 67 | file="/var/www/html/app/etc/local.xml" 68 | 69 | touch $file 70 | chmod 644 $file 71 | chown www-data:www-data $file 72 | 73 | content="$(echo $data | sed 's/\//\\\//g')" 74 | sed -i -e "/<\/global>/ s/.*/${content}\n&/" $file 75 | -------------------------------------------------------------------------------- /nginx-fpm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.7 2 | 3 | # Update some config values 4 | RUN sed -i -e "s/keepalive_timeout\s*65/keepalive_timeout 2/" /etc/nginx/nginx.conf 5 | RUN sed -i -e "s/keepalive_timeout 2/keepalive_timeout 2;\n\tclient_max_body_size 100m/" /etc/nginx/nginx.conf 6 | 7 | # Copy nginx config file 8 | COPY wordpress-fpm.conf /etc/nginx/conf.d/default.conf 9 | -------------------------------------------------------------------------------- /nginx-fpm/wordpress-fpm.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | root /var/www/html; 5 | 6 | index index.php; 7 | 8 | location / { 9 | try_files $uri $uri/ /index.php?$args; 10 | } 11 | 12 | rewrite /wp-admin$ $scheme://$host$uri/ permanent; 13 | 14 | location ~ [^/]\.php(/|$) { 15 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 16 | if (!-f $document_root$fastcgi_script_name) { 17 | return 404; 18 | } 19 | 20 | include fastcgi_params; 21 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 22 | fastcgi_param PATH_INFO $fastcgi_path_info; 23 | fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; 24 | 25 | fastcgi_pass fpm:9000; 26 | fastcgi_index index.php; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nginx-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.9 2 | 3 | # forward request and error logs to docker log collector 4 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 5 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 6 | 7 | ADD entrypoint.sh /entrypoint.sh 8 | 9 | EXPOSE 80 10 | 11 | CMD ["/entrypoint.sh"] 12 | -------------------------------------------------------------------------------- /nginx-proxy/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Validate environment variables 6 | : "${UPSTREAM:?Set UPSTREAM using --env}" 7 | : "${UPSTREAM_PORT?Set UPSTREAM_PORT using --env}" 8 | PROTOCOL=${PROTOCOL:=HTTP} 9 | 10 | # Template an nginx.conf 11 | cat </etc/nginx/nginx.conf 12 | user nginx; 13 | worker_processes 2; 14 | 15 | events { 16 | worker_connections 1024; 17 | } 18 | EOF 19 | 20 | if [ "$PROTOCOL" = "HTTP" ]; then 21 | cat <>/etc/nginx/nginx.conf 22 | 23 | http { 24 | access_log /var/log/nginx/access.log; 25 | error_log /var/log/nginx/error.log; 26 | 27 | server { 28 | location / { 29 | proxy_pass http://${UPSTREAM}:${UPSTREAM_PORT}; 30 | proxy_set_header Host \$host; 31 | proxy_set_header X-Forwarded-For \$remote_addr; 32 | } 33 | } 34 | } 35 | EOF 36 | elif [ "$PROTOCOL" == "TCP" ]; then 37 | cat <>/etc/nginx/nginx.conf 38 | 39 | stream { 40 | server { 41 | listen ${UPSTREAM_PORT}; 42 | proxy_pass ${UPSTREAM}:${UPSTREAM_PORT}; 43 | } 44 | } 45 | EOF 46 | else 47 | echo "Unknown PROTOCOL. Valid values are HTTP or TCP." 48 | fi 49 | 50 | echo "Proxy ${PROTOCOL} for ${UPSTREAM}:${UPSTREAM_PORT}" 51 | 52 | # Launch nginx in the foreground 53 | /usr/sbin/nginx -g "daemon off;" 54 | -------------------------------------------------------------------------------- /python-web-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Docker 2 | *.env 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | #Ipython Notebook 63 | .ipynb_checkpoints 64 | -------------------------------------------------------------------------------- /python-web-app/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.4 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | ADD . /src 6 | 7 | WORKDIR /src 8 | 9 | RUN pip install -r requirements.txt 10 | 11 | CMD gunicorn app:app -b 0.0.0.0:8000 12 | -------------------------------------------------------------------------------- /python-web-app/app/app.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from flask import Flask, render_template, request, redirect, url_for 5 | from flask.ext.script import Manager 6 | from flask.ext.sqlalchemy import SQLAlchemy 7 | 8 | 9 | logging.basicConfig( 10 | level=logging.DEBUG, 11 | format='%(levelname)s: %(message)s') 12 | logger = logging.getLogger(__name__) 13 | logger.debug("Welcome to Carina Guestbook") 14 | 15 | 16 | SQLALCHEMY_DATABASE_URI = \ 17 | '{engine}://{username}:{password}@{hostname}/{database}'.format( 18 | engine='mysql+pymysql', 19 | username=os.getenv('MYSQL_USER'), 20 | password=os.getenv('MYSQL_PASSWORD'), 21 | hostname=os.getenv('MYSQL_HOST'), 22 | database=os.getenv('MYSQL_DATABASE')) 23 | 24 | logger.debug("The log statement below is for educational purposes only. Do *not* log credentials.") 25 | logger.debug("%s", SQLALCHEMY_DATABASE_URI) 26 | 27 | app = Flask(__name__) 28 | app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI 29 | app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 30 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 31 | 32 | manager = Manager(app) 33 | db = SQLAlchemy(app) 34 | 35 | 36 | @app.route('/', methods=['GET', 'POST']) 37 | def index(): 38 | logger.debug("index") 39 | 40 | if request.method == 'POST': 41 | name = request.form['name'] 42 | guest = Guest(name=name) 43 | db.session.add(guest) 44 | db.session.commit() 45 | return redirect(url_for('index')) 46 | 47 | return render_template('index.html', guests=Guest.query.all()) 48 | 49 | 50 | class Guest(db.Model): 51 | __tablename__ = 'guests' 52 | 53 | id = db.Column(db.Integer, primary_key=True) 54 | name = db.Column(db.String(256), nullable=False) 55 | 56 | def __repr__(self): 57 | return "[Guest: id={}, name={}]".format(self.id, self.name) 58 | 59 | 60 | @manager.command 61 | def create_db(): 62 | logger.debug("create_db") 63 | app.config['SQLALCHEMY_ECHO'] = True 64 | db.create_all() 65 | 66 | @manager.command 67 | def create_dummy_data(): 68 | logger.debug("create_test_data") 69 | app.config['SQLALCHEMY_ECHO'] = True 70 | guest = Guest(name='Steve') 71 | db.session.add(guest) 72 | db.session.commit() 73 | 74 | @manager.command 75 | def drop_db(): 76 | logger.debug("drop_db") 77 | app.config['SQLALCHEMY_ECHO'] = True 78 | db.drop_all() 79 | 80 | 81 | if __name__ == '__main__': 82 | manager.run() 83 | -------------------------------------------------------------------------------- /python-web-app/app/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask~=0.10 2 | Flask-Script~=2.0 3 | Flask-SQLAlchemy~=2.0 4 | PyMySQL~=0.6 5 | gunicorn~=19.3 6 | -------------------------------------------------------------------------------- /python-web-app/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Carina Guestbook 6 | 7 | 8 |

Carina Guestbook

9 |

Sign the Guestbook!

10 |
11 | 12 | 13 |

14 | 15 |
16 |

Previous Guests:

17 |
    18 | {% for guest in guests %} 19 |
  1. {{ guest.name }}
  2. 20 | {% endfor %} 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /python-web-app/app/tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class MainTestCase(unittest.TestCase): 5 | 6 | def test_two_and_two(self): 7 | four = 2 + 2 8 | self.assertEqual(four, 4) 9 | self.assertNotEqual(four, 5) 10 | self.assertNotEqual(four, 6) 11 | self.assertNotEqual(four, 22) 12 | 13 | if __name__ == '__main__': 14 | unittest.main() 15 | -------------------------------------------------------------------------------- /python-web-app/db/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.6 2 | 3 | ADD mysql.cnf /etc/mysql/conf.d/ 4 | -------------------------------------------------------------------------------- /python-web-app/db/mysql.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | # Skip reverse DNS lookup of clients 3 | skip-name-resolve 4 | bind-address=0.0.0.0 -------------------------------------------------------------------------------- /python-web-app/docker-compose-common.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | # A Docker Compose file for common configuration between development and production environments 4 | 5 | services: 6 | lb: 7 | # The load balancer container. Built from the lb/Dockerfile. 8 | container_name: pythonwebapp_lb 9 | build: lb 10 | restart: unless-stopped 11 | networks: 12 | - backend 13 | ports: 14 | - "80:80" 15 | 16 | app: 17 | # The app container. Built from the app/Dockerfile. 18 | build: app 19 | restart: unless-stopped 20 | networks: 21 | backend: 22 | aliases: 23 | # All app servers be referred to by this alias with the backend network 24 | - apps 25 | environment: 26 | # Environment variables to configure the app on startup. 27 | - MYSQL_DATABASE=guestbook 28 | - MYSQL_HOST=pythonwebapp_db 29 | 30 | db: 31 | # The database container. Built from the db/Dockerfile. 32 | container_name: pythonwebapp_db 33 | build: db 34 | restart: unless-stopped 35 | networks: 36 | - backend 37 | environment: 38 | # Environment variables to configure MySQL on startup. 39 | - MYSQL_DATABASE=guestbook 40 | 41 | data: 42 | container_name: pythonwebapp_db_data 43 | # The Data Volume Container used to mount a volume to store our persistent data 44 | # https://getcarina.com/docs/tutorials/data-volume-containers/ 45 | image: cirros 46 | volumes: 47 | # Mount this path as a volume to store our MySQL files 48 | - /var/lib/mysql 49 | command: /bin/true 50 | # Run a trivial command to exit quickly. Volumes don't need a running container. 51 | -------------------------------------------------------------------------------- /python-web-app/docker-compose-prod.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | # A Docker Compose file for configuration of the production environment 4 | 5 | services: 6 | lb: 7 | extends: 8 | file: docker-compose-common.yml 9 | service: lb 10 | image: etoews/pythonwebapp_lb 11 | environment: 12 | # Always deploy to n1 so the lb always has the same IP address. This is 13 | # just for convenience and isn't strictly necessary. 14 | - "constraint:node==*n1" 15 | 16 | app: 17 | extends: 18 | file: docker-compose-common.yml 19 | service: app 20 | image: etoews/pythonwebapp_app 21 | expose: 22 | # Expose port 8000 so it's only visibile on the container, not the host 23 | - "8000" 24 | env_file: pythonwebapp-mysql-prod.env 25 | command: gunicorn app:app --bind 0.0.0.0:8000 26 | # Run Gunicorn to serve app requests 27 | 28 | db: 29 | extends: 30 | file: docker-compose-common.yml 31 | service: db 32 | image: etoews/pythonwebapp_db 33 | expose: 34 | # Expose port 3306 so it's only visibile on the container, not the host 35 | - "3306" 36 | env_file: 37 | - pythonwebapp-mysql-prod.env 38 | - pythonwebapp-mysql-root-prod.env 39 | volumes_from: 40 | # Mount the volumes from the data container to store our MySQL files 41 | - data 42 | 43 | data: 44 | extends: 45 | file: docker-compose-common.yml 46 | service: data 47 | 48 | networks: 49 | backend: {} 50 | -------------------------------------------------------------------------------- /python-web-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | # A Docker Compose file for configuration of the development environment 4 | 5 | services: 6 | # load balancer 7 | lb: 8 | extends: 9 | file: docker-compose-common.yml 10 | service: lb 11 | 12 | # app 13 | app: 14 | extends: 15 | file: docker-compose-common.yml 16 | service: app 17 | ports: 18 | # Publish the port so it's visible on the host, you can access the app directly 19 | - "8000:8000" 20 | volumes: 21 | # Mount the app dir in the container as /src so our changes to the app code 22 | # are also changed in the container 23 | - ./app:/src 24 | environment: 25 | # Environment variables to configure the app on startup. 26 | # We don't care about commiting these creds to GitHub because they're only 27 | # for our local development environment 28 | - MYSQL_USER=guestbook-admin 29 | - MYSQL_PASSWORD=my-guestbook-admin-password 30 | command: gunicorn --reload app:app --bind 0.0.0.0:8000 31 | # Run Gunicorn to serve app requests and reload on change so we can see our 32 | # changes to the app code 33 | 34 | db: 35 | extends: 36 | file: docker-compose-common.yml 37 | service: db 38 | ports: 39 | # Publish the port so it's visible on the host, you can access the db directly 40 | - "3306:3306" 41 | environment: 42 | # Environment variables to configure MySQL on startup. 43 | # We don't care about commiting these creds to GitHub because they're only 44 | # for our local development environment 45 | - MYSQL_ROOT_PASSWORD=my-root-password 46 | - MYSQL_USER=guestbook-admin 47 | - MYSQL_PASSWORD=my-guestbook-admin-password 48 | volumes_from: 49 | # Mount the volumes from the data container to store our MySQL files 50 | - data 51 | 52 | data: 53 | extends: 54 | file: docker-compose-common.yml 55 | service: data 56 | 57 | networks: 58 | backend: {} 59 | -------------------------------------------------------------------------------- /python-web-app/lb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.9 2 | 3 | # forward request and error logs to docker log collector 4 | RUN ln -sf /dev/stdout /var/log/nginx/access.log 5 | RUN ln -sf /dev/stderr /var/log/nginx/error.log 6 | 7 | COPY nginx.conf /etc/nginx/nginx.conf 8 | 9 | EXPOSE 80 10 | 11 | CMD ["nginx", "-g", "daemon off;"] 12 | -------------------------------------------------------------------------------- /python-web-app/lb/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 2; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | access_log /var/log/nginx/access.log; 10 | error_log /var/log/nginx/error.log; 11 | 12 | upstream app_servers { 13 | server apps:8000; 14 | } 15 | 16 | server { 17 | listen 80; 18 | 19 | location / { 20 | proxy_pass http://app_servers; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rails/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.2.1 2 | RUN apt-get update && apt-get install -y \ 3 | autoconf \ 4 | automake \ 5 | bison \ 6 | build-essential \ 7 | curl \ 8 | g++ \ 9 | gawk \ 10 | gcc \ 11 | libc6-dev \ 12 | libffi-dev \ 13 | imagemagick \ 14 | libgdbm-dev \ 15 | libncurses5-dev \ 16 | libpq-dev \ 17 | libreadline6-dev \ 18 | libsqlite3-dev \ 19 | libssl-dev \ 20 | libtool \ 21 | libyaml-dev \ 22 | make \ 23 | nodejs \ 24 | nodejs-legacy \ 25 | npm \ 26 | patch \ 27 | patch \ 28 | pkg-config \ 29 | sqlite3 \ 30 | vim \ 31 | zlib1g-dev 32 | 33 | RUN npm install -g phantomjs 34 | RUN mkdir /myapp 35 | 36 | WORKDIR /tmp 37 | COPY Gemfile Gemfile 38 | COPY Gemfile.lock Gemfile.lock 39 | RUN bundle install 40 | 41 | ADD . /myapp 42 | WORKDIR /myapp 43 | 44 | ENV POSTGRES_PASSWORD mysecretpassword 45 | ENV POSTGRES_USER postgres 46 | 47 | EXPOSE 80 48 | -------------------------------------------------------------------------------- /try-rails/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rails 2 | 3 | # Generate a rails app 4 | RUN cd /usr/src && rails new --skip-bundle app 5 | WORKDIR /usr/src/app 6 | RUN bundle install 7 | RUN bin/rails generate controller Demo helloworld 8 | 9 | # Switch to MySQL 10 | RUN rm Gemfile.lock && sed -i -- "s/gem 'sqlite3'/gem 'mysql'/g" Gemfile && bundle install 11 | 12 | # Make it pretty 13 | COPY carina.png public/ 14 | COPY helloworld.html.erb app/views/demo/ 15 | 16 | # Show the demo page as the homepage 17 | RUN sed -i -- "s/get 'demo\/helloworld'/root to: 'demo#helloworld'/g" config/routes.rb 18 | 19 | EXPOSE 3000 20 | 21 | CMD bin/rails server -b 0.0.0.0 22 | -------------------------------------------------------------------------------- /try-rails/README.md: -------------------------------------------------------------------------------- 1 | # Try Rails on Carina 2 | 3 | This is a sample Rails application which runs on Carina and is backed by a 4 | MySQL database hosted on the Rackspace Cloud Database service. 5 | 6 | 1. Create a MySQL database in the IAD region in the Rackspace Cloud Control Panel. 7 | Note the host name, and credentials as it will be needed in the next step. 8 | 9 | 2. Run the `carinamarina/try-rails` container. Update the `DATABASE_URL` environment 10 | variable with your database connection details. 11 | 12 | ```bash 13 | docker run --name rails \ 14 | --env DATABASE_URL="mysql://username:password@host/dbname" \ 15 | --detach \ 16 | --publish-all \ 17 | carinamarina/try-rails 18 | ``` 19 | 20 | 3. Identity the port where the rails application was published. In the example below, 21 | the port is 32800. 22 | 23 | ```bash 24 | $ docker port rails 25 | 3000/tcp -> 172.99.65.237:32800 26 | ``` 27 | 28 | 4. Open http://<dockerHost>:<containerPort>, 29 | for example **http://172.99.65.237:32800**. You should see the 30 | Powered By Carina badge if the database connection was successful. 31 | 32 | ![Powered by Carina](carina.png) 33 | -------------------------------------------------------------------------------- /try-rails/build: -------------------------------------------------------------------------------- 1 | set +v 2 | 3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | docker build --tag try-rails $DIR 6 | -------------------------------------------------------------------------------- /try-rails/carina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcarina/examples/9dd8bc49333f2bc709ae7f715136073af3312866/try-rails/carina.png -------------------------------------------------------------------------------- /try-rails/helloworld.html.erb: -------------------------------------------------------------------------------- 1 | <% dbname = ActiveRecord::Base.connection.execute("SELECT DATABASE();").first.first %> 2 | 3 |

4 | You are connected to the <%= dbname %> database! 5 |

6 | 7 | 8 | -------------------------------------------------------------------------------- /wordpress/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM wordpress:fpm 2 | 3 | RUN apt-get update && apt-get -y install curl unzip 4 | 5 | # Install phpredis extension 6 | RUN curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/2.2.7.tar.gz \ 7 | && tar xfz /tmp/redis.tar.gz \ 8 | && rm -r /tmp/redis.tar.gz \ 9 | && mv phpredis-2.2.7 /usr/src/php/ext/redis \ 10 | && docker-php-ext-install redis 11 | 12 | # Add scripts 13 | COPY set-config.php /set-config.php 14 | COPY entrypoint.sh /entrypoint.sh 15 | 16 | ENTRYPOINT ["/entrypoint.sh"] 17 | CMD ["php-fpm"] 18 | -------------------------------------------------------------------------------- /wordpress/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -z "$WORDPRESS_DB_HOST" ]; then 5 | echo >&2 'Error: missing WORDPRESS_DB_HOST environment variable' 6 | exit 1 7 | fi 8 | 9 | if [ -z "$WORDPRESS_DB_USER" ]; then 10 | echo >&2 'Error: missing WORDPRESS_DB_USER environment variables' 11 | exit 1 12 | fi 13 | 14 | if [ -z "$WORDPRESS_DB_PASSWORD" ]; then 15 | echo >&2 'Error: missing WORDPRESS_DB_PASSWORD environment variable' 16 | exit 1 17 | fi 18 | 19 | # Copy /usr/src/wordpress to the /var/www/html mount 20 | if ! [ -e index.php -a -e wp-includes/version.php ]; then 21 | echo >&2 "WordPress not found in $(pwd) - copying now..." 22 | if [ "$(ls -A)" ]; then 23 | echo >&2 "WARNING: $(pwd) is not empty - press Ctrl+C now if this is an error!" 24 | ( set -x; ls -A; sleep 10 ) 25 | fi 26 | tar cf - --one-file-system -C /usr/src/wordpress . | tar xf - 27 | echo >&2 "Complete! WordPress has been successfully copied to $(pwd)" 28 | fi 29 | 30 | # Set up wp-config.php 31 | if [ ! -e wp-config.php ]; then 32 | awk '/^\/\*.*stop editing.*\*\/$/ && c == 0 { c = 1; system("cat") } { print }' wp-config-sample.php > wp-config.php <<'EOPHP' 33 | // If we're behind a proxy server and using HTTPS, we need to alert Wordpress of that fact 34 | // see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy 35 | if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { 36 | $_SERVER['HTTPS'] = 'on'; 37 | } 38 | 39 | EOPHP 40 | fi 41 | 42 | # Set DB config 43 | sed_escape_lhs() { 44 | echo "$@" | sed 's/[]\/$*.^|[]/\\&/g' 45 | } 46 | sed_escape_rhs() { 47 | echo "$@" | sed 's/[\/&]/\\&/g' 48 | } 49 | php_escape() { 50 | php -r 'var_export((string) $argv[1]);' "$1" 51 | } 52 | set_config() { 53 | key="$1" 54 | value="$2" 55 | regex="(['\"])$(sed_escape_lhs "$key")\2\s*," 56 | if [ "${key:0:1}" = '$' ]; then 57 | regex="^(\s*)$(sed_escape_lhs "$key")\s*=" 58 | fi 59 | sed -ri "s/($regex\s*)(['\"]).*\3/\1$(sed_escape_rhs "$(php_escape "$value")")/" wp-config.php 60 | } 61 | 62 | set_config 'DB_HOST' "$WORDPRESS_DB_HOST" 63 | set_config 'DB_USER' "$WORDPRESS_DB_USER" 64 | set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" 65 | set_config 'DB_NAME' "$WORDPRESS_DB_NAME" 66 | 67 | # Set salts 68 | UNIQUES=( 69 | AUTH_KEY 70 | SECURE_AUTH_KEY 71 | LOGGED_IN_KEY 72 | NONCE_KEY 73 | AUTH_SALT 74 | SECURE_AUTH_SALT 75 | LOGGED_IN_SALT 76 | NONCE_SALT 77 | ) 78 | for unique in "${UNIQUES[@]}"; do 79 | eval unique_value=\$WORDPRESS_$unique 80 | if [ "$unique_value" ]; then 81 | set_config "$unique" "$unique_value" 82 | else 83 | # if not specified, let's generate a random value 84 | current_set="$(sed -rn "s/define\((([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\);/\4/p" wp-config.php)" 85 | if [ "$current_set" = 'put your unique phrase here' ]; then 86 | set_config "$unique" "$(head -c1M /dev/urandom | sha1sum | cut -d' ' -f1)" 87 | fi 88 | fi 89 | done 90 | 91 | # Check MySQL config actually works 92 | TERM=dumb php -- "$WORDPRESS_DB_HOST" "$WORDPRESS_DB_USER" "$WORDPRESS_DB_PASSWORD" "$WORDPRESS_DB_NAME" <<'EOPHP' 93 | connect_error) { 104 | fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); 105 | --$maxTries; 106 | if ($maxTries <= 0) { 107 | exit(1); 108 | } 109 | sleep(3); 110 | } 111 | } while ($mysql->connect_error); 112 | 113 | if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($argv[4]) . '`')) { 114 | fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); 115 | $mysql->close(); 116 | exit(1); 117 | } 118 | 119 | $mysql->close(); 120 | EOPHP 121 | 122 | # Download nginx helper plugin 123 | curl -O `curl -i -s https://wordpress.org/plugins/nginx-helper/ | egrep -o "https://downloads.wordpress.org/plugin/[^']+"` 124 | unzip -o nginx-helper.*.zip -d wp-content/plugins 125 | 126 | # Install Redis cache 127 | curl -s -o wp-content/object-cache.php https://raw.githubusercontent.com/ericmann/Redis-Object-Cache/master/object-cache.php 128 | sed -i -e "s/127.0.0.1/$REDIS_IP/" wp-content/object-cache.php 129 | 130 | # Install w3 plugin 131 | curl -O `curl -i -s https://wordpress.org/plugins/w3-total-cache/ | egrep -o "https://downloads.wordpress.org/plugin/[^']+"` 132 | unzip -o w3-total-cache.*.zip -d wp-content/plugins 133 | 134 | # Activate plugins once logged in 135 | cat << ENDL >> wp-config.php 136 | \$plugins = get_option( 'active_plugins' ); 137 | if ( count( \$plugins ) === 0 ) { 138 | require_once(ABSPATH .'/wp-admin/includes/plugin.php'); 139 | \$pluginsToActivate = array( 'nginx-helper/nginx-helper.php', 'w3-total-cache/w3-total-cache.php' ); 140 | foreach ( \$pluginsToActivate as \$plugin ) { 141 | if ( !in_array( \$plugin, \$plugins ) ) { 142 | activate_plugin( '/var/html/wp-content/plugins/' . \$plugin ); 143 | } 144 | } 145 | } 146 | ENDL 147 | 148 | # A bunch of hacks to make sure W3 works 149 | mkdir -p wp-content/cache/tmp wp-content/w3tc-config 150 | touch wp-content/w3tc-config/master.php 151 | chmod -R 777 wp-content/w3tc-config wp-content/cache 152 | rm -rf wp-content/cache/config 153 | 154 | # Set ownership 155 | chown -R www-data:www-data . 156 | 157 | # Run config script to set API creds 158 | php /set-config.php 159 | 160 | # Run nginx 161 | exec "$@" 162 | -------------------------------------------------------------------------------- /wordpress/env: -------------------------------------------------------------------------------- 1 | RS_USERNAME= 2 | RS_API_KEY= 3 | 4 | RS_LOCATION=US 5 | RS_CONTAINER= 6 | RS_CNAME= 7 | 8 | WORDPRESS_DB_HOST= 9 | WORDPRESS_DB_NAME= 10 | WORDPRESS_DB_USER= 11 | WORDPRESS_DB_PASSWORD= 12 | 13 | REDIS_IP= 14 | -------------------------------------------------------------------------------- /wordpress/set-config.php: -------------------------------------------------------------------------------- 1 | set('cdn.enabled', true); 15 | $conf->set('cdn.engine', 'rscf'); 16 | $conf->set('cdn.rscf.user', getenv('RS_USERNAME')); 17 | $conf->set('cdn.rscf.key', getenv('RS_API_KEY')); 18 | $conf->set('cdn.rscf.location', getenv('RS_LOCATION')); 19 | $conf->set('cdn.rscf.container', getenv('RS_CONTAINER')); 20 | $conf->set('cdn.rscf.cname', getenv('RS_CNAME')); 21 | $conf->set('cdn.rscf.ssl', 'enabled'); 22 | $conf->save(); 23 | -------------------------------------------------------------------------------- /znc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:15.04 2 | 3 | RUN apt-get update && apt-get install -y znc 4 | RUN useradd znc 5 | 6 | ADD docker-entrypoint.sh /entrypoint.sh 7 | ADD znc.conf.default /znc.conf.default 8 | RUN chmod 644 /znc.conf.default 9 | 10 | EXPOSE 6667 11 | ENTRYPOINT ["/entrypoint.sh"] 12 | CMD ["/home/znc/.znc"] 13 | -------------------------------------------------------------------------------- /znc/Dockerfile.mkconf: -------------------------------------------------------------------------------- 1 | FROM ubuntu:15.04 2 | 3 | RUN apt-get update && apt-get install -y znc 4 | RUN useradd znc 5 | 6 | ENV DIR=/home/znc/.znc 7 | RUN mkdir -p $DIR && chown -R znc:znc $DIR 8 | 9 | ENTRYPOINT ["bash"] 10 | -------------------------------------------------------------------------------- /znc/README.md: -------------------------------------------------------------------------------- 1 | # znc-docker 2 | 3 | ## Create conf file 4 | 5 | This step is optional, since users might have their own conf files already. If not, to create one: 6 | 7 | ```bash 8 | $ docker run -it carinamarina/znc-mkconf 9 | ``` 10 | 11 | ## Run data container 12 | 13 | ``` 14 | $ docker run --detach \ 15 | --name znc-conf \ 16 | --volume /data \ 17 | alpine true 18 | ``` 19 | 20 | ``` 21 | $ docker cp znc.conf znc-conf:/data 22 | ``` 23 | 24 | ## Run ZNC container 25 | 26 | ```bash 27 | $ docker run --detach \ 28 | --publish 6697:6697 \ 29 | --name znc \ 30 | --volumes-from znc-conf \ 31 | carinamarina/znc /data 32 | ``` 33 | -------------------------------------------------------------------------------- /znc/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | DATADIR=$1 4 | 5 | if [ -d "${DATADIR}/modules" ]; then 6 | cwd="$(pwd)" 7 | modules=$(find "${DATADIR}/modules" -name "*.cpp") 8 | 9 | for module in $modules; do 10 | cd "$(dirname "$module")" 11 | znc-buildmod "$module" 12 | done 13 | 14 | cd "$cwd" 15 | fi 16 | 17 | if [ ! -f "${DATADIR}/configs/znc.conf" ]; then 18 | mkdir -p "${DATADIR}/configs" 19 | cp /znc.conf.default "${DATADIR}/configs/znc.conf" 20 | fi 21 | 22 | su -c "znc --makepem --datadir=$DATADIR" -s /bin/sh znc 23 | echo "SSLCertFile $DATADIR/znc.pem" >> $DATADIR/configs/znc.conf 24 | 25 | chown -R znc:znc "$DATADIR" 26 | 27 | su -c "znc --foreground --datadir=$DATADIR" -s /bin/sh znc 28 | -------------------------------------------------------------------------------- /znc/znc.conf.default: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // Do NOT edit this file while ZNC is running! 4 | // Use webadmin or *controlpanel instead. 5 | // 6 | // Altering this file by hand will forfeit all support. 7 | // 8 | // But if you feel risky, you might want to read help on /znc saveconfig and /znc rehash. 9 | // Also check http://en.znc.in/wiki/Configuration 10 | 11 | AnonIPLimit = 10 12 | ConnectDelay = 5 13 | HideVersion = false 14 | LoadModule = partyline 15 | LoadModule = webadmin 16 | MaxBufferSize = 500 17 | ProtectWebSessions = true 18 | SSLCertFile = /home/znc/.znc/znc.pem 19 | ServerThrottle = 30 20 | Version = 1.6.3 21 | 22 | 23 | AllowIRC = true 24 | AllowWeb = true 25 | IPv4 = true 26 | IPv6 = true 27 | Port = 6697 28 | SSL = true 29 | URIPrefix = / 30 | 31 | 32 | 33 | Admin = true 34 | AppendTimestamp = false 35 | AutoClearChanBuffer = false 36 | AutoClearQueryBuffer = true 37 | Buffer = 999 38 | ChanModes = +stn 39 | DenyLoadMod = false 40 | DenySetBindHost = false 41 | Ident = foo 42 | JoinTries = 10 43 | LoadModule = controlpanel 44 | LoadModule = chansaver 45 | LoadModule = perform 46 | MaxJoins = 0 47 | MaxNetworks = 1 48 | MaxQueryBuffers = 50 49 | MultiClients = true 50 | Nick = foo 51 | PrependTimestamp = true 52 | QuitMsg = %znc% 53 | RealName = Boaty McBoatFace 54 | StatusPrefix = * 55 | TimestampFormat = [%H:%M:%S] 56 | 57 | 58 | FloodBurst = 4 59 | FloodRate = 1.00 60 | IRCConnectEnabled = true 61 | JoinDelay = 0 62 | LoadModule = keepnick 63 | LoadModule = kickrejoin 64 | LoadModule = nickserv 65 | Server = irc.freenode.net 6667 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Hash = 014c07e0dc9112cf9edb20da49489eb6146bb2cf1c7188ccbb34316975c7e992 75 | Method = SHA256 76 | Salt = fY6Mu0N6Zh5T5A0UY3gP 77 | 78 | 79 | --------------------------------------------------------------------------------