├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Vagrantfile ├── Vagrantfile-standalone ├── ansible-groups.yml ├── ansible.cfg ├── book.json ├── bootstrap ├── apollo-down.sh ├── apollo-env.sh ├── apollo-launch.sh ├── aws │ ├── private-cloud │ │ ├── config-default.sh │ │ └── util.sh │ └── public-cloud │ │ ├── config-default.sh │ │ └── util.sh ├── common.sh ├── digitalocean │ ├── config-default.sh │ └── util.sh ├── gce │ ├── config-default.sh │ └── util.sh ├── rackspace │ ├── config-default.sh │ └── util.sh ├── tests │ └── test.sh └── vagrant │ └── util.sh ├── contrib-plugins ├── .gitignore ├── playbook.yml └── plugins.yml ├── dcos.yml ├── docs ├── README.md ├── architecture.png ├── components │ ├── README.md │ ├── ansible.md │ ├── apache-mesos.md │ ├── consul.md │ ├── docker.md │ ├── logging.md │ ├── terraform.md │ ├── vault.md │ └── weave.md ├── dns.md ├── getting-started-guides │ ├── README.md │ ├── aws-public.md │ ├── aws.md │ ├── aws │ │ └── vpn.md │ ├── digitalocean.md │ ├── gce.md │ ├── rackspace.md │ └── vagrant.md ├── networking.md ├── platform-rolling-upgrades.md └── roadmap.md ├── examples ├── drupal-mysql │ ├── README.md │ ├── commerce-kickstart.json │ ├── drupal7.json │ └── drupal8.json ├── mattermost │ ├── README.md │ └── chatops.json ├── nodejs-rest-api │ ├── README.md │ ├── nodejs-rest-api-v1.json │ └── nodejs-rest-api-v2.json ├── spring-boot │ ├── README.md │ └── spring-boot.json ├── structr │ ├── README.md │ └── structr.json └── wordpress-mysql │ ├── README.md │ └── wordpress.json ├── group_vars ├── all ├── mesos_agents ├── mesos_masters └── vagrant ├── inventory └── inventory ├── package.json ├── playbooks └── coreos-bootstrap.yml ├── requirements-test.txt ├── requirements.txt ├── requirements.yml ├── roles ├── cadvisor │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── templates │ │ ├── cadvisor-consul.j2 │ │ └── cadvisor.service.j2 │ └── vars │ │ └── main.yml ├── consul │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── config.yml │ │ └── main.yml │ ├── templates │ │ ├── consul-discovery.service.j2 │ │ ├── consul.json.j2 │ │ └── consul.service.j2 │ └── vars │ │ └── main.yml ├── dcos_cli │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── apps.yml │ │ ├── frameworks.yml │ │ └── main.yml │ ├── templates │ │ ├── cassandra-config.j2 │ │ ├── chronos-config.j2 │ │ ├── elasticsearch.json.j2 │ │ ├── exhibitor-config.yml │ │ ├── kibana.json.j2 │ │ ├── logstash.json.j2 │ │ ├── promdash.json.j2 │ │ ├── prometheus.json.j2 │ │ └── spark-config.j2 │ └── vars │ │ ├── cassandra.yml │ │ ├── chronos.yml │ │ ├── elasticsearch.yml │ │ ├── exhibitor.yml │ │ ├── kibana.yml │ │ ├── logstash.yml │ │ ├── promdash.yml │ │ ├── prometheus.yml │ │ └── spark.yml ├── docker │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── templates │ │ ├── config.json.j2 │ │ └── docker.service.j2 │ └── vars │ │ └── main.yml ├── dockerbench │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── templates │ │ └── docker-bench-warn.sh.j2 │ └── vars │ │ └── main.yml ├── handlers │ └── handlers │ │ └── main.yml ├── logstash │ ├── defaults │ │ └── main.yml │ ├── files │ │ ├── logstash-forwarder.crt │ │ └── logstash-forwarder.key │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── config.yml │ │ ├── lumberjack.yml │ │ └── main.yml │ └── templates │ │ ├── logstash-forwarder.conf.j2 │ │ ├── logstash.conf.j2 │ │ └── lumberjack.service.j2 ├── marathon │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── templates │ │ ├── marathon-consul.j2 │ │ ├── marathon-wait-for-listen.sh.j2 │ │ └── marathon.service.j2 │ └── vars │ │ └── main.yml ├── mesos │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── agent.yml │ │ ├── main.yml │ │ └── master.yml │ └── templates │ │ ├── mesos-agent-consul.j2 │ │ ├── mesos-agent.service.j2 │ │ ├── mesos-exporter-consul.j2 │ │ ├── mesos-master-consul.j2 │ │ └── mesos-master.service.j2 ├── mesos_consul │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ └── mesos_consul.service.j2 ├── mesos_maintenance │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── complete.yml │ │ ├── main.yml │ │ ├── schedule.yml │ │ └── start.yml │ ├── templates │ │ ├── machines.json.j2 │ │ ├── schedule.json.j2 │ │ └── wait-for-agent.sh.j2 │ └── vars │ │ └── main.yml ├── prometheus │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── templates │ │ ├── node-exporter-consul.j2 │ │ └── prometheus.yml.j2 │ └── vars │ │ └── main.yml ├── traefik │ ├── defaults │ │ └── main.yml │ ├── files │ │ └── wait-for-marathon.sh │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── traefik-consul.json.j2 │ │ ├── traefik.service.j2 │ │ └── traefik.toml.j2 ├── vault │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── bootstrap.yml │ │ ├── install.yml │ │ └── main.yml │ ├── templates │ │ ├── config.hcl.j2 │ │ ├── default.j2 │ │ ├── unseal.j2 │ │ ├── vault-consul.j2 │ │ ├── vault-security.yaml.j2 │ │ ├── vault.conf.j2 │ │ └── wait-for-vault-leader.sh.j2 │ └── vars │ │ └── main.yml ├── weave │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ └── scope.yml │ ├── templates │ │ ├── scope.service.j2 │ │ ├── weave.service.j2 │ │ └── weaveproxy.service.j2 │ └── vars │ │ └── main.yml └── zookeeper │ ├── defaults │ └── main.yml │ ├── handlers │ └── main.yml │ ├── meta │ └── main.yml │ ├── tasks │ └── main.yml │ ├── templates │ ├── configuration.xsl.j2 │ ├── environment.j2 │ ├── log4j.properties.j2 │ ├── zoo.cfg.j2 │ ├── zookeeper-consul.j2 │ └── zookeeper.service.j2 │ └── vars │ └── main.yml ├── rolling-upgrade-maintenance.yml ├── rolling-upgrade-mesoscluster.yml ├── site.yml ├── terraform ├── aws │ ├── elb │ │ └── main.tf │ ├── keypair │ │ └── main.tf │ ├── private-cloud │ │ ├── .gitignore │ │ ├── agent-cloud-config.yml.tpl │ │ ├── bastion-cloud-config.yml.tpl │ │ ├── bastion-server.tf │ │ ├── bin │ │ │ ├── ovpn-client-config │ │ │ ├── ovpn-init │ │ │ ├── ovpn-new-client │ │ │ └── ovpn-start │ │ ├── etcd_discovery_url.txt │ │ ├── main.tf │ │ ├── master-cloud-config.yml.tpl │ │ ├── mesos-agents.tf │ │ ├── mesos-masters.tf │ │ ├── security_groups.tf │ │ └── vpc │ │ │ └── main.tf │ ├── public-cloud │ │ ├── agent-cloud-config.yml.tpl │ │ ├── etcd_discovery_url.txt │ │ ├── main.tf │ │ ├── master-cloud-config.yml.tpl │ │ ├── mesos-agents.tf │ │ └── mesos-masters.tf │ └── sg-all-traffic │ │ └── main.tf ├── digitalocean │ ├── .gitignore │ ├── agent-cloud-config.yml.tpl │ ├── etcd_discovery_url.txt │ ├── main.tf │ ├── master-cloud-config.yml.tpl │ └── ssh.config ├── gce │ ├── mesos-agent.tf │ ├── mesos-master.tf │ ├── outputs.tf │ ├── provider.tf │ └── variables.tf ├── rackspace │ ├── main.tf │ └── modules │ │ ├── keypair │ │ └── main.tf │ │ ├── mesos_agents │ │ ├── agent-cloud-config.yml.tpl │ │ └── main.tf │ │ ├── mesos_masters │ │ ├── main.tf │ │ └── master-cloud-config.yml.tpl │ │ └── sg-default │ │ └── main.tf └── scripts │ └── coreos │ ├── bootstrap.sh │ ├── get-pip.py │ └── runner ├── user-data ├── vagrant-standalone.yml ├── vagrant.yml ├── vagrant_helper.rb └── wercker.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vagrant 3 | *.box 4 | *.tfstate* 5 | *.tfvars 6 | *.tfplan 7 | site.retry 8 | packer_cache 9 | packer/build 10 | packer/*.pem 11 | .wercker 12 | *.cache 13 | ssh.config 14 | vendor 15 | .bundle 16 | .kitchen 17 | inventory/terraform.py 18 | tests/spec/*/*runtime_spec.rb 19 | contrib-plugins/* 20 | vault-security.yaml 21 | terraform/**/.terraform 22 | roles/coreos_bootstrap 23 | roles/coreos_timezone 24 | roles/datadog 25 | terraform/aws/public-cloud/etcd_discovery_url.txt 26 | terraform/rackspace/etcd_discovery_url.txt 27 | /_book/ 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Capgemini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ansible-groups.yml: -------------------------------------------------------------------------------- 1 | ansible_groups: 2 | "all:children": 3 | - mesos_masters 4 | - mesos_agents 5 | - load_balancers 6 | "load_balancers:children": 7 | - mesos_agents 8 | "zookeeper_servers:children": 9 | - mesos_masters 10 | "consul_servers:children": 11 | - mesos_masters 12 | "log_servers:children": 13 | - mesos_masters 14 | - mesos_agents 15 | "weave_servers:children": 16 | - mesos_masters 17 | - mesos_agents 18 | - load_balancers 19 | "marathon_servers": 20 | - mesos_masters 21 | "vagrant:children": 22 | - mesos_masters 23 | - mesos_agents 24 | - load_balancers 25 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = no 3 | record_host_keys = no 4 | jinja2_extensions = jinja2.ext.do 5 | timeout = 15 6 | gathering = smart 7 | roles_path = roles 8 | forks = 100 9 | 10 | [ssh_connection] 11 | ssh_args = -o ControlMaster=auto -o ControlPersist=30m 12 | scp_if_ssh = True 13 | pipelining = True 14 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "gitbook": "2.6.7", 3 | "structure": { 4 | "summary": "docs/README.md" 5 | }, 6 | "plugins": ["disqus", "edit-link", "-search", "github"], 7 | "pluginsConfig": { 8 | "disqus": { 9 | "shortName": "apollo" 10 | }, 11 | "edit-link": { 12 | "base": "https://github.com/Capgemini/apollo/tree/master", 13 | "label": "Edit This Page" 14 | }, 15 | "github": { 16 | "url": "https://github.com/Capgemini/apollo/" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bootstrap/apollo-down.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | APOLLO_ROOT=$(dirname "${BASH_SOURCE}")/.. 8 | source "${APOLLO_ROOT}/bootstrap/apollo-env.sh" 9 | source "${APOLLO_ROOT}/bootstrap/common.sh" 10 | source "${APOLLO_ROOT}/bootstrap/${APOLLO_PROVIDER}/util.sh" 11 | 12 | echo "Bringing down cluster using provider: $APOLLO_PROVIDER" 13 | 14 | verify_prereqs 15 | apollo_down 16 | 17 | echo "Done" 18 | -------------------------------------------------------------------------------- /bootstrap/apollo-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set the default provider of Apollo cluster to know where to load provider-specific scripts 4 | # You can override the default provider by exporting the APOLLO_PROVIDER 5 | # variable in your bashrc 6 | APOLLO_PROVIDER=${APOLLO_PROVIDER:-aws} 7 | # change global log level of components, set APOLLO_LOG to any value to enable 8 | APOLLO_LOG=${APOLLO_LOG:-} 9 | ANSIBLE_LOG=${ANSIBLE_LOG:-} 10 | 11 | # Overrides default folder in Terraform.py inventory. 12 | export TF_VAR_STATE_ROOT="${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 13 | 14 | # Some useful colors. 15 | if [[ -z "${color_start-}" ]]; then 16 | export color_start="\033[" 17 | export color_red="${color_start}0;31m" 18 | export color_yellow="${color_start}0;33m" 19 | export color_green="${color_start}0;32m" 20 | export color_norm="${color_start}0m" 21 | fi 22 | 23 | # Change logging levels of called components at a global level 24 | # if unset allow for existing selective logging of components 25 | case "${APOLLO_LOG}" in 26 | "") 27 | # Do nothing in this instance 28 | ;; 29 | 0) 30 | # Force minimal logging 31 | echo "Forcing reduction of component logging" 32 | export TF_LOG= 33 | export ANSIBLE_LOG= 34 | ;; 35 | 1) 36 | export TF_LOG=1 37 | export ANSIBLE_LOG="-v" 38 | ;; 39 | *) 40 | export TF_LOG=${APOLLO_LOG} 41 | export ANSIBLE_LOG="-vvvv" 42 | ;; 43 | esac 44 | -------------------------------------------------------------------------------- /bootstrap/apollo-launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | APOLLO_ROOT=$(dirname "${BASH_SOURCE}")/.. 8 | source "${APOLLO_ROOT}/bootstrap/apollo-env.sh" 9 | source "${APOLLO_ROOT}/bootstrap/common.sh" 10 | source "${APOLLO_ROOT}/bootstrap/${APOLLO_PROVIDER}/util.sh" 11 | 12 | main() { 13 | echo "Starting cluster using provider: $APOLLO_PROVIDER" >&2 14 | 15 | echo "... calling verify-prereqs" >&2 16 | verify_prereqs 17 | 18 | echo "... calling apollo-launch" >&2 19 | apollo_launch $@ 20 | } 21 | 22 | main $@ 23 | exit 0 24 | -------------------------------------------------------------------------------- /bootstrap/aws/private-cloud/config-default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export TF_VAR_access_key=${TF_VAR_access_key:?"Need to set TF_VAR_access_key non-empty"} 4 | export TF_VAR_secret_key=${TF_VAR_secret_key:?"Need to set TF_VAR_secret_key non-empty"} 5 | 6 | export ANSIBLE_SSH_ARGS="-F ${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}/ssh.config -q" 7 | 8 | export TF_VAR_region=${TF_VAR_region:-eu-west-1} 9 | export APOLLO_consul_dc=${APOLLO_consul_dc:-$TF_VAR_region} 10 | export APOLLO_mesos_cluster_name=${APOLLO_mesos_cluster_name:-$TF_VAR_region} 11 | export APOLLO_ansible_ssh_user=core 12 | -------------------------------------------------------------------------------- /bootstrap/aws/public-cloud/config-default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export TF_VAR_access_key=${TF_VAR_access_key:?"Need to set TF_VAR_access_key non-empty"} 4 | export TF_VAR_secret_key=${TF_VAR_secret_key:?"Need to set TF_VAR_secret_key non-empty"} 5 | 6 | export ANSIBLE_SSH_ARGS="-F ${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}/ssh.config -q" 7 | 8 | export TF_VAR_region=${TF_VAR_region:-eu-west-1} 9 | export APOLLO_consul_dc=${APOLLO_consul_dc:-$TF_VAR_region} 10 | export APOLLO_mesos_cluster_name=${APOLLO_mesos_cluster_name:-$TF_VAR_region} 11 | export APOLLO_ansible_ssh_user=core 12 | -------------------------------------------------------------------------------- /bootstrap/aws/public-cloud/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use the config file specified in $APOLLO_CONFIG_FILE, or default to 4 | # config-default.sh. 5 | 6 | ansible_ssh_config() { 7 | pushd "${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 8 | cat < ssh.config 9 | Host * 10 | StrictHostKeyChecking no 11 | ServerAliveInterval 120 12 | ControlMaster auto 13 | ControlPath ~/.ssh/mux-%r@%h:%p 14 | ControlPersist 30m 15 | User core 16 | UserKnownHostsFile /dev/null 17 | EOF 18 | popd 19 | } 20 | 21 | apollo_down() { 22 | pushd "${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 23 | terraform destroy -var "access_key=${TF_VAR_access_key}" \ 24 | -var "key_file=${TF_VAR_key_file}" \ 25 | -var "region=${TF_VAR_region}" 26 | > ${TF_VAR_etcd_discovery_url_file:-etcd_discovery_url.txt} 27 | popd 28 | } 29 | 30 | -------------------------------------------------------------------------------- /bootstrap/digitalocean/config-default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export TF_VAR_region=${TF_VAR_region:-lon1} 4 | export TF_VAR_do_token=${TF_VAR_do_token:?"Need to set TF_VAR_do_token non-empty"} 5 | 6 | export ANSIBLE_SSH_ARGS="-F ${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}/ssh.config -i ${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}/id_rsa -q" 7 | 8 | export APOLLO_consul_dc=${APOLLO_consul_dc:-$TF_VAR_region} 9 | export APOLLO_mesos_cluster_name=${APOLLO_mesos_cluster_name:-$TF_VAR_region} 10 | export APOLLO_ansible_ssh_user=core 11 | export APOLLO_traefik_network_interface=eth1 12 | -------------------------------------------------------------------------------- /bootstrap/digitalocean/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use the config file specified in $APOLLO_CONFIG_FILE, or default to 4 | # config-default.sh. 5 | apollo_down() { 6 | pushd "${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 7 | terraform destroy -var "do_token=${TF_VAR_do_token}" 8 | popd 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /bootstrap/gce/config-default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Keeping atlas variable without prefix as it's been shared by consul and tf at the moment. 4 | export ATLAS_TOKEN=${ATLAS_TOKEN:?"Need to set ATLAS_TOKEN non-empty"} 5 | export ATLAS_INFRASTRUCTURE=${ATLAS_INFRASTRUCTURE:-capgemini/apollo} 6 | 7 | export TF_VAR_account_file=${TF_VAR_account_file:?"Need to set TF_VAR_account_file non-empty"} 8 | export TF_VAR_project=${TF_VAR_project:?"Need to set TF_VAR_project non-empty"} 9 | 10 | export TF_VAR_region=${TF_VAR_region:-europe-west1} 11 | export TF_VAR_master_size=${TF_VAR_master_size:-n1-standard-2} 12 | export TF_VAR_agent_size=${TF_VAR_agent_size:-n1-standard-2} 13 | export TF_VAR_agents=${TF_VAR_agents:-1} 14 | 15 | export APOLLO_consul_dc=${APOLLO_consul_dc:-$TF_VAR_region} 16 | export APOLLO_mesos_cluster_name=${APOLLO_mesos_cluster_name:-$TF_VAR_region} 17 | -------------------------------------------------------------------------------- /bootstrap/gce/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use the config file specified in $APOLLO_CONFIG_FILE, or default to 4 | # config-default.sh. 5 | apollo_down() { 6 | pushd $APOLLO_ROOT/terraform/${APOLLO_PROVIDER} 7 | terraform destroy -var "region=${TF_VAR_region}" 8 | popd 9 | } 10 | -------------------------------------------------------------------------------- /bootstrap/rackspace/config-default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export TF_VAR_tenant_name=${TF_VAR_tenant_name:?"Need to set TF_VAR_tenant_name non-empty"} 4 | export TF_VAR_user_name=${TF_VAR_user_name:?"Need to set TF_VAR_user_name non-empty"} 5 | export TF_VAR_password=${TF_VAR_password:?"Need to set TF_VAR_password non-empty"} 6 | 7 | # Overrides default folder in Terraform.py inventory. 8 | export TF_VAR_STATE_ROOT="${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 9 | 10 | export TF_VAR_region=${TF_VAR_region:-LON} 11 | 12 | export APOLLO_consul_dc=${APOLLO_consul_dc:-$TF_VAR_region} 13 | export APOLLO_mesos_cluster_name=${APOLLO_mesos_cluster_name:-$TF_VAR_region} 14 | export APOLLO_ansible_user=core 15 | -------------------------------------------------------------------------------- /bootstrap/rackspace/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use the config file specified in $APOLLO_CONFIG_FILE, or default to 4 | # config-default.sh. 5 | apollo_down() { 6 | pushd "${APOLLO_ROOT}/terraform/${APOLLO_PROVIDER}" 7 | terraform destroy -var "tenant_name=${TF_VAR_tenant_name}" -var "user_name=${TF_VAR_user_name}" -var "password=${TF_VAR_password}" 8 | # Clear contents of etcd_discovery_url.txt file to avoid polluting the repo by pusing unecessary content. 9 | > ${TF_VAR_etcd_discovery_url_file:-etcd_discovery_url.txt} 10 | popd 11 | } 12 | -------------------------------------------------------------------------------- /bootstrap/tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ../common.sh 4 | 5 | RED='\033[0;31m' 6 | NC='\033[0m' 7 | FAIL=0 8 | 9 | test() { 10 | function="$1" 11 | expected="$2" 12 | input="$3" 13 | result=$( "$1" ${*:3} ) 14 | 15 | if [ "${result}" == "${expected}" ]; then 16 | echo -e "Pass. Function ${function}. Expected: ${expected}, Got: ${result}\n" 17 | else 18 | echo -e "${RED}Fail. Function ${function}. Expected: ${expected}, Got: ${result}${NC}" 19 | FAIL=1 20 | fi 21 | } 22 | 23 | function="check_terraform_version" 24 | expected="You are running Terraform v0.6.0..." 25 | test "${function}" "${expected}" '0.5.0' 'v0.6.0' 26 | 27 | function="check_terraform_version" 28 | expected="You are running Terraform v0.5.0... 29 | Terraform >= 0.7.0 is required, please fix and retry." 30 | input="0.7.0" 31 | test "${function}" "${expected}" '0.7.0' 'v0.5.0' 32 | 33 | export TESTSUITE_var1="Galicia" 34 | export TESTSUITE_var2="Drupal" 35 | export TESTSUITE_var3="ip1 ip2 ip3" 36 | export TESTSUITE_var4="property=val property=val property=val" 37 | function="get_apollo_variables" 38 | input="TESTSUITE_" 39 | expected="var4='property=val property=val property=val' var2='Drupal' var3='ip1 ip2 ip3' var1='Galicia'" 40 | test "${function}" "${expected}" "${input}" 41 | 42 | # Network identifier helper function tests. 43 | function="get_network_identifier" 44 | expected="10" 45 | input="10.0.0.0/16" 46 | test "${function}" "${expected}" "${input}" 47 | 48 | function="get_network_identifier" 49 | expected="172" 50 | input="172.31.1.0/24" 51 | test "${function}" "${expected}" "${input}" 52 | 53 | exit "${FAIL}" 54 | -------------------------------------------------------------------------------- /bootstrap/vagrant/util.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Use the config file specified in $APOLLO_CONFIG_FILE, or default to 4 | # config-default.sh. 5 | APOLLO_ROOT=$(dirname "${BASH_SOURCE}")/../.. 6 | 7 | verify_prereqs() { 8 | if [[ "$(which vagrant)" == "" ]]; then 9 | echo -e "${color_red}Can't find vagrant in PATH, please fix and retry.${color_norm}" 10 | exit 1 11 | fi 12 | } 13 | 14 | apollo_launch() { 15 | install_contributed_roles 16 | vagrant up --provision 17 | open_urls 18 | } 19 | 20 | apollo_down() { 21 | vagrant destroy -f 22 | } 23 | -------------------------------------------------------------------------------- /contrib-plugins/.gitignore: -------------------------------------------------------------------------------- 1 | roles/* -------------------------------------------------------------------------------- /contrib-plugins/playbook.yml: -------------------------------------------------------------------------------- 1 | # Sample plugins playbook. 2 | - hosts: all:!role=bastion 3 | 4 | tasks: 5 | - name: reload systemd 6 | sudo: yes 7 | command: systemctl daemon-reload 8 | when: datadog_enabled|bool 9 | notify: 10 | - restart datadog-agent 11 | 12 | roles: 13 | - { role: datadog, when: datadog_enabled|bool } 14 | 15 | -------------------------------------------------------------------------------- /contrib-plugins/plugins.yml: -------------------------------------------------------------------------------- 1 | # Sample plugin. 2 | #- src: https://github.com/Capgemini/apollo-aurora-plugin.git 3 | # path: contrib-plugins/roles 4 | # name: aurora 5 | 6 | - src: https://github.com/wallies/ansible-datadog.git 7 | path: contrib-plugins/roles 8 | name: datadog 9 | -------------------------------------------------------------------------------- /dcos.yml: -------------------------------------------------------------------------------- 1 | - hosts: mesos_masters 2 | roles: 3 | - dcos_cli 4 | vars_files: 5 | - roles/prometheus/defaults/main.yml 6 | environment: 7 | DOCKER_HOST: "{{ docker_host }}" 8 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## Table of Contents 2 | 3 | * [Read Me](/README.md) 4 | * [Components](/docs/components/README.md) 5 | * [Ansible](/docs/components/ansible.md) 6 | * [Apache Mesos](/docs/components/apache-mesos.md) 7 | * [Consul](/docs/components/consul.md) 8 | * [Docker](/docs/components/docker.md) 9 | * [Terraform](/docs/components/terraform.md) 10 | * [Vault](/docs/components/vault.md) 11 | * [Weave](/docs/components/weave.md) 12 | * [Getting Started Guides](/docs/getting-started-guides/README.md) 13 | * [AWS VPC](/docs/getting-started-guides/aws.md) 14 | * [Setting up a VPN connection](/docs/getting-started-guides/aws/vpn.md) 15 | * [AWS Public](/docs/getting-started-guides/aws-public.md) 16 | * [DigitalOcean](/docs/getting-started-guides/digitalocean.md) 17 | * [Google Compute Engine](/docs/getting-started-guides/gce.md) 18 | * [Vagrant](/docs/getting-started-guides/vagrant.md) 19 | * [Examples](/docs/examples/README.md) 20 | * [Troubleshooting](/docs/Troubleshooting.md) 21 | * [Networking](/docs/networking.md) 22 | * [DNS](/docs/dns.md) 23 | * [Rolling Upgrades](/docs/platform-rolling-upgrades.md) 24 | * [Contributing](/CONTRIBUTING.md) 25 | * [Change Log](/CHANGELOG.md) 26 | * [Roadmap](/docs/roadmap.md) 27 | -------------------------------------------------------------------------------- /docs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Capgemini/Apollo/21f949d8cec5a07a97202cfcb67a0dbf8c90090b/docs/architecture.png -------------------------------------------------------------------------------- /docs/components/README.md: -------------------------------------------------------------------------------- 1 | ## Components 2 | 3 | Apollo is made up of a number of other open-source components. If you want more details on an individual component and the reasons behind utilising it see the below section. 4 | 5 | - **[Ansible](ansible.md)** 6 | - **[Apache Mesos](apache-mesos.md)** 7 | - **[Consul](consul.md)** 8 | - **[Docker](docker.md)** 9 | - **[Terraform](terraform.md)** 10 | - **[Vault](vault.md)** 11 | - **[Weave](weave.md)** 12 | -------------------------------------------------------------------------------- /docs/components/ansible.md: -------------------------------------------------------------------------------- 1 | ## Ansible 2 | 3 | We use [Ansible](http://docs.ansible.com/) to handle provisioning of instances in the cloud after they are spun up via [Terraform](terraform.md). 4 | 5 | Ansible is responsible for placing any config files in place, and starting up the relevant services on each type of node. 6 | 7 | The main decision behind choosing Ansible is the fact that only Python (2.6 or later) as well as Ansible installed is required on the control machine, and only Python (2.4 or later) is required on the remote machine. 8 | 9 | Due to the fact Python comes as standard on most operating systems there are no external dependencies to running Ansible. Since Ansible also uses just SSH to execute the remote commands it is very easy/quick to get installed and up and running. 10 | 11 | The other main reason is the use of [Ansible Dynamic Inventory](http://docs.ansible.com/intro_dynamic_inventory.html). This allows us to query remote cloud APIs to build Ansible host files, thus meaning we can keep IP addresses/host information completely out of configuration files. 12 | 13 | The ability to mix static inventory and dynamic inventory (See [http://docs.ansible.com/intro_dynamic_inventory.html#static-groups-of-dynamic-groups](http://docs.ansible.com/intro_dynamic_inventory.html#static-groups-of-dynamic-groups)) also gives us complete flexibility to map a static group of roles (e.g. mesos/zookeeper/weave etc.) on to dynamic host IPs (provisioned in the cloud). 14 | 15 | To view the default Ansible playbook see [site.yml](../../site.yml). 16 | The main Ansible configuration lies in the following directories: 17 | 18 | - [inventory](../../inventory) 19 | - [roles](../../roles) 20 | - [group_vars](../../group_vars) 21 | -------------------------------------------------------------------------------- /docs/components/apache-mesos.md: -------------------------------------------------------------------------------- 1 | ## Apache Mesos 2 | 3 | [Apache Mesos](http://mesos.apache.org/) is used for cluster management, orchestration and resource scheduling. 4 | 5 | The main reason behind choosing it is detailed on their website - 6 | 7 | > "Apache Mesos abstracts CPU, memory, storage, and other compute resources away from machines (physical or virtual), enabling fault-tolerant and elastic distributed systems to easily be built and run effectively." 8 | 9 | Other reasons to select it include - 10 | 11 | * Non opinionated in what type of framework / what is run on top of it. This means any type of framework can be built on Mesos which uses the underlying resource and scheduling APIs 12 | * Frameworks can be written in any language, and their are language bindings for Go, Python, Scala, C++ and Java 13 | * Fault tolerant out of the box (via replicated master/agents using Zookeeper) 14 | * Scalable out of the box 15 | * Simplify's the view of the datacenter treating a cluster of machines, like looking down at one big machine. 16 | * Large number of frameworks already existing, suiting different use cases. See [http://mesos.apache.org/documentation/latest/mesos-frameworks/](http://mesos.apache.org/documentation/latest/mesos-frameworks/) for a list of frameworks. 17 | * Used in production by a number of large companies including Apple, Twitter, AirBnB 18 | -------------------------------------------------------------------------------- /docs/components/consul.md: -------------------------------------------------------------------------------- 1 | ## Consul 2 | 3 | Consul is used for service discovery of nodes and services in the cluster. 4 | 5 | It has a number of key features - 6 | 7 | - Key / value storage 8 | - HTTP REST API 9 | - DNS API 10 | - Highly available / fault tolerant out of the box 11 | - Health checks 12 | - Multi-datacenter support out of the box 13 | 14 | For a comparison of Consul against other service discovery backends see [https://www.consul.io/intro/vs/zookeeper.html](https://www.consul.io/intro/vs/zookeeper.html) 15 | 16 | The main reasons for selecting Consul over the others are - 17 | 18 | - DNS API providing lightweight integration with other tools / services 19 | - Easy integration with Docker via the mesos-consul container. See [https://github.com/CiscoCloud/mesos-consul](https://github.com/CiscoCloud/mesos-consul) 20 | - Easy integration with Weave. For more info about weave see [weave](weave.md) 21 | - Rich key/value storage for use with Docker containers / services 22 | 23 | For more information on how service discovery via DNS works in Apollo see [DNS](../../docs/dns.md). 24 | 25 | For more information on Consul see [http://www.consul.io](http://www.consul.io) 26 | or [https://github.com/hashicorp/consul](https://github.com/hashicorp/consul). 27 | -------------------------------------------------------------------------------- /docs/components/docker.md: -------------------------------------------------------------------------------- 1 | ## Docker 2 | 3 | Docker is used as an application container runtime. The main usage is for running 4 | containers (as a task) on top of Mesos via a Mesos framework. 5 | 6 | For example the [Marathon](https://github.com/mesosphere/marathon) 7 | and [Kubernetes](http://kubernetes.io) can both utilise Docker to deploy, 8 | manage and run containers. 9 | 10 | For more information on Docker see [https://www.docker.com](https://www.docker.com) 11 | 12 | Docker allows a clear separation between the application/task 13 | and the underlying operating system. As such this gives developers full flexibility 14 | about what they choose to run on top of Apollo. 15 | 16 | We use Docker in combination with [Weave](weave.md), with weave providing the virtual 17 | networking layer which makes accessing Docker containers across multiple hosts simpler. 18 | -------------------------------------------------------------------------------- /docs/components/logging.md: -------------------------------------------------------------------------------- 1 | ## Logging 2 | 3 | The ELK stack (Elasticsearch, Logstash and Kibana) is used as the central logging solution. 4 | These are deployed through [Marathon](https://github.com/mesosphere/marathon). 5 | 6 | On each host we have a [Logstash-forwarder](https://github.com/elastic/logstash-forwarder) container which is configured to watch for logs in '/var/lib/docker//-json.log'. We have also configured it to watch files in '/var/log/syslog' and '/var/log/consul'. When a new container starts up we have [docker-gen](https://github.com/jwilder/docker-gen) container which will re-generate our logstash-forwarder config file from docker container meta-data. 7 | 8 | To run this with your own certificate and private key set these to variables 9 | 10 | export APOLLO_lumberjack_ssl_key_file 11 | export APOLLO_lumberjack_ssl_certificate_file 12 | 13 | The whole ELK stack can be disabled in the group_vars/all -> elk_enabled: false 14 | 15 | ### Salesforce Logging 16 | We have also added the capability to enable salesforce integration in roles/logstash/defaults/main.yml. By enabling logstash_salesforce: yes, salesforce data will be imported into logstash and stored in elasticsearch. You can then create some nice visualisations in Kibana based on this data. To enable this you will need to enable these variables: 17 | 18 | export APOLLO_salesforce_client_id 19 | export APOLLO_salesforce_client_secret 20 | export APOLLO_salesforce_username 21 | export APOLLO_salesforce_password 22 | export APOLLO_salesforce_security_token 23 | 24 | # ELB Logging 25 | We have enabled the capability for the ELB to log to s3 bucket and then be sucked into logstash. We need to set these to variables for this to work. 26 | 27 | export TF_VAR_s3_bucket_name 28 | export AWS_ACCESS_KEY_ID 29 | export AWS_SECRET_ACCESS_KEY 30 | -------------------------------------------------------------------------------- /docs/components/terraform.md: -------------------------------------------------------------------------------- 1 | ## Terraform 2 | 3 | We use [Terraform](https://www.terraform.io/) as an infrastructure provisioning tool. This allows us to declare the state of our infrastructure against various [cloud providers](https://www.terraform.io/docs/providers/index.html). 4 | 5 | The general flow is (for example for Amazon) - 6 | 7 | - Run a terraform plan to provision the necessary instances in AWS corresponding to the architecture we have chosen (e.g. public cloud / private VPC) 8 | - Run Ansible on top of those instances to configure them on the fly and start up the necessary services to bring an Apollo cluster up. 9 | -------------------------------------------------------------------------------- /docs/components/vault.md: -------------------------------------------------------------------------------- 1 | ## Vault 2 | 3 | We use [Vault](https://vaultproject.io/) for for securely accessing secrets. 4 | 5 | The main decision behind choosing Vault is its easy integration with Consul as a [secret backend](https://vaultproject.io/docs/secrets/index.html). 6 | 7 | Vault provides "a unified interface to any secret, while providing tight access control and recording a detailed audit log". 8 | 9 | Vault credentials are autogenerate and stored in vault-security.yaml i.e root_roken and keys. 10 | -------------------------------------------------------------------------------- /docs/components/weave.md: -------------------------------------------------------------------------------- 1 | ## Weave 2 | 3 | We use [weave](zettio.github.io/weave/) to provide an overlay network for Docker containers. 4 | This allows each Docker container to have its own IP address / port in the overlay network and for container to container communication to happen in the overlay network without the need for host port mapping or statically linking Docker containers together. 5 | 6 | For more information on how networking works in Apollo see [networking](../networking.md) 7 | -------------------------------------------------------------------------------- /docs/dns.md: -------------------------------------------------------------------------------- 1 | ## DNS in Apollo 2 | 3 | We use a combination of [mesos-consul](https://github.com/CiscoCloud/mesos-consul) 4 | and Consul to provide DNS for services/tasks that are started via Mesos/Marathon. 5 | 6 | ### How it works 7 | 8 | When a Mesos task starts up it publishes its information (IP address and port) 9 | to the Consul backend via [mesos-consul](https://github.com/CiscoCloud/mesos-consul). 10 | 11 | The mesos_consul Docker container is running on every master instance and is subscribing to changes 12 | via the Mesos API. 13 | 14 | When a Mesos task is killed or removed, mesos-consul subsequently takes care of removing 15 | the service registry information from Consul. 16 | 17 | By default the name of the service will be equivalent to what it is started up via marathon (at appname.service.consul). 18 | -------------------------------------------------------------------------------- /docs/getting-started-guides/README.md: -------------------------------------------------------------------------------- 1 | IaaS Provider | Config. Mgmt | OS | Networking | Docs | Support Level | Notes 2 | -------------- | ------------ | ------ | ---------- | ---------------------------------------------------- | ---------------------------- | ----- 3 | AWS | Ansible | CoreOS | Weave | [docs](../../docs/getting-started-guides/aws.md) | Project | AWS private VPC with NAT gateway server for SSH/VPN 4 | AWS Public Cloud | Ansible | CoreOS | Weave | [docs](../../docs/getting-started-guides/aws-public.md) | Project | Public cloud instances 5 | Vagrant | Ansible | CoreOS | Weave | [docs](../../docs/getting-started-guides/vagrant.md) | Project | 6 | Digitalocean | Ansible | CoreOS | Weave | [docs](../../docs/getting-started-guides/digitalocean.md) | Project | Public cloud instances 7 | Rackspace | Ansible | CoreOS | Weave | [docs](../../docs/getting-started-guides/rackspace.md) | Project | Public cloud instances 8 | 9 | 10 | Definition of columns: 11 | 12 | - **IaaS Provider** is who/what provides the virtual or physical machines (nodes) that Apollo runs on. 13 | - **OS** is the base operating system of the nodes. 14 | - **Config. Mgmt** is the configuration management system that helps install and maintain apollo software on the 15 | nodes. 16 | - **Networking** is what implements the networking model. Those with networking type 17 | _none_ may not support more than one node, or may support multiple VM nodes only in the same physical node. 18 | - Support Levels 19 | - **Project**: Apollo Committers regularly use this configuration, so it usually works with the latest release 20 | of Apollo. 21 | - **Commercial**: A commercial offering with its own support arrangements. 22 | - **Community**: Actively supported by community contributions. May not work with more recent releases of Apollo. 23 | - **Inactive**: No active maintainer. Not recommended for first-time Apollo users, and may be deleted soon. 24 | -------------------------------------------------------------------------------- /docs/getting-started-guides/aws-public.md: -------------------------------------------------------------------------------- 1 | ## Getting started on AWS 2 | 3 | ### Prerequisites 4 | 5 | 1. You need an AWS account. Visit [http://aws.amazon.com](http://aws.amazon.com) to get started 6 | 2. You need an AWS [instance profile and role](http://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) with EC2 full access. 7 | 4. You need to have installed and configured Terraform (>= 0.6.10 recommended). Visit [https://www.terraform.io/intro/getting-started/install.html](https://www.terraform.io/intro/getting-started/install.html) to get started. 8 | 6. You need to have [Python](https://www.python.org/) >= 2.7.5 installed along with [pip](https://pip.pypa.io/en/latest/installing.html). 9 | 7. You will need to have created an SSH RSA key pair for accessing your aws intances. You can create it as follows: 10 | 11 | ``` 12 | cd ~/.ssh 13 | ssh-keygen -P "" -t rsa -f id_rsa_aws -b 4096 -C "email@example.com" 14 | openssl rsa -in ~/.ssh/id_rsa_aws -outform pem > id_rsa_aws.pem 15 | chmod 400 id_rsa_aws.pem 16 | eval `ssh-agent -s` 17 | ssh-add id_rsa_aws.pem 18 | ``` 19 | 20 | ### Cluster Turnup 21 | 22 | #### Download Apollo 23 | 24 | ##### Install from source at head 25 | 1. `git clone https://github.com/Capgemini/apollo.git` 26 | 2. `cd apollo` 27 | 3. `pip install -r requirements.txt` 28 | 29 | #### Set config 30 | 31 | Configuration can be set via environment variables. 32 | 33 | All variables following the pattern "TF_VAR_" will be available for Apollo in terraform, see [https://github.com/hashicorp/terraform/pull/1621#issuecomment-100825568](https://github.com/hashicorp/terraform/pull/1621#issuecomment-100825568) 34 | 35 | All variables following pattern "APOLLO_" will be available for Apollo in ansible. 36 | 37 | For a full list of default config options for AWS see `bootstrap/aws-public/config-default.sh` 38 | 39 | As a minimum you will need to set these environment variables - 40 | 41 | ``` 42 | APOLLO_PROVIDER=aws/public-cloud 43 | TF_VAR_access_key 44 | TF_VAR_secret_key 45 | TF_VAR_key_name="deployer" 46 | TF_VAR_key_file='~/.ssh/id_rsa_aws.pub' 47 | TF_VAR_public_key_file='~/.ssh/id_rsa_aws.pub' 48 | ``` 49 | 50 | #### Turn up the cluster 51 | ``` 52 | /bin/bash bootstrap/apollo-launch.sh 53 | ``` 54 | 55 | NOTE: The script will provision a new VPC and a 3 node mesos master cluster across all the availability zones in eu-west-1 (Ireland). 56 | 57 | #### Tearing down the cluster 58 | ``` 59 | /bin/bash bootstrap/apollo-down.sh 60 | ``` 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/getting-started-guides/aws/vpn.md: -------------------------------------------------------------------------------- 1 | # How to Configure OpenVPN Server and Generate Client Configuration 2 | 3 | The below steps configure the VPN server and generate a client 4 | configuration to connect with the OpenVPN client from your workstation. 5 | This is required if you wish to access the web UI of machines running 6 | in the private VPC (e.g. consul UI / Mesos / Marathon) 7 | 8 | ### Pre-requisites 9 | 10 | * Install aws cli to generate key-pair - https://github.com/aws/aws-cli 11 | * Generate key-pair - http://www.dowdandassociates.com/blog/content/howto-create-an-amazon-ec2-key-pair-using-the-aws-cli/ 12 | * Add the key to your keychain 13 | 14 | ``` 15 | ssh-add -K 16 | ``` 17 | 18 | ### Steps 19 | 20 | 1: Initialize PKI 21 | 22 | 23 | ``` 24 | bin/ovpn-init 25 | ``` 26 | 27 | The above command will prompt you for a passphrase for the root 28 | certificate. Choose a strong passphrase and store it some where safe. 29 | This passphrase is required every time you generate a new client 30 | configuration. 31 | 32 | 2: Start the VPN server 33 | 34 | ``` 35 | bin/ovpn-start 36 | ``` 37 | 3: Generate client certificate 38 | 39 | ``` 40 | bin/ovpn-new-client $USER 41 | ``` 42 | 43 | Where $USER is the username you want to generate a connection config 44 | for. 45 | 46 | 4: Download OpenVPN client configuration 47 | 48 | ``` 49 | bin/ovpn-client-config $USER 50 | ``` 51 | 52 | The above command creates a $USER-apollo.ovpn client 53 | configuration file in the current directory. Double-click on the file to 54 | import the configuration to your VPN client 55 | 56 | # You will also need to sed or edit $USER-apollo.ovpn file andreplace ovpn gateway with the correct IP address, because we are getting the bastion instance IP address not the elastic IP address in the downloaded file. 57 | 58 | ### Connecting to the VPN server (Mac OS X) 59 | 60 | This assumes you have followed steps 1-4 above and have a downloaded 61 | $USER-cagpemini-mesos.ovpn file 62 | 63 | 1. Download and install 64 | [Tunnelblick](https://code.google.com/p/tunnelblick/wiki/DownloadsEntry?tm=2#Tunnelblick_Stable_Release) 65 | 2. Double click the $USER-capgemini-mesos-ovpn file. This should open it 66 | with Tunnelblick 67 | 3. Connect to the VPN 68 | 69 | Once connected you should be able to access the following - 70 | 71 | * [Mesos Master UI] (http://10.0.1.11:5050) 72 | * [Marathon UI] (http://10.0.1.11:8080) 73 | * [Consul Web UI] (http://10.0.1.11:8500) 74 | -------------------------------------------------------------------------------- /docs/getting-started-guides/digitalocean.md: -------------------------------------------------------------------------------- 1 | ## Getting started on Digital Ocean 2 | 3 | ### Prerequisites 4 | 5 | 1. You need an Digital Ocean account. Visit [https://cloud.digitalocean.com/registrations/new](https://cloud.digitalocean.com/registrations/new) to get started 6 | 4. You need to have installed and configured Terraform (>= 0.6.10 recommended). Visit [https://www.terraform.io/intro/getting-started/install.html](https://www.terraform.io/intro/getting-started/install.html) to get started. 7 | 5. You need to have [Python](https://www.python.org/) >= 2.7.5 installed along with [pip](https://pip.pypa.io/en/latest/installing.html). 8 | 6. You will need to have created an SSH RSA key pair for accessing your Digitalocean 9 | droplets. Execute `ssh-keygen -t rsa` to create a key pair. 10 | 11 | ### Cluster Startup 12 | 13 | #### Download Apollo 14 | 15 | ##### Install from source at head 16 | 1. `git clone https://github.com/Capgemini/apollo.git` 17 | 2. `cd apollo` 18 | 3. `pip install -r requirements.txt` 19 | 20 | #### Set config 21 | 22 | Configuration can be set via environment variables. 23 | 24 | All variables following the pattern "TF_VAR_" will be available for Apollo in terraform, see [https://github.com/hashicorp/terraform/pull/1621#issuecomment-100825568](https://github.com/hashicorp/terraform/pull/1621#issuecomment-100825568) 25 | 26 | All variables following the pattern "APOLLO_" will be available for Apollo in ansible. 27 | 28 | For a full list of default config options for Digital Ocean see `bootstrap/digitalocean/config-default.sh` 29 | 30 | As a minimum you will need to set these environment variables - 31 | 32 | ``` 33 | # v2 API token 34 | 35 | TF_VAR_do_token= 36 | 37 | ``` 38 | To generate a v2 API token see [https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocea n-api-v2](https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2) 39 | 40 | 41 | ``` 42 | APOLLO_PROVIDER=digitalocean 43 | 44 | # Path to your public ssh key (created in prerequisite step 6 above). 45 | TF_VAR_public_key_file= 46 | ``` 47 | 48 | #### Start up the cluster 49 | ``` 50 | /bin/bash bootstrap/apollo-launch.sh 51 | ``` 52 | 53 | NOTE: The script will provision a 3 node mesos master cluster in lon1 (UK) by default. It will also create a mesos agent cluster and a SSH key so you can access the droplets. 54 | 55 | 56 | #### Tearing down the cluster 57 | ``` 58 | /bin/bash bootstrap/apollo-down.sh 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/platform-rolling-upgrades.md: -------------------------------------------------------------------------------- 1 | ## Rolling upgrades of the platform 2 | 3 | we provide two playbooks for upgrading the differents components of the platform with ease. 4 | 5 | You can specify which bits to upgrade by using ansible tags. E.g: 6 | ``` export ANSIBLE_TAGS=weave,mesos_maintenance``` 7 | 8 | ### Software maintenance of the cluster 9 | 10 | ``` /bin/bash bootstrap/apollo-launch.sh ansible_upgrade_maintenance ``` 11 | 12 | By using ```mesos_maintenance``` Apollo assumes you have schedule a [Mesos maintenance](http://mesos.apache.org/documentation/latest/maintenance/). 13 | 14 | Apollo will [set the machine down](http://mesos.apache.org/documentation/latest/endpoints/master/machine/down/), run ansible, and [set the machine up](http://mesos.apache.org/documentation/latest/endpoints/master/machine/up/) squentially in every host. 15 | 16 | ### Upgrading Mesos/Marathon 17 | 18 | ``` /bin/bash bootstrap/apollo-launch.sh ansible_upgrade_mesoscluster ``` 19 | 20 | TODOs: 21 | 22 | * Consul Maintenance. 23 | * Handle systemd dependencies explicitly. 24 | -------------------------------------------------------------------------------- /docs/roadmap.md: -------------------------------------------------------------------------------- 1 | Apollo Roadmap 2 | ============== 3 | 4 | Mesos Frameworks 5 | -------- 6 | - [x] Marathon framework 7 | - [ ] Jenkins framework 8 | - [x] Aurora framework 9 | - [x] Chronos framework 10 | - [ ] Kubernetes framework 11 | - [x] Cassandra framework 12 | - [ ] Myriad framework 13 | - [x] Spark framework 14 | - [ ] Storm framework 15 | - [ ] Mysos framework 16 | - [ ] Elastiseach framework 17 | - [ ] Mesosaurus framework 18 | - [ ] Kafka framework 19 | 20 | Providers 21 | --------- 22 | - [x] Vagrant 23 | - [x] AWS 24 | - [x] Digitalocean 25 | - [x] Google Cloud 26 | - [ ] Openstack 27 | - [ ] Microsoft Azure 28 | 29 | Operating Systems 30 | ----------------- 31 | - [x] CoreOS 32 | 33 | Features 34 | -------- 35 | - [x] Easier pluggability for frameworks 36 | - [x] Move all services to Docker containers 37 | - [x] Monitoring and alerts(nodes/services) 38 | - [x] Logging (nodes/services) 39 | - [ ] Metrics (nodes/services) 40 | - [ ] Distributed File storage (for nodes/services) 41 | - [ ] Multi-Datacenter 42 | - [ ] Multi-Cloud 43 | - [ ] Autoscaling of Mesos agent nodes 44 | - [x] GPU Support 45 | 46 | Security 47 | -------- 48 | - [x] Turn SELinux on to enforce 49 | - [x] Utilise Docker Audit Toolkit in CI 50 | - [ ] Manage Linux user accounts with Consul + Vault 51 | - [ ] ACLs and encrpytion for Consul 52 | - [ ] Encrypt network traffic with Weave 53 | - [ ] Authentication and authorization for Mesos 54 | - [ ] Authentication and authorization for Marathon 55 | - [ ] Application dynamic firewalls (using consul template) 56 | - [ ] Network and Data encryption with IPsec 57 | - [ ] Add AppArmor/Seccomp profiles to docker containers 58 | 59 | Demonstrators / Examples 60 | ------------------------ 61 | - [ ] Continous Deployment with Marathon 62 | - [ ] Mule ESB 63 | - [x] Drupal / MySQL 64 | - [x] Wordpress / MySQL 65 | - [x] Simple NodeJS webservice 66 | - [x] Spring Boot microservice 67 | - [ ] Jmeter 68 | - [ ] API Management 69 | 70 | Documentation 71 | ------------- 72 | - [x] Architecture diagram of components 73 | - [x] Component overview and decision log 74 | - [x] Getting started guides for supported providers 75 | -------------------------------------------------------------------------------- /examples/drupal-mysql/commerce-kickstart.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "commerce-kickstart", 3 | "apps": [ 4 | { 5 | "id": "mysql", 6 | "container": { 7 | "type": "DOCKER", 8 | "docker": { 9 | "image": "mysql:5.5", 10 | "network": "BRIDGE" 11 | } 12 | }, 13 | "env": { 14 | "SERVICE_NAME": "mysql", 15 | "SERVICE_TAGS": "commerce-kickstart", 16 | "MYSQL_DATABASE": "commerce-kickstart", 17 | "MYSQL_USER": "ckuser", 18 | "MYSQL_PASSWORD": "ckuser", 19 | "MYSQL_ROOT_PASSWORD": "password" 20 | }, 21 | "cpus": 1, 22 | "mem": 1024.0, 23 | "instances": 1 24 | }, 25 | { 26 | "id": "web", 27 | "container": { 28 | "type": "DOCKER", 29 | "docker": { 30 | "image": "capgemini/apollo-commerce-kickstart:latest", 31 | "network": "BRIDGE", 32 | "portMappings": [{ 33 | "containerPort": 80, 34 | "hostPort": 0, 35 | "protocol": "tcp" 36 | }] 37 | } 38 | }, 39 | "env": { 40 | "SERVICE_NAME": "commerce-kickstart", 41 | "DRUPAL_DB_PASSWORD": "password", 42 | "DRUPAL_DB_NAME": "commerce-kickstart", 43 | "DRUPAL_DB_HOST": "commerce-kickstart.mysql.service.consul" 44 | }, 45 | "cpus": 1, 46 | "mem": 512.0, 47 | "instances": 1, 48 | "dependencies": ["/commerce-kickstart/mysql"] 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /examples/drupal-mysql/drupal7.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "drupal-7", 3 | "apps": [ 4 | { 5 | "id": "mysql", 6 | "container": { 7 | "type": "DOCKER", 8 | "docker": { 9 | "image": "mysql:5.5", 10 | "network": "BRIDGE" 11 | } 12 | }, 13 | "env": { 14 | "SERVICE_NAME": "mysql", 15 | "SERVICE_TAGS": "drupal7", 16 | "MYSQL_DATABASE": "drupal7", 17 | "MYSQL_USER": "drupal7", 18 | "MYSQL_PASSWORD": "drupal7", 19 | "MYSQL_ROOT_PASSWORD": "password" 20 | }, 21 | "cpus": 1, 22 | "mem": 1024.0, 23 | "instances": 1 24 | }, 25 | { 26 | "id": "drupal7", 27 | "container": { 28 | "type": "DOCKER", 29 | "docker": { 30 | "image": "drupal:7", 31 | "network": "BRIDGE", 32 | "portMappings": [{ 33 | "containerPort": 80, 34 | "hostPort": 0, 35 | "protocol": "tcp" 36 | }] 37 | } 38 | }, 39 | "env": { 40 | "SERVICE_NAME": "drupal7", 41 | "DRUPAL_DB_PASSWORD": "password", 42 | "DRUPAL_DB_NAME": "drupal7", 43 | "DRUPAL_DB_HOST": "drupal7.mysql.service.consul" 44 | }, 45 | "cpus": 1, 46 | "mem": 512.0, 47 | "instances": 1, 48 | "healthChecks": [{ 49 | "path": "/", 50 | "portIndex": 0, 51 | "protocol": "HTTP", 52 | "gracePeriodSeconds": 30, 53 | "intervalSeconds": 10, 54 | "timeoutSeconds": 20, 55 | "maxConsecutiveFailures": 3 56 | }], 57 | "dependencies": ["/drupal-7/mysql"] 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /examples/drupal-mysql/drupal8.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "drupal-8", 3 | "apps": [ 4 | { 5 | "id": "mysql", 6 | "container": { 7 | "type": "DOCKER", 8 | "docker": { 9 | "image": "mysql:5.5", 10 | "network": "BRIDGE" 11 | } 12 | }, 13 | "env": { 14 | "SERVICE_NAME": "mysql", 15 | "SERVICE_TAGS": "drupal8", 16 | "MYSQL_DATABASE": "drupal8", 17 | "MYSQL_USER": "drupal8", 18 | "MYSQL_PASSWORD": "drupal8", 19 | "MYSQL_ROOT_PASSWORD": "password" 20 | }, 21 | "cpus": 1, 22 | "mem": 1024.0, 23 | "instances": 1 24 | }, 25 | { 26 | "id": "drupal8", 27 | "container": { 28 | "type": "DOCKER", 29 | "docker": { 30 | "image": "drupal:8", 31 | "network": "BRIDGE", 32 | "portMappings": [{ 33 | "containerPort": 80, 34 | "hostPort": 0, 35 | "protocol": "tcp" 36 | }] 37 | } 38 | }, 39 | "env": { 40 | "SERVICE_NAME": "drupal8", 41 | "DRUPAL_DB_PASSWORD": "password", 42 | "DRUPAL_DB_NAME": "drupal8", 43 | "DRUPAL_DB_HOST": "drupal8.mysql.service.consul" 44 | }, 45 | "cpus": 1, 46 | "mem": 512.0, 47 | "instances": 1, 48 | "healthChecks": [{ 49 | "path": "/", 50 | "portIndex": 0, 51 | "protocol": "HTTP", 52 | "gracePeriodSeconds": 30, 53 | "intervalSeconds": 10, 54 | "timeoutSeconds": 20, 55 | "maxConsecutiveFailures": 3 56 | }], 57 | "dependencies": ["/drupal-8/mysql"] 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /examples/mattermost/README.md: -------------------------------------------------------------------------------- 1 | ## Mattermost Platform example 2 | 3 | This example shows how to deploy Mattermost using Apollo and Marathon Mesos framework. 4 | 5 | The example includes - 6 | 7 | * Mattermost an open source, on-prem Slack-alternative 8 | 9 | We'll use the [mattermost](https://hub.docker.com/r/mattermost/platform/) [Docker](https://www.docker.com/) image. 10 | 11 | The examples are to be deployed on top of the Marathon Mesos framework. 12 | 13 | ### Start the Mattermost Platform 14 | 15 | Start the services by running the following command (from somewhere you can access the REST interface of Marathon). Replace $MARATHON_IP with the actual hostname/ip address of the marathon instance. 16 | Marathon by default should be deployed in the ```mesos_master``` nodes. 17 | 18 | ``` 19 | curl -X POST -HContent-Type:application/json -d @chatops.json http://$MARATHON_IP:8080/v2/apps 20 | ``` 21 | 22 | The service will be accessible through the HAProxy container (on port 80) at ```chatops.example.com``` by default. It is recommended that you set up your own DNS servers / hostname and override the ```haproxy_domain``` in [../roles/haproxy/defaults/main.yml](../roles/haproxy/defaults/main.yml). 23 | 24 | ### For cloud instances 25 | 26 | To access the Mattermost application, go to the Marathon dashboard at ```http://$MARATHON_IP:8080/#apps``` and click on ```/chatops```. You should see an IP address and Port in the service definition, if you click on it you should be redirected to the mattermost application. 27 | 28 | ### For Vagrant only 29 | 30 | If you are deploying this example in the Vagrant environment, simply add the following entry to your host machine in ```/etc/hosts``` 31 | 32 | ``` 33 | 172.31.1.14 chatops.example.com 34 | ``` 35 | 36 | Where ```172.31.1.14``` is the Agent IP address configured in ```vagrant.yml``` 37 | If you access ```chatops.example.com``` through your browser that will hit the Haproxy container 38 | running on the agent machine which will forward the traffic to the mattermost container. 39 | 40 | ### Removing the apps 41 | 42 | You can remove the applications straight from the command line by running - 43 | 44 | ``` 45 | curl -XDELETE http://$MARATHON_IP:8080/v2/apps/chatops 46 | ``` 47 | -------------------------------------------------------------------------------- /examples/mattermost/chatops.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "chatops", 3 | "instances": 1, 4 | "cpus": 0.2, 5 | "mem": 1024, 6 | "labels": { 7 | "DCOS_PACKAGE_NAME": "chatops", 8 | "DCOS_PACKAGE_IS_FRAMEWORK": "false" 9 | }, 10 | "healthChecks": [ 11 | { 12 | "gracePeriodSeconds": 120, 13 | "intervalSeconds": 15, 14 | "maxConsecutiveFailures": 10, 15 | "path": "/", 16 | "portIndex": 0, 17 | "protocol": "HTTP", 18 | "timeoutSeconds": 5 19 | } 20 | ], 21 | "container": { 22 | "type": "DOCKER", 23 | "volumes": [ 24 | { 25 | "containerPath": "/var/run/docker.sock", 26 | "hostPath": "/var/run/docker.sock", 27 | "mode": "RO" 28 | } 29 | ], 30 | "docker": { 31 | "image": "mattermost/platform", 32 | "network": "BRIDGE", 33 | "portMappings": [ 34 | { 35 | "containerPort": 8065, 36 | "hostPort": 0, 37 | "servicePort": 8065, 38 | "protocol": "tcp" 39 | } 40 | ] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/nodejs-rest-api/README.md: -------------------------------------------------------------------------------- 1 | ## Simple nodejs REST API service 2 | 3 | This example contains a simple nodejs REST service that is self-contained and 4 | has a single endpoint exposed. The endpoint returns a simple JSON response that 5 | just returns the version of itself. 6 | 7 | For example the v1 container (1.0.0) will return "1.0.0" as its version, whereas 8 | the v2 container (2.0.0) will return "2.0.0" as its version. This container is 9 | mostly used to demonstrate some basic concepts of the Apollo platform. 10 | 11 | These examples includes - 12 | 13 | * A nodejs container containing a simple rest service with a single endpoint 14 | at / 15 | 16 | ### Start the service 17 | 18 | ``` 19 | curl -X POST -HContent-Type:application/json -d @nodejs-rest-api-v1.json $MARATHON_IP:8080/v2/apps 20 | ``` 21 | 22 | The service will be accessible through the HAProxy container (on port 80) at ```nodejs-rest-api.example.com``` by default. It is recommended that you set up your own DNS servers / hostname and override the ```haproxy_domain``` in [../roles/haproxy/defaults/main.yml](../roles/haproxy/defaults/main.yml). 23 | 24 | ### Removing the app 25 | 26 | You can remove the application straight from the command line by running - 27 | 28 | ``` 29 | curl -XDELETE http://$MARATHON_IP:8080/v2/apps/nodejs-rest-api 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/nodejs-rest-api/nodejs-rest-api-v1.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "nodejs-rest-api", 3 | "container": { 4 | "type": "DOCKER", 5 | "docker": { 6 | "image": "capgemini/apollo-example-nodejs-rest:1.0.0", 7 | "network": "BRIDGE", 8 | "portMappings": [ 9 | { 10 | "containerPort": 8080, 11 | "hostPort": 0, 12 | "protocol": "tcp" 13 | } 14 | ] 15 | } 16 | }, 17 | "healthChecks": [ 18 | { 19 | "path": "/", 20 | "portIndex": 0, 21 | "protocol": "HTTP", 22 | "gracePeriodSeconds": 3, 23 | "intervalSeconds": 10, 24 | "timeoutSeconds": 10, 25 | "maxConsecutiveFailures": 3 26 | } 27 | ], 28 | "cpus": 0.3, 29 | "mem": 64.0, 30 | "instances": 2, 31 | "upgradeStrategy": { 32 | "minimumHealthCapacity": 1, 33 | "maximumOverCapacity": 0.1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/nodejs-rest-api/nodejs-rest-api-v2.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "nodejs-rest-api-v2", 3 | "container": { 4 | "type": "DOCKER", 5 | "docker": { 6 | "image": "capgemini/apollo-example-nodejs-rest:2.0.0", 7 | "network": "BRIDGE", 8 | "portMappings": [ 9 | { 10 | "containerPort": 8080, 11 | "hostPort": 0, 12 | "protocol": "tcp" 13 | } 14 | ] 15 | } 16 | }, 17 | "labels": { 18 | "traefik.backend": "backend-nodejs-rest-api" 19 | }, 20 | "ports": [0], 21 | "healthChecks": [ 22 | { 23 | "path": "/", 24 | "portIndex": 0, 25 | "protocol": "HTTP", 26 | "gracePeriodSeconds": 3, 27 | "intervalSeconds": 10, 28 | "timeoutSeconds": 10, 29 | "maxConsecutiveFailures": 3 30 | } 31 | ], 32 | "cpus": 0.3, 33 | "mem": 64.0, 34 | "instances": 1, 35 | "upgradeStrategy": { 36 | "minimumHealthCapacity": 1, 37 | "maximumOverCapacity": 0.1 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/spring-boot/README.md: -------------------------------------------------------------------------------- 1 | ## Spring Boot example 2 | 3 | This example shows how to deploy spring boot application using Apollo and Marathon Mesos framework. 4 | 5 | The example includes - 6 | 7 | * A custom spring boot application 8 | 9 | We'll use the [spring-boot](https://registry.hub.docker.com/u/capgemini/apollo-spring-boot/) [Docker](https://www.docker.com/) image. 10 | 11 | The examples are to be deployed on top of the Marathon Mesos framework. 12 | 13 | ### Start the Spring Boot Application 14 | 15 | Start the services by running the following command (from somewhere you can access the REST interface of Marathon). Replace $MARATHON_IP with the actual hostname/ip address of the marathon instance. 16 | Marathon by default should be deployed in the ```mesos_master``` nodes. 17 | 18 | ``` 19 | curl -X POST -HContent-Type:application/json -d @spring-boot.json http://$MARATHON_IP:8080/v2/apps 20 | ``` 21 | 22 | The service will be accessible through the HAProxy container (on port 80) at ```springboot.example.com``` by default. It is recommended that you set up your own DNS servers / hostname and override the ```haproxy_domain``` in [../roles/haproxy/defaults/main.yml](../roles/haproxy/defaults/main.yml). 23 | 24 | ### For cloud instances 25 | 26 | To access the Spring Boot application, go to the Marathon dashboard at ```http://$MARATHON_IP:8080/#apps``` and click on ```/springboot```. You should see an IP address and Port in the service definition, if you click on it you should be redirected to the spring boot application. 27 | 28 | ### For Vagrant only 29 | 30 | If you are deploying this example in the Vagrant environment, simply add the following entry to your host machine in ```/etc/hosts``` 31 | 32 | ``` 33 | 172.31.1.14 springboot.example.com 34 | ``` 35 | 36 | Where ```172.31.1.14``` is the Agent IP address configured in ```vagrant.yml``` 37 | If you access ```springboot.example.com``` through your browser that will hit the Haproxy container 38 | running on the agent machine which will forward the traffic to the Drupal docker container. 39 | 40 | ### Removing the apps 41 | 42 | You can remove the applications straight from the command line by running - 43 | 44 | ``` 45 | curl -XDELETE http://$MARATHON_IP:8080/v2/apps/springboot 46 | ``` 47 | -------------------------------------------------------------------------------- /examples/spring-boot/spring-boot.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "/springboot", 3 | "container": { 4 | "docker": { 5 | "type": "DOCKER", 6 | "image": "capgemini/apollo-spring-boot:1.0.1", 7 | "network": "BRIDGE", 8 | "portMappings": [ 9 | { 10 | "containerPort": 8080, 11 | "hostPort": 0, 12 | "protocol": "tcp" 13 | } 14 | ] 15 | } 16 | }, 17 | "healthChecks": [{ 18 | "protocol": "TCP", 19 | "gracePeriodSeconds": 300, 20 | "intervalSeconds": 60, 21 | "portIndex": 0, 22 | "timeoutSeconds": 15, 23 | "maxConsecutiveFailures": 3 24 | }], 25 | "env": { 26 | "SERVICE_NAME": "springboot" 27 | }, 28 | "cpus": 1, 29 | "mem": 256.0, 30 | "instances": 1 31 | } 32 | -------------------------------------------------------------------------------- /examples/structr/README.md: -------------------------------------------------------------------------------- 1 | ## Structr application example 2 | 3 | This example shows how to deploy Structr using Apollo and Marathon Mesos framework. 4 | 5 | The example includes - 6 | 7 | * Structr is the most advanced open Graph Application Platform based on Neo4j 8 | 9 | We'll use the [structr](https://hub.docker.com/r/structr/structr/) [Docker](https://www.docker.com/) image. 10 | 11 | The examples are to be deployed on top of the Marathon Mesos framework. 12 | 13 | ### Start the Structr application 14 | 15 | Start the services by running the following command (from somewhere you can access the REST interface of Marathon). Replace $MARATHON_IP with the actual hostname/ip address of the marathon instance. 16 | Marathon by default should be deployed in the ```mesos_master``` nodes. 17 | 18 | ``` 19 | curl -X POST -HContent-Type:application/json -d @structr.json http://$MARATHON_IP:8080/v2/apps 20 | ``` 21 | 22 | The service will be accessible through the HAProxy container (on port 80) at ```structr.example.com``` by default. It is recommended that you set up your own DNS servers / hostname and override the ```haproxy_domain``` in [../roles/haproxy/defaults/main.yml](../roles/haproxy/defaults/main.yml). 23 | 24 | ### For cloud instances 25 | 26 | To access the Mattermost application, go to the Marathon dashboard at ```http://$MARATHON_IP:8080/#apps``` and click on ```/structr```. You should see an IP address and Port in the service definition, if you click on it you should be redirected to the mattermost application. 27 | 28 | ### For Vagrant only 29 | 30 | If you are deploying this example in the Vagrant environment, simply add the following entry to your host machine in ```/etc/hosts``` 31 | 32 | ``` 33 | 172.31.1.14 structr.example.com 34 | ``` 35 | 36 | Where ```172.31.1.14``` is the Agent IP address configured in ```vagrant.yml``` 37 | If you access ```structr.example.com``` through your browser that will hit the Haproxy container 38 | running on the agent machine which will forward the traffic to the mattermost container. 39 | 40 | ### Removing the apps 41 | 42 | You can remove the applications straight from the command line by running - 43 | 44 | ``` 45 | curl -XDELETE http://$MARATHON_IP:8080/v2/apps/structr 46 | ``` 47 | -------------------------------------------------------------------------------- /examples/structr/structr.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "structr", 3 | "instances": 1, 4 | "cpus": 0.2, 5 | "mem": 1024, 6 | "labels": { 7 | "DCOS_PACKAGE_NAME": "structr", 8 | "DCOS_PACKAGE_IS_FRAMEWORK": "false" 9 | }, 10 | "healthChecks": [ 11 | { 12 | "gracePeriodSeconds": 120, 13 | "intervalSeconds": 15, 14 | "maxConsecutiveFailures": 10, 15 | "path": "/", 16 | "portIndex": 0, 17 | "protocol": "HTTP", 18 | "timeoutSeconds": 5 19 | } 20 | ], 21 | "container": { 22 | "type": "DOCKER", 23 | "volumes": [ 24 | { 25 | "containerPath": "/var/run/docker.sock", 26 | "hostPath": "/var/run/docker.sock", 27 | "mode": "RO" 28 | } 29 | ], 30 | "docker": { 31 | "image": "structr/structr:1.1-SNAPSHOT", 32 | "network": "BRIDGE", 33 | "portMappings": [ 34 | { 35 | "containerPort": 7474, 36 | "hostPort": 0, 37 | "servicePort": 7474, 38 | "protocol": "tcp" 39 | }, 40 | { 41 | "containerPort": 8082, 42 | "hostPort": 0, 43 | "servicePort": 8082, 44 | "protocol": "tcp" 45 | }, 46 | { 47 | "containerPort": 8021, 48 | "hostPort": 0, 49 | "servicePort": 8021, 50 | "protocol": "tcp" 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/wordpress-mysql/wordpress.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "wordpress", 3 | "apps": [ 4 | { 5 | "id": "mysql", 6 | "container": { 7 | "type": "DOCKER", 8 | "docker": { 9 | "image": "mysql:5.5", 10 | "network": "BRIDGE" 11 | } 12 | }, 13 | "env": { 14 | "SERVICE_NAME": "mysql", 15 | "SERVICE_TAGS": "wordpress", 16 | "MYSQL_DATABASE": "wordpress", 17 | "MYSQL_USER": "wordpress", 18 | "MYSQL_PASSWORD": "wordpress", 19 | "MYSQL_ROOT_PASSWORD": "password" 20 | }, 21 | "cpus": 1, 22 | "mem": 512.0, 23 | "instances": 1 24 | }, 25 | { 26 | "id": "wordpress", 27 | "container": { 28 | "type": "DOCKER", 29 | "docker": { 30 | "image": "wordpress", 31 | "network": "BRIDGE", 32 | "portMappings": [{ 33 | "containerPort": 80, 34 | "hostPort": 0, 35 | "protocol": "tcp" 36 | }] 37 | } 38 | }, 39 | "env": { 40 | "SERVICE_NAME": "wordpress", 41 | "WORDPRESS_DB_HOST": "wordpress.mysql.service.consul:3306", 42 | "WORDPRESS_DB_USER": "wordpress", 43 | "WORDPRESS_DB_PASSWORD": "wordpress", 44 | "WORDPRESS_DB_NAME": "wordpress" 45 | }, 46 | "cpus": 1, 47 | "mem": 256.0, 48 | "instances": 1, 49 | "healthChecks": [{ 50 | "path": "/", 51 | "portIndex": 0, 52 | "protocol": "HTTP", 53 | "gracePeriodSeconds": 120, 54 | "intervalSeconds": 10, 55 | "timeoutSeconds": 20, 56 | "maxConsecutiveFailures": 3 57 | }], 58 | "dependencies": ["/wordpress/mysql"] 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /group_vars/all: -------------------------------------------------------------------------------- 1 | mesos_cluster_name: "Cluster01" 2 | zookeeper_client_port: "2181" 3 | zookeeper_server_group: zookeeper_servers 4 | zookeeper_peers_nodes: " 5 | {%- if zookeeper_peers is defined -%} 6 | {{ zookeeper_peers }} 7 | {%- else -%} 8 | {%- set zookeeper_peers = [] -%} 9 | {%- for host in groups[zookeeper_server_group] -%} 10 | {%- if host not in zookeeper_peers -%} 11 | {%- set current_host = hostvars[host]['ansible_host'] + ':' + zookeeper_client_port -%} 12 | {%- do zookeeper_peers.append(current_host) -%} 13 | {%- endif -%} 14 | {%- endfor -%} 15 | {{ zookeeper_peers|join(',') }} 16 | {%- endif -%} 17 | " 18 | consul_domain: consul 19 | http_proxy: '' 20 | proxy_env: 21 | http_proxy: "{{ http_proxy }}" 22 | https_proxy: "{{ http_proxy }}" 23 | HTTP_PROXY: "{{ http_proxy }}" 24 | HTTPS_PROXY: "{{ http_proxy }}" 25 | 26 | prometheus_enabled: true 27 | chronos_enabled: false 28 | spark_enabled: false 29 | cadvisor_enabled: true 30 | marathon_enabled: true 31 | datadog_enabled: false 32 | scope_enabled: false 33 | elk_enabled: false 34 | docker_host: 'unix:///var/run/weave/weave.sock' 35 | 36 | datadog_api_key: "{{ DD_API_KEY }}" 37 | datadog_config: 38 | tags: "{{ mesos_cluster_name }}" 39 | log_level: INFO 40 | 41 | coreos_timezone: 'Europe/London' 42 | traefik_network_interface: "eth0" 43 | -------------------------------------------------------------------------------- /group_vars/mesos_agents: -------------------------------------------------------------------------------- 1 | datadog_checks: 2 | docker: 3 | init_config: 4 | socket_timeout: 100 5 | instances: 6 | - url: "unix://var/run/docker.sock" 7 | new_tag_names: true 8 | collect_events: true 9 | collect_container_size: true 10 | collect_images_stats: false 11 | consul: 12 | init_config: 13 | instances: 14 | - url: http://localhost:8500 15 | catalog_checks: yes 16 | new_leader_checks: yes 17 | mesos_agent: 18 | init_config: 19 | default_timeout: 10 20 | instances: 21 | - url: "http://{{ ansible_default_ipv4.address }}:5051" 22 | -------------------------------------------------------------------------------- /group_vars/mesos_masters: -------------------------------------------------------------------------------- 1 | datadog_checks: 2 | docker: 3 | init_config: 4 | socket_timeout: 100 5 | instances: 6 | - url: "unix://var/run/docker.sock" 7 | new_tag_names: true 8 | collect_events: true 9 | collect_container_size: true 10 | collect_images_stats: false 11 | consul: 12 | init_config: 13 | instances: 14 | - url: http://localhost:8500 15 | catalog_checks: yes 16 | new_leader_checks: yes 17 | mesos_master: 18 | init_config: 19 | default_timeout: 10 20 | instances: 21 | - url: "http://{{ ansible_default_ipv4.address }}:5050" 22 | marathon: 23 | init_config: 24 | default_timeout: 10 25 | instances: 26 | - url: "http://{{ ansible_default_ipv4.address }}:8080" 27 | zk: 28 | init_config: 29 | instances: 30 | - host: localhost 31 | port: 2181 32 | timeout: 10 33 | -------------------------------------------------------------------------------- /group_vars/vagrant: -------------------------------------------------------------------------------- 1 | mesos_cluster_name: "Vagrant" 2 | consul_dc: vagrant 3 | mesos_ip: "{{ ansible_eth1.ipv4.address }}" 4 | consul_advertise: "{{ ansible_eth1.ipv4.address }}" 5 | consul_bind_addr: "{{ ansible_eth1.ipv4.address }}" 6 | marathon_hostname: "{{ ansible_eth1.ipv4.address }}" 7 | mesos_hostname: "{{ ansible_eth1.ipv4.address }}" 8 | dcos_cli_marathon_url: "http://{{ ansible_eth1.ipv4.address }}:8080" 9 | dcos_cli_mesos_master_url: "http://{{ ansible_eth1.ipv4.address }}:5050" 10 | prometheus_consul_host: "{{ ansible_eth1.ipv4.address }}" 11 | prometheus_node_exporter_hostname: "{{ ansible_eth1.ipv4.address }}" 12 | 13 | registrator_uri: "consul://{{ ansible_eth1.ipv4.address }}:8500" 14 | vault_advertise_addr: "{{ ansible_eth1.ipv4.address }}" 15 | weave_launch_peers: " 16 | {%- set weave_peers = [] -%} 17 | {%- for host in groups[weave_server_group] -%} 18 | {%- if host != inventory_hostname and host not in weave_peers -%} 19 | {% do weave_peers.append(hostvars[host]['ansible_eth1']['ipv4']['address']) %} 20 | {%- endif -%} 21 | {%- endfor -%} 22 | {{ weave_peers|join(' ') }} 23 | " 24 | traefik_network_interface: "eth1" 25 | -------------------------------------------------------------------------------- /inventory/inventory: -------------------------------------------------------------------------------- 1 | [role=mesos_masters] 2 | 3 | [role=mesos_agents] 4 | 5 | [mesos_masters:children] 6 | role=mesos_masters 7 | 8 | [mesos_agents:children] 9 | role=mesos_agents 10 | 11 | [load_balancers:children] 12 | mesos_agents 13 | 14 | [all:children] 15 | mesos_masters 16 | mesos_agents 17 | load_balancers 18 | 19 | [all:vars] 20 | ansible_python_interpreter="PATH=/home/core/bin:$PATH python" 21 | 22 | [zookeeper_servers:children] 23 | mesos_masters 24 | 25 | [consul_servers:children] 26 | mesos_masters 27 | 28 | [weave_servers:children] 29 | mesos_masters 30 | mesos_agents 31 | load_balancers 32 | 33 | [marathon_servers:children] 34 | mesos_masters 35 | 36 | [log_servers:children] 37 | mesos_masters 38 | mesos_agents 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo", 3 | "private": true, 4 | "version": "0.0.1", 5 | "description": "An open-source PaaS for cloud native applications", 6 | "scripts": { 7 | "docs:prepare": "gitbook install", 8 | "docs:build": "npm run docs:prepare && gitbook build -g capgemini/apollo", 9 | "docs:watch": "npm run docs:prepare && gitbook serve", 10 | "docs:publish": "npm run docs:clean && npm run docs:build && cp CNAME _book && cd _book && git init && git commit --allow-empty -m 'update book' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update book' && git push git@github.com:capgemini/apollo gh-pages --force" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/capgemini/apollo.git" 15 | }, 16 | "keywords": [ 17 | "capgemini", 18 | "apollo", 19 | "mesos", 20 | "docker", 21 | "paas", 22 | "containers" 23 | ], 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/capgemini/apollo/issues" 27 | }, 28 | "homepage": "https://github.com/capgemini/apollo/issues", 29 | "dependencies": {}, 30 | "devDependencies": { 31 | "gitbook-cli": "^0.3.4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /playbooks/coreos-bootstrap.yml: -------------------------------------------------------------------------------- 1 | - name: bootstrap coreos hosts 2 | hosts: all:!role=bastion 3 | gather_facts: False 4 | environment: "{{ proxy_env }}" 5 | roles: 6 | - coreos_bootstrap 7 | - coreos_timezone 8 | 9 | - name: Install docker-py 10 | hosts: all:!role=bastion 11 | gather_facts: False 12 | environment: "{{ proxy_env }}" 13 | tasks: 14 | - pip: 15 | name: docker-py 16 | version: 1.5.0 17 | -------------------------------------------------------------------------------- /requirements-test.txt: -------------------------------------------------------------------------------- 1 | ansible-lint==2.6.2 2 | -r requirements.txt 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ansible==2.0.2.0 2 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | - src: mkaag.coreos-timezone 2 | name: coreos_timezone 3 | version: v0.1.2 4 | 5 | - src: defunctzombie.coreos-bootstrap 6 | name: coreos_bootstrap 7 | -------------------------------------------------------------------------------- /roles/cadvisor/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for cadvisor 3 | cadvisor_enabled: true 4 | cadvisor_version: 'latest' 5 | cadvisor_restart_policy: 'always' 6 | cadvisor_net: 'bridge' 7 | cadvisor_hostname: "{{ ansible_host }}" 8 | cadvisor_image: "google/cadvisor:{{ cadvisor_version }}" 9 | cadvisor_consul_dir: /etc/consul.d 10 | cadvisor_consul_service_id: "{{ ansible_hostname }}:cadvisor:8080" 11 | cadvisor_docker_socket: "{{ docker_host }}" 12 | -------------------------------------------------------------------------------- /roles/cadvisor/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: restart cadvisor 2 | become: yes 3 | service: 4 | name: cadvisor 5 | state: restarted 6 | -------------------------------------------------------------------------------- /roles/cadvisor/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # tasks for running cadvisor 2 | - name: deploy cadvisor service 3 | become: yes 4 | become_user: root 5 | template: 6 | src: cadvisor.service.j2 7 | dest: /etc/systemd/system/cadvisor.service 8 | notify: 9 | - reload systemd 10 | - restart cadvisor 11 | tags: 12 | - cadvisor 13 | 14 | # Attach to the running container, or start it if needed 15 | # and forward all signals so that the process manager can detect 16 | # when a container stops and correctly restart it. 17 | - name: ensure cadvisor is running (and enable it at boot) 18 | become: yes 19 | service: 20 | name: cadvisor 21 | state: started 22 | enabled: yes 23 | tags: 24 | - cadvisor 25 | 26 | - name: get cadvisor container ip 27 | become: yes 28 | command: > 29 | docker inspect -f \{\{' '.NetworkSettings.IPAddress' '\}\} cadvisor 30 | register: cadvisor_container_ip 31 | tags: 32 | - cadvisor 33 | 34 | - name: Set cadvisor consul service definition 35 | become: yes 36 | template: 37 | src: cadvisor-consul.j2 38 | dest: "{{ cadvisor_consul_dir }}/cadvisor.json" 39 | notify: 40 | - restart consul 41 | tags: 42 | - cadvisor 43 | -------------------------------------------------------------------------------- /roles/cadvisor/templates/cadvisor-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "cadvisor", 4 | "tags": [ "cadvisor" ], 5 | "check": { 6 | "docker_container_id": "cadvisor", 7 | "shell": "/bin/sh", 8 | "script": "wget -q -s {{ cadvisor_container_ip.stdout }}:8080/containers/ -O /dev/null", 9 | "interval": "10s", 10 | "timeout": "3s" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /roles/cadvisor/templates/cadvisor.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=cadvisor 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | RestartSec=20 9 | TimeoutStartSec=0 10 | EnvironmentFile=-/etc/environment 11 | Environment="DOCKER_HOST={{ cadvisor_docker_socket }}" 12 | ExecStartPre=-/usr/bin/docker kill cadvisor 13 | ExecStartPre=-/usr/bin/docker rm cadvisor 14 | ExecStartPre=/usr/bin/docker pull {{ cadvisor_image }} 15 | ExecStart=/usr/bin/docker run --name cadvisor \ 16 | --restart={{ cadvisor_restart_policy }} \ 17 | --net={{ cadvisor_net }} \ 18 | --hostname={{ cadvisor_hostname }} \ 19 | -v /var/lib/docker/:/var/lib/docker:ro \ 20 | -v /:/rootfs:ro \ 21 | -v /var/run:/var/run:rw \ 22 | -v /sys:/sys:ro \ 23 | {{ cadvisor_image }} 24 | 25 | ExecStop=/usr/bin/docker stop cadvisor 26 | 27 | [Install] 28 | WantedBy=multi-user.target 29 | -------------------------------------------------------------------------------- /roles/cadvisor/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for cadvisor 3 | -------------------------------------------------------------------------------- /roles/consul/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for consul 3 | consul_dc: dc1 4 | consul_servers_group: consul_servers 5 | consul_bootstrap_expect: "{{ groups[consul_servers_group] | length }}" 6 | consul_advertise: "{{ ansible_host }}" 7 | consul_config_dir: /etc/consul.d 8 | consul_data_dir: /var/lib/consul 9 | consul_atlas_join: false 10 | consul_bind_addr: "{{ ansible_default_ipv4.address }}" 11 | consul_retry_join: "{% for host in groups[consul_servers_group] %}\"{{ hostvars[host].ansible_default_ipv4.address }}\"{% if not loop.last %}, {% endif %}{% endfor %}" 12 | consul_client_addr: "0.0.0.0" 13 | consul_node_name: "{{ ansible_hostname }}" 14 | consul_version: 0.6 15 | consul_docker_socket: "{{ docker_host }}" 16 | consul_image: " 17 | {%- if inventory_hostname in groups[consul_servers_group] -%} 18 | gliderlabs/consul-server:{{ consul_version }} 19 | {%- else -%} 20 | gliderlabs/consul-agent:{{ consul_version }} 21 | {%- endif -%} 22 | " 23 | -------------------------------------------------------------------------------- /roles/consul/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for consul 3 | - name: wait for consul to listen 4 | wait_for: 5 | host: "{{ consul_bind_addr }}" 6 | port: 8500 7 | 8 | - name: restart consul 9 | become: yes 10 | service: 11 | name: consul 12 | state: restarted 13 | notify: 14 | - wait for consul to listen 15 | -------------------------------------------------------------------------------- /roles/consul/tasks/config.yml: -------------------------------------------------------------------------------- 1 | - name: create consul dirs 2 | become: yes 3 | file: 4 | path: "{{ item }}" 5 | state: directory 6 | mode: 0755 7 | with_items: 8 | - "{{ consul_data_dir }}" 9 | - "{{ consul_config_dir }}" 10 | 11 | - name: configure consul 12 | become: yes 13 | template: 14 | src: consul.json.j2 15 | dest: /etc/consul.d/consul.json 16 | owner: root 17 | group: root 18 | mode: 0644 19 | notify: 20 | - restart consul 21 | tags: 22 | - consul 23 | 24 | - name: deploy consul service 25 | become: yes 26 | become_user: root 27 | template: 28 | src: "{{ item.src }}" 29 | dest: "{{ item.dest }}" 30 | with_items: 31 | - src: consul.service.j2 32 | dest: /etc/systemd/system/consul.service 33 | - src: consul-discovery.service.j2 34 | dest: /etc/systemd/system/consul-discovery.service 35 | notify: 36 | - reload systemd 37 | - restart consul 38 | tags: 39 | - consul 40 | -------------------------------------------------------------------------------- /roles/consul/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: config.yml 3 | 4 | - name: enable consul 5 | become: yes 6 | service: 7 | name: consul 8 | enabled: yes 9 | state: started 10 | notify: 11 | - restart consul 12 | tags: 13 | - consul 14 | 15 | - name: wait for consul to listen 16 | wait_for: 17 | host: "{{ consul_bind_addr }}" 18 | port: 8500 19 | -------------------------------------------------------------------------------- /roles/consul/templates/consul-discovery.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Consul Discovery 3 | BindsTo=consul.service 4 | After=consul.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | EnvironmentFile=/etc/environment 9 | ExecStart=/bin/sh -c "while true; do etcdctl mk /services/consul $COREOS_PUBLIC_IPV4 --ttl 60;/usr/bin/docker exec consul consul join $(etcdctl get /services/consul);sleep 45;done" 10 | ExecStop=/usr/bin/etcdctl rm /services/consul --with-value %H 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /roles/consul/templates/consul.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "datacenter": "{{ consul_dc }}", 3 | "advertise_addr": "{{ consul_advertise }}", 4 | "node_name": "{{ consul_node_name }}", 5 | "domain": "{{ consul_domain }}", 6 | "rejoin_after_leave": true, 7 | "client_addr": "{{ consul_client_addr }}", 8 | "ports": {"dns": 53}, 9 | {% if consul_bootstrap_expect > 1 %} 10 | "retry_join": [ {{ consul_retry_join }} ], 11 | {% endif %} 12 | {% if inventory_hostname in groups[consul_servers_group] %} 13 | "server": true, 14 | "bootstrap_expect": {{ consul_bootstrap_expect }}, 15 | "dns_config": { 16 | "allow_stale": false 17 | }, 18 | "ui": true, 19 | {% else %} 20 | "leave_on_terminate": true, 21 | "dns_config": { 22 | "allow_stale": true, 23 | "max_stale": "1s" 24 | }, 25 | {% endif %} 26 | {% if consul_atlas_join|bool %} 27 | "atlas_join": true, 28 | "atlas_token": "{{ consul_atlas_token }}", 29 | "atlas_infrastructure": "{{ consul_atlas_infrastructure }}", 30 | {% endif %} 31 | "data_dir": "{{ consul_data_dir }}" 32 | } 33 | -------------------------------------------------------------------------------- /roles/consul/templates/consul.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Consul 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | TimeoutStartSec=0 9 | EnvironmentFile=/etc/environment 10 | Environment=DOCKER_HOST={{ consul_docker_socket }} 11 | # make sure /etc/systemd/resolved.conf.d dir exists so we can add Consul's DNS resolver to system 12 | ExecStartPre=/usr/bin/mkdir -p /etc/systemd/resolved.conf.d 13 | ExecStartPre=-/usr/bin/docker kill consul 14 | ExecStartPre=-/usr/bin/docker rm consul 15 | ExecStartPre=-/bin/bash -c 'rm /etc/systemd/resolved.conf.d/00-consul-dns.conf && systemctl restart systemd-resolved' 16 | ExecStartPre=/usr/bin/docker pull {{ consul_image }} 17 | 18 | ExecStart=/usr/bin/bash -c "/usr/bin/docker run --rm --name consul \ 19 | -h $(/usr/bin/cat /etc/hostname) \ 20 | -v {{ consul_data_dir }}:/data \ 21 | -v {{ consul_config_dir }}:/config \ 22 | -v /var/run/docker.sock:/var/run/docker.sock \ 23 | -p 8300:8300 \ 24 | -p 8301:8301 \ 25 | -p 8301:8301/udp \ 26 | -p 8302:8302 \ 27 | -p 8302:8302/udp \ 28 | -p 8400:8400 \ 29 | -p 8500:8500 \ 30 | -p {{ ansible_default_ipv4.address }}:53:53/udp \ 31 | {{ consul_image }}" 32 | 33 | {% raw %} 34 | ExecStartPost=/bin/sh -c "sleep 1; echo -e \"[Resolve]\nDNS=$(/usr/bin/docker inspect --format '{{ .NetworkSettings.IPAddress }}' consul)\" > /etc/systemd/resolved.conf.d/00-consul-dns.conf && systemctl restart systemd-resolved" 35 | {% endraw %} 36 | 37 | ExecStop=/usr/bin/docker stop consul 38 | ExecStopPost=/bin/sh -c 'rm /etc/systemd/resolved.conf.d/00-consul-dns.conf && systemctl restart systemd-resolved' 39 | 40 | [Install] 41 | WantedBy=multi-user.target 42 | -------------------------------------------------------------------------------- /roles/consul/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for consul 3 | -------------------------------------------------------------------------------- /roles/dcos_cli/README.md: -------------------------------------------------------------------------------- 1 | Frameworks 2 | ========= 3 | 4 | Install mesos frameworks via capgemini:dcos-cli. 5 | 6 | Requirements 7 | ------------ 8 | 9 | The tasks inside the role should be run only once, i.e run_once=true 10 | 11 | Role Variables 12 | -------------- 13 | ``` 14 | dcos_cli_image: capgemini/dcos-cli 15 | dcos_cli_zk_master_peers: "zk://{{ zookeeper_peers_nodes }}/mesos" 16 | dcos_cli_mesos_master_url: "http://{{ ansible_host }}:5050" 17 | dcos_cli_marathon_url: "http://{{ ansible_host }}:8080" 18 | 19 | frameworks_FRAMEWORK-NAME_enabled: false 20 | ``` 21 | 22 | License 23 | ------- 24 | 25 | MIT 26 | 27 | -------------------------------------------------------------------------------- /roles/dcos_cli/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for dcos-cli 3 | dcos_cli_image: capgemini/dcos-cli 4 | dcos_cli_zk_master_peers: "zk://{{ zookeeper_peers_nodes }}/mesos" 5 | dcos_cli_mesos_master_url: "http://{{ ansible_host }}:5050" 6 | dcos_cli_marathon_url: "http://{{ ansible_host }}:8080" 7 | dcos_cli_no_proxy: "{{ ansible_host }}:8080,{{ ansible_host }}:5050" 8 | dcos_cli_sources: '["https://github.com/mesosphere/universe/archive/version-1.x.zip", "https://github.com/mesosphere/multiverse/archive/version-1.x.zip"]' 9 | dcos_cli_container_environment: 10 | http_proxy: "{{ proxy_env.http_proxy }}" 11 | https_proxy: "{{ proxy_env.https_proxy }}" 12 | HTTP_PROXY: "{{ proxy_env.HTTP_PROXY }}" 13 | HTTPS_PROXY: "{{ proxy_env.HTTPS_PROXY }}" 14 | no_proxy: "{{ dcos_cli_no_proxy }}" 15 | NO_PROXY: "{{ dcos_cli_no_proxy }}" 16 | MESOS_MASTER_URL: "{{ dcos_cli_mesos_master_url }}" 17 | MARATHON_URL: "{{ dcos_cli_marathon_url }}" 18 | SOURCES: "{{ dcos_cli_sources }}" 19 | 20 | dcos_cli_frameworks_list: 21 | - cassandra 22 | - chronos 23 | - exhibitor 24 | - spark 25 | 26 | # Type flag allows you to set up a command which you want to use to run an app. 27 | # To run one app use "type: app" and to run group of apps use "type: group". 28 | dcos_cli_apps_list: 29 | - { name: elasticsearch, type: app } 30 | - { name: prometheus, type: app } 31 | - { name: promdash, type: group } 32 | -------------------------------------------------------------------------------- /roles/dcos_cli/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for dcos-cli 3 | -------------------------------------------------------------------------------- /roles/dcos_cli/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Alberto Lamela 4 | description: 5 | company: Capgemini 6 | license: MIT 7 | min_ansible_version: 2.0 8 | platforms: 9 | - name: CoreOS 10 | versions: 11 | - all 12 | categories: 13 | - cloud 14 | - cloud:ec2 15 | - cloud:gce 16 | - cloud:rax 17 | dependencies: [] 18 | 19 | 20 | -------------------------------------------------------------------------------- /roles/dcos_cli/tasks/apps.yml: -------------------------------------------------------------------------------- 1 | - include_vars: "{{ item.name }}.yml" 2 | with_items: 3 | - "{{ dcos_cli_apps_list }}" 4 | 5 | # Create the JSON files for apps 6 | - name: create json files for apps 7 | when: "dcos_cli_app_{{ item.name }}_enabled | bool" 8 | run_once: true 9 | template: 10 | src: '{{ item.name }}.json.j2' 11 | dest: "/etc/marathon/{{ item.name }}.json" 12 | mode: 0755 13 | become: yes 14 | with_items: 15 | - "{{ dcos_cli_apps_list }}" 16 | 17 | - name: add marathon app via dcos-cli 18 | when: "dcos_cli_app_{{ item.name }}_enabled | bool" 19 | run_once: true 20 | docker: 21 | name: "{{ item.name }}" 22 | image: "{{ dcos_cli_image }}" 23 | state: started 24 | command: "marathon {{ item.type }} add /config/{{ item.name }}.json" 25 | volumes: 26 | - "/etc/marathon:/config" 27 | env: 28 | "{{ dcos_cli_container_environment }}" 29 | with_items: 30 | - "{{ dcos_cli_apps_list }}" 31 | 32 | 33 | - name: remove marathon app via dcos-cli 34 | when: "not dcos_cli_app_{{ item.name }}_enabled | bool" 35 | run_once: true 36 | docker: 37 | name: "{{ item.name }}" 38 | image: "{{ dcos_cli_image }}" 39 | state: started 40 | command: "marathon {{ item.type }} remove {{ item.name }}" 41 | env: 42 | "{{ dcos_cli_container_environment }}" 43 | with_items: 44 | - "{{ dcos_cli_apps_list }}" 45 | -------------------------------------------------------------------------------- /roles/dcos_cli/tasks/frameworks.yml: -------------------------------------------------------------------------------- 1 | - include_vars: "{{ item }}.yml" 2 | with_items: 3 | - "{{ dcos_cli_frameworks_list }}" 4 | 5 | - name: create config directory 6 | when: "dcos_cli_framework_{{ item }}_enabled | bool" 7 | run_once: true 8 | template: 9 | src: "{{ item }}-config.j2" 10 | dest: "/tmp/{{ item }}-config" 11 | mode: 0755 12 | become: true 13 | with_items: 14 | - "{{ dcos_cli_frameworks_list }}" 15 | 16 | - name: install dcos-cli package 17 | when: "dcos_cli_framework_{{ item }}_enabled | bool" 18 | run_once: true 19 | docker: 20 | name: "{{ item }}" 21 | image: "{{ dcos_cli_image }}" 22 | state: started 23 | command: "package install --options=/config --yes {{ item }}" 24 | volumes: 25 | - "/tmp/{{ item }}-config:/config" 26 | env: 27 | "{{ dcos_cli_container_environment }}" 28 | with_items: 29 | - "{{ dcos_cli_frameworks_list }}" 30 | 31 | - name: uninstall dcos-cli package 32 | when: "not dcos_cli_framework_{{ item }}_enabled | bool" 33 | run_once: true 34 | docker: 35 | name: "{{ item }}" 36 | image: "{{ dcos_cli_image }}" 37 | state: started 38 | command: "package uninstall {{ item }}" 39 | env: 40 | "{{ dcos_cli_container_environment }}" 41 | with_items: 42 | - "{{ dcos_cli_frameworks_list }}" 43 | -------------------------------------------------------------------------------- /roles/dcos_cli/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: frameworks.yml 2 | - include: apps.yml 3 | 4 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/cassandra-config.j2: -------------------------------------------------------------------------------- 1 | { 2 | "mesos": { 3 | "master": "{{ dcos_cli_zk_master_peers }}" 4 | }, 5 | "cassandra": { 6 | "zk": "zk://{{ zookeeper_peers_nodes }}/cassandra-mesos", 7 | "node-count": {{ dcos_cli_framework_cassandra_node_count }} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/chronos-config.j2: -------------------------------------------------------------------------------- 1 | { 2 | "mesos": { 3 | "master": "{{ dcos_cli_zk_master_peers }}" 4 | }, 5 | "chronos": { 6 | "zk-hosts": "{{ zookeeper_peers_nodes }}", 7 | "mem": {{ dcos_cli_framework_chronos_mem }}, 8 | "cpus": {{ dcos_cli_framework_chronos_cpus }} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/elasticsearch.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "id": "elasticsearch", 3 | "instances": {{ dcos_cli_app_elasticsearch_instances }}, 4 | "cpus": {{ dcos_cli_app_elasticsearch_cpus }}, 5 | "mem": {{ dcos_cli_app_elasticsearch_mem }}, 6 | "labels": { 7 | "DCOS_PACKAGE_NAME": "elasticsearch", 8 | "DCOS_PACKAGE_IS_FRAMEWORK": "true" 9 | }, 10 | "env": { 11 | "SERVICE_NAME": "elasticsearch", 12 | "SERVICE_9200_NAME": "elasticsearch" 13 | }, 14 | "healthChecks": [ 15 | { 16 | "gracePeriodSeconds": 120, 17 | "intervalSeconds": 15, 18 | "maxConsecutiveFailures": 10, 19 | "path": "/", 20 | "portIndex": 0, 21 | "protocol": "HTTP", 22 | "timeoutSeconds": 5 23 | } 24 | ], 25 | "container": { 26 | "type": "DOCKER", 27 | "docker": { 28 | "image": "{{ dcos_cli_app_elasticsearch_image }}:{{ dcos_cli_app_elasticsearch_image_tag }}", 29 | "network": "BRIDGE", 30 | "portMappings": [ 31 | { 32 | "containerPort": 9200, 33 | "servicePort": 9200, 34 | "hostPort": 0, 35 | "protocol": "tcp" 36 | }, 37 | { 38 | "containerPort": 9300, 39 | "servicePort": 9300, 40 | "hostPort": 0, 41 | "protocol": "tcp" 42 | } 43 | ] 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/exhibitor-config.yml: -------------------------------------------------------------------------------- 1 | { 2 | "exhibitor": { 3 | "zk_servers": "{{ zookeeper_peers_nodes }}", 4 | "app-id": "exhibitor", 5 | "cpus": {{ dcos_cli_framework_exhibitor_cpus }}, 6 | "mem": {{ dcos_cli_framework_exhibitor_mem }}, 7 | "docker-image": "{{ dcos_cli_framework_exhibitor_image }}" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/kibana.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "id": "kibana", 3 | "container": { 4 | "type": "DOCKER", 5 | "docker": { 6 | "image": "{{ dcos_cli_app_kibana_image }}:{{ dcos_cli_app_kibana_image_tag }}", 7 | "network": "BRIDGE", 8 | "parameters": [ 9 | { "key": "log-driver", "value": "json-file" }, 10 | { "key": "log-opt", "value": "max-size=64m" }, 11 | { "key": "log-opt", "value": "max-file=8" } 12 | ], 13 | "portMappings": [{ 14 | "containerPort": 5601, 15 | "servicePort": 5601, 16 | "hostPort": 0, 17 | "protocol": "tcp" 18 | }] 19 | } 20 | }, 21 | "instances": {{ dcos_cli_app_kibana_instances }}, 22 | "cpus": {{ dcos_cli_app_kibana_cpus }}, 23 | "mem": {{ dcos_cli_app_kibana_mem }}, 24 | "labels": { 25 | "DCOS_PACKAGE_NAME": "kibana", 26 | "DCOS_PACKAGE_IS_FRAMEWORK": "true" 27 | }, 28 | "healthChecks": [ 29 | { 30 | "protocol": "HTTP", 31 | "path": "/", 32 | "portIndex": 0, 33 | "initialDelaySeconds": 600, 34 | "gracePeriodSeconds": 10, 35 | "intervalSeconds": 30, 36 | "timeoutSeconds": 120, 37 | "maxConsecutiveFailures": 10 38 | } 39 | ], 40 | "env": { 41 | "ELASTICSEARCH_URL": "http://elasticsearch.service.{{ consul_domain }}:9200" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/logstash.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "id": "logstash", 3 | "cmd": "/bin/bash -c \"logstash -f {{ dcos_cli_app_logstash_config_dir }}/logstash.conf\"", 4 | "instances": {{ dcos_cli_app_logstash_instances }}, 5 | "cpus": {{ dcos_cli_app_logstash_cpus }}, 6 | "mem": {{ dcos_cli_app_logstash_mem }}, 7 | "labels": { 8 | "DCOS_PACKAGE_NAME": "logstash", 9 | "DCOS_PACKAGE_IS_FRAMEWORK": "true" 10 | }, 11 | "env": { 12 | "SERVICE_NAME": "logstash", 13 | "SERVICE_5043_NAME": "logstash", 14 | "SERVICE_19532_NAME": "journald-upload" 15 | }, 16 | "healthChecks": [ 17 | { 18 | "protocol": "TCP", 19 | "portIndex": 0, 20 | "gracePeriodSeconds": 5, 21 | "intervalSeconds": 20, 22 | "maxConsecutiveFailures": 3 23 | }, 24 | { 25 | "protocol": "TCP", 26 | "portIndex": 1, 27 | "gracePeriodSeconds": 5, 28 | "intervalSeconds": 20, 29 | "maxConsecutiveFailures": 3 30 | } 31 | ], 32 | "container": { 33 | "type": "DOCKER", 34 | "volumes": [ 35 | { 36 | "containerPath": "{{ dcos_cli_app_logstash_config_dir }}", 37 | "hostPath": "{{ dcos_cli_app_logstash_config_dir }}", 38 | "mode": "RO" 39 | } 40 | ], 41 | "docker": { 42 | "image": "{{ dcos_cli_app_logstash_image }}:{{ dcos_cli_app_logstash_image_tag }}", 43 | "network": "BRIDGE", 44 | "portMappings": [ 45 | { 46 | "containerPort": 5043, 47 | "servicePort": 5043, 48 | "hostPort": 0, 49 | "protocol": "tcp" 50 | }, 51 | { 52 | "containerPort": 19532, 53 | "servicePort": 19532, 54 | "hostPort": 0, 55 | "protocol": "tcp" 56 | } 57 | ] 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/promdash.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "id": "promdash-group", 3 | "apps": [ 4 | { 5 | "id": "mysql", 6 | "container": { 7 | "type": "DOCKER", 8 | "docker": { 9 | "image": "mysql:latest", 10 | "network": "BRIDGE", 11 | "portMappings": [{"containerPort": 3306, "hostPort": 0, "protocol": "tcp"}] 12 | } 13 | }, 14 | "env": { 15 | "SERVICE_NAME": "mysql", 16 | "SERVICE_TAGS": "promdash", 17 | "MYSQL_DATABASE": "promdash", 18 | "MYSQL_USER": "promdash", 19 | "MYSQL_PASSWORD": "promdash", 20 | "MYSQL_ROOT_PASSWORD": "password" 21 | }, 22 | "cpus": 0.5, 23 | "mem": 1024.0, 24 | "instances": 1, 25 | "healthChecks": [{ 26 | "path": "/", 27 | "portIndex": 0, 28 | "protocol": "TCP", 29 | "gracePeriodSeconds": 30, 30 | "intervalSeconds": 10, 31 | "timeoutSeconds": 20, 32 | "maxConsecutiveFailures": 3 33 | }] 34 | }, 35 | { 36 | "id": "promdash", 37 | "container": { 38 | "type": "DOCKER", 39 | "docker": { 40 | "image": "{{ promdash_image }}", 41 | "network": "BRIDGE", 42 | "portMappings": [{"containerPort": 3000, "hostPort": 0, "protocol": "tcp"}] 43 | } 44 | }, 45 | "env": { 46 | "SERVICE_NAME": "promdash", 47 | "DATABASE_URL": "{{ promdash_database_url }}", 48 | "RAILS_ENV": "production" 49 | }, 50 | "cpus": {{ dcos_cli_app_promdash_cpus }}, 51 | "mem": {{ dcos_cli_app_promdash_mem }}, 52 | "instances": {{ dcos_cli_app_promdash_instances }}, 53 | "healthChecks": [{ 54 | "protocol": "HTTP", 55 | "path": "/", 56 | "portIndex": 0, 57 | "gracePeriodSeconds": 30, 58 | "intervalSeconds": 30, 59 | "timeoutSeconds": 10, 60 | "maxConsecutiveFailures": 2, 61 | "ignoreHttp1xx": false 62 | }], 63 | "dependencies": ["/promdash-group/mysql"], 64 | "upgradeStrategy": { 65 | "minimumHealthCapacity": 0.5, 66 | "maximumOverCapacity": 0.0 67 | } 68 | } 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/prometheus.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "container": { 3 | "type": "DOCKER", 4 | "docker": { 5 | "network": "BRIDGE", 6 | "image": "{{ dcos_cli_app_prometheus_image }}:{{ dcos_cli_app_prometheus_image_tag }}", 7 | "portMappings": [{"containerPort": 9090, "hostPort": 0, "protocol": "tcp"}] 8 | }, 9 | "volumes": [{ 10 | "containerPath": "/etc/prometheus/prometheus.yml", 11 | "hostPath": "{{ prometheus_config_dir }}/prometheus.yml", 12 | "mode": "RO" 13 | }] 14 | }, 15 | "id": "prometheus", 16 | "instances": {{ dcos_cli_app_prometheus_instances }}, 17 | "cpus": {{ dcos_cli_app_prometheus_cpus }}, 18 | "mem": {{ dcos_cli_app_prometheus_mem }}, 19 | "healthChecks": [ 20 | { 21 | "protocol": "HTTP", 22 | "path": "/", 23 | "portIndex": 0, 24 | "gracePeriodSeconds": 30, 25 | "intervalSeconds": 30, 26 | "timeoutSeconds": 10, 27 | "maxConsecutiveFailures": 2, 28 | "ignoreHttp1xx": false 29 | } 30 | ], 31 | "upgradeStrategy": { 32 | "minimumHealthCapacity": 0.5, 33 | "maximumOverCapacity": 0.0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /roles/dcos_cli/templates/spark-config.j2: -------------------------------------------------------------------------------- 1 | { 2 | "mesos": { 3 | "master": "mesos://{{ dcos_cli_zk_master_peers }}" 4 | }, 5 | "spark": { 6 | "cpus": {{ dcos_cli_framework_spark_cpus }}, 7 | "mem": {{ dcos_cli_framework_spark_mem }}, 8 | "zookeeper": "{{ zookeeper_peers_nodes }}" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/cassandra.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_framework_cassandra_enabled: false 2 | dcos_cli_framework_cassandra_node_count: 1 3 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/chronos.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_framework_chronos_enabled: "{{ chronos_enabled }}" 2 | dcos_cli_framework_chronos_mem: 512 3 | dcos_cli_framework_chronos_cpus: 0.5 4 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_app_elasticsearch_enabled: "{{ elk_enabled }}" 2 | dcos_cli_app_elasticsearch_image: elasticsearch 3 | dcos_cli_app_elasticsearch_image_tag: 2.3.1 4 | dcos_cli_app_elasticsearch_mem: 756 5 | dcos_cli_app_elasticsearch_cpus: 1.0 6 | dcos_cli_app_elasticsearch_instances: 1 7 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/exhibitor.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_framework_exhibitor_enabled: false 2 | dcos_cli_framework_exhibitor_mem: 3072.0 3 | dcos_cli_framework_exhibitor_cpus: 1 4 | dcos_cli_framework_exhibitor_image: mesosphere/exhibitor-dcos 5 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/kibana.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_app_kibana_enabled: "{{ elk_enabled }}" 2 | dcos_cli_app_kibana_image: kibana 3 | dcos_cli_app_kibana_image_tag: 4.4.2 4 | dcos_cli_app_kibana_mem: 512 5 | dcos_cli_app_kibana_cpus: 0.5 6 | dcos_cli_app_kibana_instances: 1 7 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/logstash.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_app_logstash_enabled: "{{ elk_enabled }}" 2 | dcos_cli_app_logstash_image: logstash 3 | dcos_cli_app_logstash_image_tag: 2.3.1-1 4 | dcos_cli_app_logstash_mem: 756 5 | dcos_cli_app_logstash_cpus: 0.8 6 | dcos_cli_app_logstash_instances: 1 7 | dcos_cli_app_logstash_config_dir: '/opt/logstash/conf.d' 8 | dcos_cli_app_logstash_elasticsearch: elasticsearch.service.{{ consul_domain }}:9200 9 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/promdash.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_app_promdash_enabled: "{{ prometheus_enabled }}" 2 | dcos_cli_app_promdash_mem: 128 3 | dcos_cli_app_promdash_cpus: 0.5 4 | dcos_cli_app_promdash_instances: 1 5 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/prometheus.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_app_prometheus_enabled: "{{ prometheus_enabled }}" 2 | dcos_cli_app_prometheus_mem: 128 3 | dcos_cli_app_prometheus_cpus: 0.5 4 | dcos_cli_app_prometheus_instances: 1 5 | dcos_cli_app_prometheus_image: prom/prometheus 6 | dcos_cli_app_prometheus_image_tag: 0.16.1 7 | -------------------------------------------------------------------------------- /roles/dcos_cli/vars/spark.yml: -------------------------------------------------------------------------------- 1 | dcos_cli_framework_spark_enabled: "{{ spark_enabled }}" 2 | dcos_cli_framework_spark_mem: 2048.0 3 | dcos_cli_framework_spark_cpus: 2 4 | -------------------------------------------------------------------------------- /roles/docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for docker 3 | docker_tmp_dir: /var/lib/docker/tmp 4 | docker_dns_config: "--dns={{ ansible_default_ipv4.address }} --dns=8.8.8.8 --dns-search='service.{{ consul_domain }}'" 5 | docker_storage_config: --storage-driver=overlay 6 | docker_endpoints: "-H=tcp://{{ ansible_default_ipv4.address }}:2376 -H=unix:///var/run/docker.sock" 7 | docker_bridge_ip: '' 8 | docker_proxy_exceptions: '' 9 | docker_registry: '' 10 | private_docker_registry: false 11 | -------------------------------------------------------------------------------- /roles/docker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for docker 3 | - name: reload systemd 4 | become: yes 5 | command: systemctl daemon-reload 6 | notify: 7 | - restart docker 8 | 9 | - name: restart docker 10 | become: yes 11 | service: 12 | name: docker 13 | state: restarted 14 | -------------------------------------------------------------------------------- /roles/docker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for docker 3 | - name: ensure docker config dir exists 4 | become: yes 5 | file: 6 | path: /root/.docker 7 | state: directory 8 | tags: 9 | - docker 10 | 11 | - name: setup private docker registry credentials 12 | become: yes 13 | when: private_docker_registry|bool 14 | template: 15 | src: config.json.j2 16 | dest: /root/.docker/config.json 17 | tags: 18 | - docker 19 | 20 | - name: deploy docker service 21 | become: yes 22 | become_user: root 23 | template: 24 | src: docker.service.j2 25 | dest: /etc/systemd/system/docker.service 26 | notify: 27 | - reload systemd 28 | - restart docker 29 | tags: 30 | - docker 31 | 32 | - name: ensure docker is running (and enable it at boot) 33 | become: yes 34 | service: 35 | name: docker 36 | state: started 37 | enabled: yes 38 | tags: 39 | - docker 40 | -------------------------------------------------------------------------------- /roles/docker/templates/config.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "auths": { 3 | "{{ docker_registry_url }}": { 4 | "auth": "{{ docker_registry_auth }}", 5 | "email": "{{ docker_registry_email }}" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /roles/docker/templates/docker.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Docker Application Container Engine 3 | Documentation=http://docs.docker.com 4 | After=docker.socket early-docker.target network.target 5 | Requires=docker.socket early-docker.target 6 | 7 | [Service] 8 | EnvironmentFile=-/run/flannel_docker_opts.env 9 | {% if http_proxy is defined and http_proxy != '' %} 10 | Environment="HTTP_PROXY={{ http_proxy }}" 11 | Environment="NO_PROXY={{ docker_proxy_exceptions }}" 12 | {% endif %} 13 | Environment="DOCKER_TMPDIR={{ docker_tmp_dir }}" 14 | 15 | MountFlags=slave 16 | LimitNOFILE=1048576 17 | LimitNPROC=1048576 18 | ExecStart=/usr/lib/coreos/dockerd daemon {{ docker_endpoints }} {{ docker_bridge_ip }} {{ docker_storage_config }} {{ docker_dns_config }} {{ docker_registry }} --host=fd:// $DOCKER_OPTS $DOCKER_OPT_BIP $DOCKER_OPT_MTU $DOCKER_OPT_IPMASQ 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /roles/docker/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for docker 3 | -------------------------------------------------------------------------------- /roles/dockerbench/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for dockerbench 3 | dockerbench_run_test: false 4 | dockerbench_dest: /opt/dockerbench 5 | dockerbench_repo: https://github.com/docker/docker-bench-security.git 6 | dockerbench_version: master 7 | dockerbench_warn_threshold: 100 8 | -------------------------------------------------------------------------------- /roles/dockerbench/handlers/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /roles/dockerbench/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for docker bench 3 | - name: checkout docker bench git repo 4 | git: 5 | repo: "{{ dockerbench_repo }}" 6 | dest: "{{ dockerbench_dest }}" 7 | accept_hostkey: true 8 | version: "{{ dockerbench_version }}" 9 | 10 | - name: install docker bench threshold script 11 | sudo: yes 12 | template: 13 | src: docker-bench-warn.sh.j2 14 | dest: /usr/local/bin/docker-bench-warn.sh 15 | mode: 0755 16 | 17 | - name: run docker bench script 18 | command: /usr/local/bin/docker-bench-warn.sh 19 | sudo: yes 20 | args: 21 | chdir: "{{ dockerbench_dest }}" 22 | -------------------------------------------------------------------------------- /roles/dockerbench/templates/docker-bench-warn.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dockerwarns=$(/bin/bash {{ dockerbench_dest }}/docker-bench-security.sh | grep WARN | wc -l) 4 | dockeroutput="$(/bin/bash {{ dockerbench_dest }}/docker-bench-security.sh | grep WARN)" 5 | if [[ $dockerwarns -gt {{ dockerbench_warn_threshold }} ]] ; then 6 | echo "There are $dockerwarns docker security warnings. The threshold is {{ dockerbench_warn_threshold }}" 7 | echo "${dockeroutput}" 8 | exit 1 9 | else 10 | echo "There are $dockerwarns docker security warnings." 11 | echo "${dockeroutput}" 12 | exit 0 13 | fi 14 | 15 | # EOF 16 | -------------------------------------------------------------------------------- /roles/dockerbench/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for dockerbench 3 | -------------------------------------------------------------------------------- /roles/handlers/handlers/main.yml: -------------------------------------------------------------------------------- 1 | - name: reload systemd 2 | become: yes 3 | command: systemctl daemon-reload 4 | 5 | - name: restart consul 6 | service: 7 | name: consul 8 | state: restarted 9 | become: yes 10 | 11 | - name: wait for consul to listen 12 | wait_for: 13 | port: 8500 14 | 15 | - name: restart docker 16 | service: 17 | name: docker 18 | state: restarted 19 | become: yes 20 | 21 | - name: wait for weave to listen 22 | wait_for: 23 | port: 6783 24 | delay: 10 25 | -------------------------------------------------------------------------------- /roles/logstash/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # lumberjack configuration 3 | lumberjack_enabled: "{{ elk_enabled }}" 4 | lumberjack_restart_policy: 'always' 5 | lumberjack_version: latest 6 | lumberjack_net: 'bridge' 7 | lumberjack_hostname: "{{ ansible_host }}" 8 | lumberjack_image: "digitalwonderland/logstash-forwarder:{{ lumberjack_version }}" 9 | lumberjack_host_port: 5043 10 | lumberjack_consul_service_id: "{{ ansible_hostname }}:lumberjack:{{ lumberjack_host_port }}" 11 | lumberjack_ssl_certificate_file: "logstash-forwarder.crt" 12 | lumberjack_ssl_key_file: "logstash-forwarder.key" 13 | lumberjack_docker_socket: "{{ docker_host }}" 14 | 15 | logstash_config_dir: "/opt/logstash/conf.d" 16 | logstash_lumberjack_host: "logstash.service.{{ consul_domain }}" 17 | logstash_output_stdout: false 18 | logstash_salesforce: false 19 | logstash_s3: false 20 | logstash_elasticsearch_output: "elasticsearch.service.{{ consul_domain }}:9200" 21 | 22 | dcos_cli_image: capgemini/dcos-cli 23 | dcos_cli_zk_master_peers: "zk://{{ zookeeper_peers_nodes }}/mesos" 24 | dcos_cli_mesos_master_url: "http://{{ ansible_host }}:5050" 25 | dcos_cli_marathon_url: "http://{{ ansible_host }}:8080" 26 | dcos_cli_sources: '["https://github.com/mesosphere/multiverse/archive/version-1.x.zip"]' 27 | dcos_cli_apps_list: 28 | - { name: logstash, type: app } 29 | - { name: kibana, type: app } 30 | -------------------------------------------------------------------------------- /roles/logstash/files/logstash-forwarder.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDNTCCAh2gAwIBAgIJAOqJMzn/H04QMA0GCSqGSIb3DQEBBQUAMBsxGTAXBgNV 3 | BAMUECouc2VydmljZS5jb25zdWwwHhcNMTYwMTE0MTIwNTE4WhcNMjUxMDEzMTIw 4 | NTE4WjAbMRkwFwYDVQQDFBAqLnNlcnZpY2UuY29uc3VsMIIBIjANBgkqhkiG9w0B 5 | AQEFAAOCAQ8AMIIBCgKCAQEAoy7Tab+9QroIQTZKXzO8A7l4oGnyrh2yAnETO7gr 6 | xSfZjR8uFDxzthJWKZc+384Sd/G/G5KwqOrJhtB1w1qzlofj+P710AQ4VCE8bYWB 7 | UDvEY5O2A6CJDmHvx8L/B1AosfYkbzQ9TRfD+TKVdgeW9zJntQWVUL406fSGlrsk 8 | isK8ABnmy7oFUOpn6WCJvvnVPAiblw+lRYl7hu8447GhFelcAZMlaVerEvMAPgDF 9 | 8WZYjY+vAxVvw1t5/xuYqgy9sbsJVDg0QVDf5io4ztGuAd6nGy8EmvWFEZQFPkN3 10 | 76JgrqRTljTS39lfiLXRzZZTcvELM0CCNxBCFsZvPA3RaQIDAQABo3wwejAdBgNV 11 | HQ4EFgQUL/VsQCvoMj5bHf0dE4kUmnyFOW0wSwYDVR0jBEQwQoAUL/VsQCvoMj5b 12 | Hf0dE4kUmnyFOW2hH6QdMBsxGTAXBgNVBAMUECouc2VydmljZS5jb25zdWyCCQDq 13 | iTM5/x9OEDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBH6iaWfbq6 14 | TO+oE7oHo/7EkPoKE8rxCJXcbksTOBgLt3gYqbROKwLC9Hy/etjqddVaS2LMfBCB 15 | xixL4YgZowC6EsIrfVNhv+e9RpszfXjwZSm1nAYm+6NDr9X1xnkhM6RBD4KDcSvd 16 | eNIAXmycvWSnhWre5/UY55fyGdEhpGifrcriaxWz/gVGQbgbRNmQyjuWA9FSBIF4 17 | /6VZFEx8c4IK7JZSnR8Gm/y1Eo+Jjrmf2u4IZ6f8GLGANlnG4PldizFiZ0hx2bLS 18 | +wc3atHRNc6ZSNjZyHeNfvVligo4/9ActxFbFlJSOwwXBEN3jDt5gdBJ2T75c0Sk 19 | sUK3qM8TWWxn 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /roles/logstash/files/logstash-forwarder.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAoy7Tab+9QroIQTZKXzO8A7l4oGnyrh2yAnETO7grxSfZjR8u 3 | FDxzthJWKZc+384Sd/G/G5KwqOrJhtB1w1qzlofj+P710AQ4VCE8bYWBUDvEY5O2 4 | A6CJDmHvx8L/B1AosfYkbzQ9TRfD+TKVdgeW9zJntQWVUL406fSGlrskisK8ABnm 5 | y7oFUOpn6WCJvvnVPAiblw+lRYl7hu8447GhFelcAZMlaVerEvMAPgDF8WZYjY+v 6 | AxVvw1t5/xuYqgy9sbsJVDg0QVDf5io4ztGuAd6nGy8EmvWFEZQFPkN376JgrqRT 7 | ljTS39lfiLXRzZZTcvELM0CCNxBCFsZvPA3RaQIDAQABAoIBAHjFl0KU3gYcmS9q 8 | dvCu4WAATP6sayfiYnTcK1fvnrV0INcJVJk1hI4kVBDEF4ycf562FLLbhlP+MNjO 9 | P9otruyh9l+6k0M5XFcnogmM3X/8PAVWtUdJ8SXr5gL6lrVa5kOP4LdM+nGsPSaa 10 | AXQxedHKRGb9kt0HaTId/95e81SeTOhQZ86ETHxodALFF+Kv6RE5OS4dt3apxnwh 11 | M9FGGoMCdfkqNMPvGKoC/UpshDKNKiT8pNbae8OJFyU3JKEjBMfMSo5M+I5Y//Mk 12 | OhfktsbK+mfy1ZupSUEoztkDw2uNYbyXMEsKgWGXrrBhoFu+An9DYhkMytr6hLMW 13 | WRGIoeECgYEAzi9I/XTzhT9NGdA5TtuhvbHM9z5OOshAylF1RhXHRja58lCQdksO 14 | yM5p6xs8YNxx9xGcJzAuzyyRwJyc1/Q2C1mdS4MGYXp7dfSAmZz9TbC/N99KOUxy 15 | iOejzLTStSie61uCT0xEvnYEbgiQKGxW3y04jfVm5Ikxh6CmPBTGUzsCgYEAypvX 16 | CIFmNxppv4kKCinbrqa4vKu67SW/m6+hTQXESrHE1gRxXMAbN1eERdU8UP0MjMtA 17 | yiNh0jY9ZuOqUUgPVEF6lACdKTuH28xmSk3Ud7t5XSWdR9+Yydzpgd6BthJgvnHz 18 | dfwFYRG/k64VnOVJ71NT5/VxY163FRXXLHuXG6sCgYEAhNSntEnc/PHsDP49fVU3 19 | nQrn3jzwjyQlwXG7GLy9Fbn6D2bhuqPeUXXRfNqeClTawu5AaGq9LVEsUSdUUDgP 20 | fT5tfJFb0f7jfPlYxB4EfkGo3yjmG4Xpn9ODjkTMHlOeFkhs6gNbokxLzEuN+8zY 21 | Jo1uit4XPJI6K4NOtRQ5NLMCgYApt4jBEZOwSNn5PAg7K382KNHk1x838QvQzIrT 22 | xxoxnwS+ZE/LHyr7bCOqFUvECTZqTvdaJ4res5hU9Q9+iO3PFWRd0PqLINzKXv24 23 | 0umqdYl5qmMGB334ImpZ+SyQBpyw2dmdM3UQFY1ypOeCVJuykV+3ZQwhv8DGsKaL 24 | XC8y3QKBgDWLo/0eiVIlYQ6LA1/sjPNZAQBcvchfvsDxbFeKUEqw9Xb0xKYGmDIE 25 | bXcHNcTXFl5fSv8wabPBirWFo7kU16E3j54A1V9RUSonba2/xeWWxKZ0rfW6ju2e 26 | kc1J47rMcrk7R0MF1GDakn6jyn3aYlNDirxKhn43JLGDYaQUSlJE 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /roles/logstash/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Cam Parry 4 | description: 5 | company: Capgemini 6 | license: license (MIT) 7 | min_ansible_version: 2.0 8 | platforms: 9 | - name: CoreOS 10 | versions: 11 | - stable 12 | categories: 13 | - cloud 14 | - system 15 | dependencies: 16 | - role: handlers 17 | -------------------------------------------------------------------------------- /roles/logstash/tasks/config.yml: -------------------------------------------------------------------------------- 1 | - name: create configuration and ssl directory 2 | become: yes 3 | file: 4 | path: "{{ item }}" 5 | state: directory 6 | mode: 0755 7 | recurse: yes 8 | with_items: 9 | - "{{ logstash_config_dir }}/ssl" 10 | - "{{ logstash_config_dir }}/lumberjack" 11 | tags: 12 | - logstash 13 | 14 | - name: configure logstash 15 | become: yes 16 | template: 17 | src: logstash.conf.j2 18 | dest: "{{ logstash_config_dir }}/logstash.conf" 19 | tags: 20 | - logstash 21 | 22 | # tasks for running lumberjack 23 | - name: deploy lumberjack service 24 | become: yes 25 | become_user: root 26 | template: 27 | src: lumberjack.service.j2 28 | dest: /etc/systemd/system/lumberjack.service 29 | tags: 30 | - lumberjack 31 | 32 | - name: upload lumberjack config files 33 | become: yes 34 | template: 35 | src: logstash-forwarder.conf.j2 36 | dest: "{{ logstash_config_dir }}/lumberjack/logstash-forwarder.conf" 37 | tags: 38 | - lumberjack 39 | 40 | - name: upload lumberjack ssl files 41 | copy: 42 | src: "{{ item }}" 43 | dest: "{{ logstash_config_dir }}/ssl/{{ item }}" 44 | mode: 0644 45 | become: yes 46 | with_items: 47 | - "{{ lumberjack_ssl_certificate_file }}" 48 | - "{{ lumberjack_ssl_key_file }}" 49 | tags: 50 | - haproxy 51 | -------------------------------------------------------------------------------- /roles/logstash/tasks/lumberjack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: wait for logstash to start up 3 | wait_for: 4 | host: "{{ logstash_lumberjack_host }}" 5 | port: "{{ lumberjack_host_port }}" 6 | delay: 15 7 | tags: 8 | - logstash 9 | 10 | - name: ensure lumberjack is running (and enable it at boot) 11 | become: yes 12 | service: 13 | name: lumberjack 14 | state: started 15 | enabled: yes 16 | tags: 17 | - logstash 18 | -------------------------------------------------------------------------------- /roles/logstash/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: config.yml 3 | - include: ../../dcos_cli/tasks/apps.yml 4 | - include: lumberjack.yml 5 | -------------------------------------------------------------------------------- /roles/logstash/templates/logstash-forwarder.conf.j2: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "servers": [ "logstash:5043" ], 4 | "ssl certificate": "./lumberjack.crt", 5 | "ssl key": "./lumberjack.key", 6 | "ssl ca": "./lumberjack_ca.crt" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /roles/logstash/templates/logstash.conf.j2: -------------------------------------------------------------------------------- 1 | input { 2 | lumberjack { 3 | codec => "json" 4 | port => 5043 5 | ssl_certificate => "{{ logstash_config_dir }}/ssl/{{ lumberjack_ssl_certificate_file }}" 6 | ssl_key => "{{ logstash_config_dir }}/ssl/{{ lumberjack_ssl_key_file }}" 7 | } 8 | {% if logstash_s3 %} 9 | s3 { 10 | bucket => "{{ lookup('env','TF_VAR_s3_bucket_name') }}" 11 | prefix => "elb" 12 | delete => true 13 | region => "{{ lookup('env','TF_VAR_region') }}" 14 | region_endpoint => "{{ lookup('env','TF_VAR_region') }}" 15 | access_key_id => "{{ lookup('env','AWS_ACCESS_KEY_ID') }}" 16 | secret_access_key => "{{ lookup('env','AWS_SECRET_ACCESS_KEY') }}" 17 | } 18 | {% endif %} 19 | {% if logstash_salesforce %} 20 | salesforce { 21 | client_id => '{{ salesforce_client_id }}' 22 | client_secret => '{{ salesforce_client_secret }}' 23 | username => '{{ salesforce_client_username }}' 24 | password => '{{ salesforce_client_password }}' 25 | security_token => '{{ salesforce_client_security_token }}' 26 | sfdc_object_name => 'Opportunity' 27 | } 28 | {% endif %} 29 | } 30 | 31 | output { 32 | elasticsearch { 33 | hosts => "{{ logstash_elasticsearch_output }}" 34 | } 35 | 36 | {% if logstash_output_stdout %} 37 | stdout { 38 | codec => rubydebug 39 | } 40 | {% endif %} 41 | } 42 | -------------------------------------------------------------------------------- /roles/logstash/templates/lumberjack.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=lumberjack 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | RestartSec=20 9 | TimeoutStartSec=0 10 | EnvironmentFile=-/etc/environment 11 | Environment="DOCKER_HOST={{ lumberjack_docker_socket }}" 12 | ExecStartPre=-/usr/bin/docker kill lumberjack 13 | ExecStartPre=-/usr/bin/docker rm lumberjack 14 | ExecStartPre=/usr/bin/docker pull {{ lumberjack_image }} 15 | ExecStart=/usr/bin/docker run --name lumberjack \ 16 | --restart={{ lumberjack_restart_policy }} \ 17 | --net={{ lumberjack_net }} \ 18 | --hostname={{ lumberjack_hostname }} \ 19 | -v /var/lib/docker/:/var/lib/docker:ro \ 20 | -v /var/run/docker.sock:/var/run/docker.sock:ro \ 21 | -v "{{ logstash_config_dir }}/lumberjack/logstash-forwarder.conf:/etc/logstash-forwarder.conf:rw" \ 22 | -v "{{ logstash_config_dir }}/ssl:/mnt/logstash-forwarder" \ 23 | -e "LOGSTASH_HOST={{ logstash_lumberjack_host }}:5043" \ 24 | {{ lumberjack_image }} 25 | 26 | ExecStop=/usr/bin/docker stop lumberjack 27 | 28 | [Install] 29 | WantedBy=multi-user.target 30 | -------------------------------------------------------------------------------- /roles/marathon/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for marathon 3 | marathon_consul_dir: /etc/consul.d 4 | marathon_enabled: true 5 | marathon_version: '1.1.1' 6 | marathon_restart_policy: 'always' 7 | marathon_net: 'host' 8 | marathon_hostname: "{{ ansible_host }}" 9 | marathon_port: '8080' 10 | marathon_container_memory_limit: '512MB' 11 | marathon_java_settings: '-Xmx512m -Xms512m -XX:+HeapDumpOnOutOfMemoryError' 12 | marathon_artifact_store: 'file:///store' 13 | marathon_artifact_store_dir: '/etc/marathon/store' 14 | marathon_server_zk_group: marathon_servers 15 | marathon_image: "mesosphere/marathon:v{{ marathon_version }}" 16 | marathon_master_peers: "zk://{{ zookeeper_peers_nodes }}/mesos" 17 | marathon_zk_peers: "zk://{{ zookeeper_peers_nodes }}/marathon" 18 | marathon_command: "--event_subscriber http_callback --artifact_store {{ marathon_artifact_store }} --hostname {{ marathon_hostname }} --master {{ marathon_master_peers }} --zk {{ marathon_zk_peers }}" 19 | -------------------------------------------------------------------------------- /roles/marathon/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for marathon 3 | - name: wait for marathon to listen 4 | command: /usr/local/bin/marathon-wait-for-listen.sh 5 | 6 | - name: restart marathon 7 | become: yes 8 | service: 9 | name: marathon 10 | state: restarted 11 | -------------------------------------------------------------------------------- /roles/marathon/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: create marathon artifact store directory 2 | when: marathon_artifact_store_dir is defined 3 | file: 4 | path: "{{ marathon_artifact_store_dir }}" 5 | state: directory 6 | mode: 0755 7 | become: yes 8 | tags: 9 | - marathon 10 | 11 | - name: deploy marathon service 12 | become: yes 13 | become_user: root 14 | template: 15 | src: marathon.service.j2 16 | dest: /etc/systemd/system/marathon.service 17 | notify: 18 | - reload systemd 19 | - restart marathon 20 | tags: 21 | - marathon 22 | 23 | # Attach to the running container, or start it if needed 24 | # and forward all signals so that the process manager can detect 25 | # when a container stops and correctly restart it. 26 | - name: ensure marathon is running (and enable it at boot) 27 | become: yes 28 | service: 29 | name: marathon 30 | state: started 31 | enabled: yes 32 | tags: 33 | - marathon 34 | 35 | - name: Set marathon consul service definition 36 | become: yes 37 | template: 38 | src: marathon-consul.j2 39 | dest: "{{ marathon_consul_dir }}/marathon.json" 40 | notify: 41 | - restart consul 42 | tags: 43 | - marathon 44 | -------------------------------------------------------------------------------- /roles/marathon/templates/marathon-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "marathon", 4 | "tags": [ "marathon" ], 5 | "port": {{ marathon_port }}, 6 | "check": { 7 | "script": "curl --silent --show-error --fail --dump-header /dev/stderr --retry 2 http://{{ marathon_hostname }}:{{ marathon_port }}/ping", 8 | "interval": "10s", 9 | "timeout": "3s" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /roles/marathon/templates/marathon-wait-for-listen.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MAX_SECONDS=120 4 | while /bin/true 5 | do 6 | curl -s http://localhost:{{ marathon_port }}/ping | grep -q "pong" && exit 0 || sleep 1 7 | [[ "$SECONDS" -ge "$MAX_SECONDS" ]] && exit 2 8 | done 9 | 10 | # EOF 11 | -------------------------------------------------------------------------------- /roles/marathon/templates/marathon.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Marathon 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | RestartSec=20 9 | TimeoutStartSec=0 10 | EnvironmentFile=-/etc/environment 11 | ExecStartPre=-/usr/bin/docker kill marathon 12 | ExecStartPre=-/usr/bin/docker rm marathon 13 | ExecStartPre=/usr/bin/docker pull {{ marathon_image }} 14 | ExecStart=/usr/bin/docker run --name marathon \ 15 | --memory={{ marathon_container_memory_limit }} \ 16 | --restart={{ marathon_restart_policy }} \ 17 | --net={{ marathon_net }} \ 18 | -p {{ marathon_port }}:{{ marathon_port }} \ 19 | -v {{ marathon_artifact_store_dir }}:/store \ 20 | -e "LIBPROCESS_IP=${COREOS_PRIVATE_IPV4}" \ 21 | -e "JAVA_OPTS={{ marathon_java_settings }}" \ 22 | {{ marathon_image }} \ 23 | {{ marathon_command }} 24 | 25 | ExecStop=/usr/bin/docker stop marathon 26 | 27 | [Install] 28 | WantedBy=multi-user.target 29 | -------------------------------------------------------------------------------- /roles/marathon/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for marathon 3 | -------------------------------------------------------------------------------- /roles/mesos/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Common 3 | consul_dir: /etc/consul.d 4 | mesos_executor_registration_timeout: 10mins 5 | mesos_cluster_name: "Cluster01" 6 | mesos_ip: "{{ ansible_default_ipv4.address }}" 7 | mesos_hostname: "{{ ansible_host }}" 8 | mesos_docker_socket: "/var/run/weave/weave.sock" 9 | mesos_version: "0.28.1" 10 | 11 | # Defaults file for mesos-salve 12 | mesos_agent_port: 5051 13 | mesos_containerizers: "docker,mesos" 14 | mesos_resources: "ports(*):[31000-32000]" 15 | mesos_agent_work_dir: "/tmp/mesos" 16 | mesos_agent_image: "mesosphere/mesos-slave:{{ mesos_version }}" 17 | mesos_gpu: false 18 | 19 | # Defaults file for mesos-master 20 | mesos_zookeeper_group: zookeeper_servers 21 | mesos_master_port: 5050 22 | mesos_master_work_dir: "/var/lib/mesos" 23 | mesos_master_image: "mesosphere/mesos-master:{{ mesos_version }}" 24 | mesos_master_command: "--registry=replicated_log" 25 | 26 | prometheus_mesos_exporter_image: "prom/mesos-exporter:latest" 27 | prometheus_mesos_exporter_port: 9105 28 | prometheus_mesos_exporter_consul_service_id: "{{ ansible_hostname }}:mesos-exporter:{{ prometheus_mesos_exporter_port }}" 29 | 30 | # The Mesos quorum value is based on the number of Mesos Masters. Take the 31 | # number of masters, divide by 2, and round-up to nearest integer. For example, 32 | # if there are 1 or 2 masters the quorum count is 1. If there are 3 or 4 33 | # masters then the quorum count is 2. For 5 or 6 masters it's 3 and so on. 34 | mesos_quorum: " 35 | {% if mesos_master_quorum is defined %} 36 | {{ mesos_master_quorum }} 37 | {% else %} 38 | {{ ( groups.mesos_masters|count / 2) | round(0, 'ceil') | int }} 39 | {%- endif -%} 40 | " 41 | -------------------------------------------------------------------------------- /roles/mesos/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for mesos 3 | - name: start mesos master 4 | become: yes 5 | service: 6 | name: mesos-master 7 | state: started 8 | 9 | - name: start mesos agent 10 | become: yes 11 | service: 12 | name: mesos-agent 13 | state: started 14 | 15 | - name: restart mesos master 16 | become: yes 17 | service: 18 | name: mesos-master 19 | state: restarted 20 | 21 | - name: restart mesos agent 22 | become: yes 23 | service: 24 | name: mesos-agent 25 | state: restarted 26 | -------------------------------------------------------------------------------- /roles/mesos/tasks/agent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Tasks for Agent nodes 3 | - name: create mesos-agent work directory 4 | file: 5 | path: "{{ mesos_agent_work_dir }}" 6 | state: directory 7 | mode: 0755 8 | become: yes 9 | tags: 10 | - mesos-agent 11 | 12 | - name: detect gpu support 13 | become: yes 14 | shell: "ls -la nvidia0" 15 | args: 16 | chdir: /dev 17 | register: nvidio_drivers 18 | failed_when: nvidio_drivers.rc != 0 and "No such file or directory" not in nvidio_drivers.stderr 19 | tags: 20 | - mesos-agent 21 | 22 | - name: add gpu support for slave 23 | set_fact: 24 | mesos_gpu: true 25 | when: nvidio_drivers.rc == 0 26 | tags: 27 | - mesos-agent 28 | 29 | - name: deploy mesos-agent service 30 | become: yes 31 | become_user: root 32 | template: 33 | src: mesos-agent.service.j2 34 | dest: /etc/systemd/system/mesos-agent.service 35 | notify: 36 | - reload systemd 37 | - restart mesos agent 38 | tags: 39 | - mesos-agent 40 | 41 | - name: ensure mesos-agent is running (and enable it at boot) 42 | become: yes 43 | service: 44 | name: mesos-agent 45 | state: started 46 | enabled: yes 47 | tags: 48 | - mesos-agent 49 | 50 | - name: run prometheus mesos agent exporter container 51 | when: prometheus_enabled|bool 52 | docker: 53 | name: mesos-exporter 54 | image: "{{ prometheus_mesos_exporter_image }}" 55 | command: "-exporter.scrape-mode=agent -exporter.url=http://{{ mesos_hostname }}:{{ mesos_agent_port }}" 56 | state: started 57 | restart_policy: always 58 | ports: 59 | - "{{ prometheus_mesos_exporter_port }}:{{ prometheus_mesos_exporter_port }}" 60 | environment: "{{ proxy_env }}" 61 | tags: 62 | - prometheus 63 | - mesos_agent 64 | 65 | - name: Set mesos-exporter consul service definition 66 | when: prometheus_enabled|bool 67 | become: yes 68 | template: 69 | src: mesos-exporter-consul.j2 70 | dest: "{{ consul_dir }}/mesos-exporter.json" 71 | notify: 72 | - restart consul 73 | tags: 74 | - prometheus 75 | - mesos_agent 76 | -------------------------------------------------------------------------------- /roles/mesos/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - include: master.yml 2 | when: mesos_install_mode == "master" 3 | 4 | - include: agent.yml 5 | when: mesos_install_mode == "agent" 6 | -------------------------------------------------------------------------------- /roles/mesos/tasks/master.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Tasks for Master nodes 3 | - name: create mesos-master work directory 4 | file: 5 | path: "{{ mesos_master_work_dir }}" 6 | state: directory 7 | mode: 0755 8 | become: yes 9 | tags: 10 | - mesos-master 11 | 12 | - name: deploy mesos-master service 13 | become: yes 14 | become_user: root 15 | template: 16 | src: mesos-master.service.j2 17 | dest: /etc/systemd/system/mesos-master.service 18 | notify: 19 | - reload systemd 20 | - restart mesos master 21 | tags: 22 | - mesos-master 23 | 24 | - name: ensure mesos-master is running (and enable it at boot) 25 | become: yes 26 | service: 27 | name: mesos-master 28 | state: started 29 | enabled: yes 30 | tags: 31 | - mesos-master 32 | 33 | - name: Set mesos-master consul service definition 34 | become: yes 35 | template: 36 | src: mesos-master-consul.j2 37 | dest: "{{ consul_dir }}/mesos-master.json" 38 | notify: 39 | - restart consul 40 | tags: 41 | - mesos-master 42 | 43 | - name: run prometheus mesos master exporter container 44 | when: prometheus_enabled|bool 45 | docker: 46 | name: mesos-exporter 47 | image: "{{ prometheus_mesos_exporter_image }}" 48 | command: "-exporter.scrape-mode=master -exporter.url=http://{{ mesos_hostname }}:{{ mesos_master_port }}" 49 | state: started 50 | restart_policy: always 51 | ports: 52 | - "{{ prometheus_mesos_exporter_port }}:{{ prometheus_mesos_exporter_port }}" 53 | environment: "{{ proxy_env }}" 54 | tags: 55 | - prometheus 56 | - mesos_master 57 | 58 | - name: Set mesos-exporter consul service definition 59 | when: prometheus_enabled|bool 60 | become: yes 61 | template: 62 | src: mesos-exporter-consul.j2 63 | dest: "{{ consul_dir }}/mesos-exporter.json" 64 | notify: 65 | - restart consul 66 | tags: 67 | - prometheus 68 | - mesos_master 69 | -------------------------------------------------------------------------------- /roles/mesos/templates/mesos-agent-consul.j2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Capgemini/Apollo/21f949d8cec5a07a97202cfcb67a0dbf8c90090b/roles/mesos/templates/mesos-agent-consul.j2 -------------------------------------------------------------------------------- /roles/mesos/templates/mesos-agent.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=MesosAgent 3 | After=docker.service 4 | Requires=docker.service 5 | Requires=weaveproxy.service 6 | 7 | [Service] 8 | Restart=on-failure 9 | RestartSec=20 10 | TimeoutStartSec=0 11 | EnvironmentFile=-/etc/environment 12 | ExecStartPre=-/usr/bin/docker kill mesos_agent 13 | ExecStartPre=-/usr/bin/docker rm mesos_agent 14 | ExecStartPre=/usr/bin/docker pull {{ mesos_agent_image }} 15 | ExecStart=/usr/bin/docker run --rm --name mesos_agent \ 16 | --net=host \ 17 | --privileged=true \ 18 | -p {{ mesos_agent_port }}:{{ mesos_agent_port }} \ 19 | -v /sys:/sys \ 20 | -v /proc:/host/proc:ro \ 21 | -v /lib/libgcrypt.so:/lib/libgcrypt.so:ro \ 22 | -v /lib/libgcrypt.so:/lib/libgcrypt.so.20:ro \ 23 | -v /lib/libsystemd.so.0:/lib/libsystemd.so.0:ro \ 24 | -v /lib/libpthread.so.0:/lib/libpthread.so.0:ro \ 25 | -v /lib64/libdevmapper.so.1.02:/lib/libdevmapper.so.1.02:ro \ 26 | -v /usr/bin/docker:/usr/bin/docker:ro \ 27 | -v {{ mesos_docker_socket }}:/var/run/docker.sock \ 28 | -v {{ mesos_agent_work_dir }}:{{ mesos_agent_work_dir }} \ 29 | -e "MESOS_MASTER=zk://{{ zookeeper_peers_nodes }}/mesos" \ 30 | -e "MESOS_EXECUTOR_REGISTRATION_TIMEOUT={{ mesos_executor_registration_timeout }}" \ 31 | -e "MESOS_CONTAINERIZERS={{ mesos_containerizers }}" \ 32 | -e "MESOS_RESOURCES={{ mesos_resources }}" \ 33 | -e "MESOS_IP={{ mesos_ip }}" \ 34 | -e "MESOS_WORK_DIR={{ mesos_agent_work_dir }}" \ 35 | -e "MESOS_LOG_DIR=/var/log/mesos" \ 36 | -e "MESOS_HOSTNAME={{ mesos_hostname }}" \ 37 | -e "MESOS_ISOLATION=cgroups/cpu,cgroups/mem" \ 38 | -e "MESOS_CGROUPS_ROOT=system.slice/mesos-agent.service" \ 39 | -e "MESOS_CGROUPS_HIERARCHY=/sys/fs/cgroup" \ 40 | {% if mesos_gpu|bool %} 41 | -e "MESOS_ATTRIBUTES=hasGpu:true" \ 42 | {% endif %} 43 | -e "LIBPROCESS_IP=${COREOS_PRIVATE_IPV4}" \ 44 | {{ mesos_agent_image }} 45 | 46 | ExecStop=/usr/bin/docker stop mesos_agent 47 | 48 | [Install] 49 | WantedBy=multi-user.target 50 | -------------------------------------------------------------------------------- /roles/mesos/templates/mesos-exporter-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "id": "mesos-exporter", 4 | "name": "prometheus-mesos-exporter", 5 | "tags": [ "mesos", "prometheus" ], 6 | "check": { 7 | "script": "curl --silent --show-error --fail --dump-header /dev/stderr --retry 2 http://{{ mesos_hostname }}:{{ prometheus_mesos_exporter_port }}", 8 | "interval": "10s", 9 | "timeout": "3s" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /roles/mesos/templates/mesos-master-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "mesos-master", 4 | "port": {{ mesos_master_port }}, 5 | "tags": [ "mesos" ], 6 | "check": { 7 | "script": "curl --silent --show-error --fail --dump-header /dev/stderr --retry 2 http://{{ mesos_hostname }}:{{ mesos_master_port }}/master/health", 8 | "interval": "10s", 9 | "timeout": "3s" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /roles/mesos/templates/mesos-master.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=MesosMaster 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | RestartSec=20 9 | TimeoutStartSec=0 10 | EnvironmentFile=-/etc/environment 11 | ExecStartPre=-/usr/bin/docker kill mesos_master 12 | ExecStartPre=-/usr/bin/docker rm mesos_master 13 | ExecStartPre=/usr/bin/docker pull {{ mesos_master_image }} 14 | ExecStart=/usr/bin/docker run --rm --name mesos_master \ 15 | --net=host \ 16 | -v {{ mesos_master_work_dir }}:{{ mesos_master_work_dir }} \ 17 | -p {{ mesos_master_port }}:{{ mesos_master_port }} \ 18 | -e "MESOS_HOSTNAME={{ mesos_hostname }}" \ 19 | -e "MESOS_IP={{ mesos_ip }}" \ 20 | -e "MESOS_CLUSTER={{ mesos_cluster_name }}" \ 21 | -e "MESOS_ZK=zk://{{ zookeeper_peers_nodes }}/mesos" \ 22 | -e "MESOS_QUORUM={{ mesos_quorum }}" \ 23 | -e "MESOS_WORK_DIR={{ mesos_master_work_dir }}" \ 24 | -e "MESOS_EXTERNAL_LOG_FILE=/var/log/mesos" \ 25 | -e "LIBPROCESS_IP=${COREOS_PRIVATE_IPV4}" \ 26 | {{ mesos_master_image }} {{ mesos_master_command }} 27 | 28 | ExecStop=/usr/bin/docker stop mesos_master 29 | 30 | [Install] 31 | WantedBy=multi-user.target 32 | -------------------------------------------------------------------------------- /roles/mesos_consul/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for mesos-consul 3 | mesos_consul_image_tag: v0.3.2 4 | mesos_consul_image: "ciscocloud/mesos-consul:{{ mesos_consul_image_tag }}" 5 | mesos_consul_refresh: "5s" 6 | mesos_consul_zk: "zk://zookeeper.service.{{ consul_domain }}:2181/mesos" 7 | -------------------------------------------------------------------------------- /roles/mesos_consul/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for mesos-consul 3 | - name: restart mesos_consul 4 | become: yes 5 | service: 6 | name: mesos_consul 7 | state: restarted 8 | -------------------------------------------------------------------------------- /roles/mesos_consul/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Graham Taylor 4 | description: 5 | company: Capgemini 6 | license: license (MIT) 7 | min_ansible_version: 1.2 8 | platforms: 9 | - name: CoreOS 10 | versions: 11 | - all 12 | categories: 13 | - cloud 14 | - system 15 | dependencies: 16 | - handlers 17 | -------------------------------------------------------------------------------- /roles/mesos_consul/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: deploy mesos_consul service 4 | become: yes 5 | become_user: root 6 | template: 7 | src: mesos_consul.service.j2 8 | dest: /etc/systemd/system/mesos_consul.service 9 | notify: 10 | - reload systemd 11 | - restart mesos_consul 12 | tags: 13 | - mesos_consul 14 | 15 | - name: enable mesos_consul 16 | become: yes 17 | service: 18 | name: mesos_consul 19 | enabled: yes 20 | state: started 21 | tags: 22 | - mesos_consul 23 | 24 | -------------------------------------------------------------------------------- /roles/mesos_consul/templates/mesos_consul.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Mesos Consul 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | TimeoutStartSec=0 9 | EnvironmentFile=/etc/environment 10 | 11 | ExecStartPre=-/usr/bin/docker kill mesos_consul 12 | ExecStartPre=-/usr/bin/docker rm mesos_consul 13 | ExecStartPre=/usr/bin/docker pull {{ mesos_consul_image }} 14 | 15 | ExecStart=/usr/bin/bash -c "/usr/bin/docker run --rm --name mesos_consul \ 16 | {{ mesos_consul_image }} \ 17 | --zk={{ mesos_consul_zk }} --refresh={{ mesos_consul_refresh }}" 18 | 19 | ExecStop=/usr/bin/docker stop mesos_consul 20 | 21 | [Install] 22 | WantedBy=multi-user.target 23 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for mesos-maintenance 3 | mesos_maintenance_server_group: mesos_agents 4 | mesos_maintenance_server_master_group: mesos_masters 5 | mesos_maintenance_master_url: '' 6 | mesos_maintenance_starting_time: '' 7 | mesos_maintenance_duration: '' 8 | mesos_maintenance_schedule: false 9 | mesos_maintenance_start: false 10 | mesos_maintenance_complete: false 11 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for mesos-maintenance 3 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/tasks/complete.yml: -------------------------------------------------------------------------------- 1 | # complete maintenance 2 | - name: complete maintenance 3 | command: "curl -XPOST -x '' http://{{ mesos_maintenance_master_url }}/master/machine/up -d@/tmp/machines.json -H 'Content-type: application/json'" 4 | register: complete_content 5 | when: mesos_maintenance_complete 6 | 7 | - name: wait for agent to be healthy 8 | sudo: yes 9 | command: /tmp/wait-for-agent.sh 10 | when: mesos_maintenance_complete 11 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: schedule.yml 3 | when: mesos_maintenance_schedule 4 | 5 | - include: start.yml 6 | when: mesos_maintenance_start 7 | 8 | - include: complete.yml 9 | when: mesos_maintenance_complete 10 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/tasks/schedule.yml: -------------------------------------------------------------------------------- 1 | # schedule maintenance 2 | - name: deploy schedule template 3 | sudo: yes 4 | sudo_user: root 5 | template: 6 | src: schedule.json.j2 7 | dest: /tmp/schedule.json 8 | run_once: true 9 | when: mesos_maintenance_schedule 10 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/tasks/start.yml: -------------------------------------------------------------------------------- 1 | # start maintenance 2 | - name: deploy machines template 3 | sudo: yes 4 | sudo_user: root 5 | template: 6 | src: "{{ item.src }}" 7 | dest: "{{ item.dest }}" 8 | mode: 0755 9 | when: mesos_maintenance_start 10 | tags: 11 | - mesos-maintenance 12 | with_items: 13 | - src: machines.json.j2 14 | dest: /tmp/machines.json 15 | - src: wait-for-agent.sh.j2 16 | dest: /tmp/wait-for-agent.sh 17 | 18 | - name: start maintenance 19 | command: "curl -XPOST -x '' http://{{ mesos_maintenance_master_url }}/master/machine/down -d@/tmp/machines.json -H 'Content-type: application/json'" 20 | register: start_content 21 | when: mesos_maintenance_start 22 | 23 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/templates/machines.json.j2: -------------------------------------------------------------------------------- 1 | [ 2 | { "hostname" : "{{ ansible_host }}", "ip" : "{{ ansible_host }}" } 3 | ] 4 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/templates/schedule.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "windows" : [ 3 | {%- for host in groups[mesos_maintenance_server_group] -%} 4 | { 5 | "machine_ids" : [ 6 | { "hostname" : "{{ hostvars[host].ansible_default_ipv4.address }}", "ip" : "{{ hostvars[host].ansible_default_ipv4.address }}" } 7 | ], 8 | "unavailability" : { 9 | "start" : { "nanoseconds" : {{ mesos_maintenance_starting_time }} }, 10 | "duration" : { "nanoseconds" : {{ mesos_maintenance_starting_time }} } 11 | } 12 | }{% if not loop.last %},{% endif %} 13 | {%- endfor -%} 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/templates/wait-for-agent.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MAX_SECONDS=20 4 | 5 | while /bin/true 6 | do 7 | curl -x '' --write-out %{http_code} --silent --output /dev/null "http://{{ ansible_host }}:5051/slave(1)/health" | grep -q 200 && exit 0 || sleep 1 8 | [[ "$SECONDS" -ge "$MAX_SECONDS" ]] && exit 2 9 | done 10 | -------------------------------------------------------------------------------- /roles/mesos_maintenance/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for mesos-maintenance 3 | -------------------------------------------------------------------------------- /roles/prometheus/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for prometheus 3 | prometheus_consul_host: "{{ ansible_host }}" 4 | prometheus_config_dir: /etc/prometheus 5 | prometheus_node_exporter_image: "prom/node-exporter:latest" 6 | prometheus_node_exporter_port: 9100 7 | prometheus_node_exporter_hostname: "{{ ansible_host }}" 8 | prometheus_node_exporter_consul_service_id: "{{ ansible_hostname }}:node-exporter:9100" 9 | prometheus_consul_dir: /etc/consul.d 10 | # promdash settings 11 | promdash_database_url: "mysql2://promdash:promdash@mysql-promdash-group.service.consul/promdash" 12 | promdash_image: "capgemini/promdash" 13 | -------------------------------------------------------------------------------- /roles/prometheus/handlers/main.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Capgemini/Apollo/21f949d8cec5a07a97202cfcb67a0dbf8c90090b/roles/prometheus/handlers/main.yml -------------------------------------------------------------------------------- /roles/prometheus/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: Graham Taylor 4 | description: 5 | company: Capgemini 6 | license: license (MIT) 7 | min_ansible_version: 1.9 8 | platforms: 9 | - name: Ubuntu 10 | versions: 11 | - trusty 12 | 13 | categories: 14 | - cloud 15 | - system 16 | 17 | -------------------------------------------------------------------------------- /roles/prometheus/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # tasks for running prometheus 2 | - name: create prometheus config dir 3 | file: 4 | path: "{{ prometheus_config_dir }}" 5 | state: directory 6 | mode: 0755 7 | become: yes 8 | tags: 9 | - prometheus 10 | 11 | - name: upload prometheus config file 12 | template: 13 | src: prometheus.yml.j2 14 | dest: "{{ prometheus_config_dir }}/prometheus.yml" 15 | mode: 0755 16 | become: yes 17 | tags: 18 | - prometheus 19 | 20 | - name: run prometheus node exporter container 21 | docker: 22 | name: node-exporter 23 | image: "{{ prometheus_node_exporter_image }}" 24 | state: started 25 | restart_policy: always 26 | net: host 27 | ports: 28 | - "{{ prometheus_node_exporter_port }}:{{ prometheus_node_exporter_port }}" 29 | environment: "{{ proxy_env }}" 30 | tags: 31 | - prometheus 32 | 33 | - name: set node-exporter consul service definition 34 | become: yes 35 | template: 36 | src: node-exporter-consul.j2 37 | dest: "{{ prometheus_consul_dir }}/node-exporter.json" 38 | notify: 39 | - restart consul 40 | tags: 41 | - prometheus 42 | -------------------------------------------------------------------------------- /roles/prometheus/templates/node-exporter-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "id": "node-exporter", 4 | "name": "prometheus-node-exporter", 5 | "port": {{ prometheus_node_exporter_port }}, 6 | "tags": [ "prometheus" ], 7 | "check": { 8 | "script": "curl --silent --show-error --fail --dump-header /dev/stderr --retry 2 http://{{ prometheus_node_exporter_hostname }}:{{ prometheus_node_exporter_port }}", 9 | "interval": "10s", 10 | "timeout": "3s" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /roles/prometheus/templates/prometheus.yml.j2: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 30s 4 | # scrape_timeout is set to the global default (10s). 5 | 6 | scrape_configs: 7 | - job_name: prometheus 8 | 9 | honor_labels: true 10 | 11 | # metrics_path defaults to '/metrics' 12 | # scheme defaults to 'http'. 13 | 14 | target_groups: 15 | - targets: ['localhost:9090'] 16 | 17 | - job_name: service-consul 18 | 19 | consul_sd_configs: 20 | - server: '{{ prometheus_consul_host }}:8500' 21 | services: ['mesos-exporter', 'cadvisor'] 22 | 23 | relabel_configs: 24 | - source_labels: ['__meta_consul_service'] 25 | regex: '(.*)' 26 | target_label: 'job' 27 | replacement: '$1' 28 | - source_labels: ['__meta_consul_node'] 29 | regex: '(.*)' 30 | target_label: 'instance' 31 | replacement: '$1' 32 | - source_labels: ['__meta_consul_service_address', '__meta_consul_service_port'] 33 | separator: ';' 34 | regex: '(.*);(.*)' 35 | replacement: '${1}:${2}' 36 | target_label: '__address__' 37 | 38 | - job_name: service-consul-node-exporter 39 | 40 | consul_sd_configs: 41 | - server: '{{ prometheus_consul_host }}:8500' 42 | services: ['node-exporter'] 43 | 44 | relabel_configs: 45 | - source_labels: ['__meta_consul_service'] 46 | regex: '(.*)' 47 | target_label: 'job' 48 | replacement: '$1' 49 | - source_labels: ['__meta_consul_node'] 50 | regex: '(.*)' 51 | target_label: 'instance' 52 | replacement: '$1' 53 | -------------------------------------------------------------------------------- /roles/prometheus/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for prometheus 3 | -------------------------------------------------------------------------------- /roles/traefik/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | traefik_marathon_hostname: marathon.service.{{ consul_domain }} 3 | traefik_marathon_endpoint: "http://{{ traefik_marathon_hostname }}:8080" 4 | traefik_marathon_domain: marathon.localhost 5 | traefik_image_tag: v1.0.0-beta.621 6 | traefik_image: "containous/traefik:{{ traefik_image_tag }}" 7 | traefik_config_dir: /etc/traefik 8 | traefik_frontend_port: 80 9 | traefik_webui_port: 8888 10 | traefik_log_level: DEBUG 11 | traefik_consul_dir: /etc/consul.d 12 | traefik_docker_socket: "{{ docker_host }}" 13 | traefik_network_interface: "{{ traefik_network_interface }}" 14 | -------------------------------------------------------------------------------- /roles/traefik/files/wait-for-marathon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ -n "$1" ]] && host=$1 || host=$HOSTNAME 4 | 5 | MAX_SECONDS=60 6 | while /bin/true 7 | do 8 | ping -q -c1 "$host" &>/dev/null 9 | if [[ $? -ne 0 ]]; then 10 | sleep 1 11 | [[ "$SECONDS" -ge "$MAX_SECONDS" ]] && exit 1 12 | else 13 | exit 0 14 | fi 15 | done 16 | 17 | # EOF 18 | -------------------------------------------------------------------------------- /roles/traefik/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart traefik 3 | become: yes 4 | command: systemctl restart traefik 5 | -------------------------------------------------------------------------------- /roles/traefik/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create traefik config directory 3 | become: yes 4 | file: 5 | path: "{{ traefik_config_dir }}" 6 | state: directory 7 | mode: 0755 8 | tags: 9 | - traefik 10 | 11 | - name: configure traefik 12 | become: yes 13 | template: 14 | src: traefik.toml.j2 15 | dest: "{{ traefik_config_dir }}/traefik.toml" 16 | mode: 0644 17 | backup: yes 18 | tags: 19 | - traefik 20 | 21 | - name: install check scripts 22 | become: yes 23 | copy: 24 | src: wait-for-marathon.sh 25 | dest: "{{ traefik_config_dir }}" 26 | mode: 0755 27 | tags: 28 | - traefik 29 | 30 | - name: deploy traefik service 31 | become: yes 32 | template: 33 | src: traefik.service.j2 34 | dest: /etc/systemd/system/traefik.service 35 | notify: 36 | - restart traefik 37 | tags: 38 | - traefik 39 | 40 | - name: enable traefik 41 | become: yes 42 | service: 43 | name: traefik 44 | state: started 45 | enabled: yes 46 | tags: 47 | - traefik 48 | 49 | - name: Set traefik consul service definition 50 | become: yes 51 | template: 52 | src: traefik-consul.json.j2 53 | dest: "{{ traefik_consul_dir }}/traefik.json" 54 | notify: 55 | - restart consul 56 | tags: 57 | - traefik 58 | -------------------------------------------------------------------------------- /roles/traefik/templates/traefik-consul.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "traefik", 4 | "tags": [ "http" ], 5 | "port": {{ traefik_frontend_port }}, 6 | "check": { 7 | "script": "curl --silent --show-error --fail --dump-header /dev/stderr --retry 2 --connect-timeout 5 --max-time 5 http://localhost:{{ traefik_frontend_port }}/", 8 | "timeout": "3s" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /roles/traefik/templates/traefik.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Traefik 3 | Requires=docker.service 4 | After=docker.service 5 | After=consul.service 6 | 7 | [Service] 8 | Restart=on-failure 9 | RestartSec=20 10 | TimeoutStartSec=0 11 | EnvironmentFile=-/etc/environment 12 | 13 | ExecStartPre=-/usr/bin/docker kill traefik 14 | ExecStartPre=-/usr/bin/docker rm traefik 15 | ExecStartPre=/usr/bin/docker pull {{ traefik_image }} 16 | ExecStartPre={{ traefik_config_dir }}/wait-for-marathon.sh {{ traefik_marathon_hostname }} 17 | ExecStart=/usr/bin/docker run --rm --name traefik \ 18 | --net=host \ 19 | -v {{ traefik_config_dir }}/traefik.toml:/traefik.toml \ 20 | {{ traefik_image }} 21 | 22 | ExecStop=/usr/bin/docker stop traefik 23 | 24 | [Install] 25 | WantedBy=multi-user.target 26 | -------------------------------------------------------------------------------- /roles/traefik/templates/traefik.toml.j2: -------------------------------------------------------------------------------- 1 | port = ":{{ traefik_frontend_port }}" 2 | graceTimeOut = 10 3 | logLevel = "{{ traefik_log_level }}" 4 | 5 | [web] 6 | address = ":{{ traefik_webui_port }}" 7 | 8 | [marathon] 9 | endpoint = "{{ traefik_marathon_endpoint }}" 10 | domain = "{{ traefik_marathon_domain }}" 11 | watch = true 12 | networkInterface = "{{ traefik_network_interface }}" 13 | -------------------------------------------------------------------------------- /roles/vault/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults settings for vault 3 | vault_consul_dir: /etc/consul.d 4 | vault_version: '0.4.0' 5 | vault_url: "https://releases.hashicorp.com/vault/{{ vault_version }}/vault_{{ vault_version }}_linux_amd64.zip" 6 | vault_config_folder: '/etc/vault' 7 | vault_port: 8200 8 | vault_addr: "http://127.0.0.1:{{ vault_port }}" 9 | vault_health_status_command: 'curl -k http://localhost:{{ vault_port }}/v1/sys/health' 10 | vault_initialize_status_command: 'curl -k http://localhost:{{ vault_port }}/v1/sys/init' 11 | vault_initialize_command: "curl -1 -X PUT -d '{{ vault_init_json }}' -k http://localhost:{{ vault_port }}/v1/sys/init" 12 | vault_advertise_addr: "{{ ansible_host }}" 13 | 14 | vault_init_json: '{ 15 | "secret_shares": 5, 16 | "secret_threshold": 3 17 | }' 18 | -------------------------------------------------------------------------------- /roles/vault/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart vault 3 | sudo: yes 4 | service: 5 | name: vault 6 | state: restarted 7 | enabled: yes 8 | tags: 9 | - vault 10 | 11 | - name: reload vault 12 | sudo: yes 13 | service: 14 | name: vault 15 | state: reload 16 | enabled: yes 17 | tags: 18 | - vault 19 | notify: 20 | - wait for vault to listen 21 | 22 | 23 | - name: wait for vault to listen 24 | wait_for: 25 | port: "{{ vault_default_port }}" 26 | -------------------------------------------------------------------------------- /roles/vault/tasks/bootstrap.yml: -------------------------------------------------------------------------------- 1 | - name: ensure vault is running (and enable it at boot) 2 | sudo: yes 3 | service: 4 | name: vault 5 | state: started 6 | enabled: yes 7 | tags: 8 | - vault 9 | 10 | - name: vault initialise status 11 | sudo: yes 12 | command: "{{ vault_initialize_status_command }}" 13 | register: vault_initialized_output 14 | tags: 15 | - vault 16 | 17 | - name: vault health status 18 | sudo: yes 19 | command: "{{ vault_health_status_command }}" 20 | register: vault_health_output 21 | tags: 22 | - vault 23 | 24 | - name: initialize vault 25 | when: vault_initialized_output.stdout == "{\"initialized\":false}" 26 | run_once: true 27 | changed_when: no 28 | sudo: yes 29 | command: "{{ vault_initialize_command }}" 30 | register: vault_init_output 31 | tags: 32 | - vault 33 | 34 | - name: set vault security values 35 | when: vault_initialized_output.stdout == "{\"initialized\":false}" 36 | run_once: true 37 | changed_when: no 38 | sudo: yes 39 | set_fact: 40 | vault_keys: "{{ (vault_init_output.stdout | from_json)['keys'] }}" 41 | vault_root_token: "{{ (vault_init_output.stdout | from_json)['root_token'] }}" 42 | tags: 43 | - vault 44 | 45 | - name: upload vault unseal template 46 | when: "'\"sealed\":false' not in vault_health_output.stdout" 47 | changed_when: no 48 | template: 49 | src: unseal.j2 50 | dest: "{{ vault_config_folder }}/unseal" 51 | mode: 0744 52 | sudo: yes 53 | tags: 54 | - vault 55 | notify: restart vault 56 | 57 | - name: unseal vault 58 | when: vault_keys is defined 59 | sudo: yes 60 | command: "{{ vault_config_folder }}/unseal" 61 | tags: 62 | - vault 63 | 64 | # This will be used to setup security for the entire stack later 65 | - name: store vault security values 66 | when: vault_root_token is defined 67 | local_action: template src=vault-security.yaml.j2 dest=./vault-security.yaml mode=0644 68 | sudo: False 69 | tags: 70 | - vault 71 | 72 | - meta: flush_handlers 73 | -------------------------------------------------------------------------------- /roles/vault/tasks/install.yml: -------------------------------------------------------------------------------- 1 | - name: download vault binary 2 | sudo: yes 3 | get_url: 4 | url: "{{ vault_url }}" 5 | dest: /tmp/vault.zip 6 | mode: 0755 7 | 8 | - name: uncompress vault 9 | unarchive: 10 | src: /tmp/vault.zip 11 | dest: /usr/bin 12 | copy: no 13 | 14 | - name: create vault config directory 15 | file: 16 | path: "{{ vault_config_folder }}" 17 | state: directory 18 | mode: 0755 19 | sudo: yes 20 | tags: 21 | - vault 22 | 23 | - name: upload vault template config files 24 | template: 25 | src: "{{ item.src }}" 26 | dest: "{{ item.dst }}" 27 | mode: 0755 28 | sudo: yes 29 | with_items: 30 | - { src: vault.conf.j2, dst: '/etc/init/vault.conf' } 31 | - { src: default.j2, dst: '/etc/default/vault' } 32 | - { src: config.hcl.j2, dst: "{{ vault_config_folder }}/config.hcl" } 33 | tags: 34 | - vault 35 | 36 | - name: upload wait for vault leader script 37 | sudo: yes 38 | template: 39 | src: wait-for-vault-leader.sh.j2 40 | dest: "{{ vault_config_folder }}/wait-for-vault-leader.sh" 41 | mode: 0755 42 | tags: 43 | - vault 44 | 45 | - name: Set vault consul service definition 46 | sudo: yes 47 | template: 48 | src: vault-consul.j2 49 | dest: "{{ vault_consul_dir }}/vault.json" 50 | notify: 51 | - restart consul 52 | -------------------------------------------------------------------------------- /roles/vault/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for vault 3 | - include: install.yml 4 | - include: bootstrap.yml 5 | -------------------------------------------------------------------------------- /roles/vault/templates/config.hcl.j2: -------------------------------------------------------------------------------- 1 | backend "consul" { 2 | address = "127.0.0.1:8500" 3 | path = "vault" 4 | scheme = "http" 5 | advertise_addr = "http://{{ vault_advertise_addr }}:{{ vault_port }}" 6 | } 7 | 8 | listener "tcp" { 9 | address = "0.0.0.0:{{ vault_port }}" 10 | tls_disable = 1 11 | } 12 | -------------------------------------------------------------------------------- /roles/vault/templates/default.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VAULT_CONFIG_FILE=${VAULT_CONFIG_FILE:-/etc/vault/config.hcl} 3 | VAULT_UNSEAL_FILE=${VAULT_UNSEAL_FILE:-/etc/vault/unseal} 4 | -------------------------------------------------------------------------------- /roles/vault/templates/unseal.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export VAULT_ADDR="http://127.0.0.1:{{ vault_port }}" 3 | {% for key in vault_keys %} 4 | vault unseal {{ key }} 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /roles/vault/templates/vault-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "vault", 4 | "tags": [ "vault" ], 5 | "port": {{ vault_port }}, 6 | "check": { 7 | "http": "{{ vault_addr }}/v1/sys/health", 8 | "interval": "10s", 9 | "timeout": "3s" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /roles/vault/templates/vault-security.yaml.j2: -------------------------------------------------------------------------------- 1 | {{ vault_init_output.stdout|from_json|to_nice_yaml }} 2 | -------------------------------------------------------------------------------- /roles/vault/templates/vault.conf.j2: -------------------------------------------------------------------------------- 1 | description "Vault server" 2 | 3 | start on runlevel [2345] 4 | stop on runlevel [!2345] 5 | 6 | script 7 | . /etc/default/vault 8 | exec /usr/bin/vault server -config="${VAULT_CONFIG_FILE}" 9 | end script 10 | 11 | post-start script 12 | . /etc/default/vault 13 | while ! nc -w 1 127.0.0.1 "{{ vault_port }}" 14 | do 15 | sleep 1 16 | done 17 | exec ${VAULT_UNSEAL_FILE} 18 | end script 19 | 20 | respawn 21 | respawn limit 10 10 22 | kill timeout 10 23 | -------------------------------------------------------------------------------- /roles/vault/templates/wait-for-vault-leader.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export VAULT_ADDR="{{ vault_addr }}" 4 | while ! vault status {{ vault_addr }} | grep 'Leader: http://.*:{{ vault_port }}' 5 | do 6 | sleep 1 7 | done -------------------------------------------------------------------------------- /roles/vault/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for marathon 3 | -------------------------------------------------------------------------------- /roles/weave/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for weave 3 | weave_server_group: weave_servers 4 | weave_launch_peers: "{% for host in groups[weave_server_group] %}{% if host != inventory_hostname %}{{ hostvars[host].ansible_default_ipv4.address }} {% endif %}{% endfor %}" 5 | weave_version: 1.4.6 6 | weave_url: "https://github.com/weaveworks/weave/releases/download/v{{ weave_version }}/weave" 7 | weave_bin: /mnt/weave 8 | 9 | # scope 10 | scope_url: https://github.com/weaveworks/scope/releases/download/latest_release/scope 11 | scope_bin: /mnt/scope 12 | -------------------------------------------------------------------------------- /roles/weave/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for weave 3 | - name: restart weave 4 | become: yes 5 | service: 6 | name: weave 7 | state: restarted 8 | notify: 9 | - wait for weave socket 10 | 11 | - name: restart weaveproxy 12 | become: yes 13 | service: 14 | name: weaveproxy 15 | state: restarted 16 | 17 | - name: wait for weave socket 18 | wait_for: 19 | port: 6783 20 | delay: 10 21 | -------------------------------------------------------------------------------- /roles/weave/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: download weave 3 | become: yes 4 | become_user: root 5 | get_url: 6 | url: "{{ weave_url }}" 7 | dest: "{{ weave_bin }}" 8 | mode: 0755 9 | validate_certs: no 10 | force: true 11 | environment: "{{ proxy_env }}" 12 | tags: 13 | - weave 14 | 15 | - name: deploy weave service 16 | become: yes 17 | become_user: root 18 | template: 19 | src: "{{ item.src }}" 20 | dest: "{{ item.dest }}" 21 | with_items: 22 | - src: weave.service.j2 23 | dest: /etc/systemd/system/weave.service 24 | - src: weaveproxy.service.j2 25 | dest: /etc/systemd/system/weaveproxy.service 26 | notify: 27 | - reload systemd 28 | - restart weave 29 | - restart weaveproxy 30 | tags: 31 | - weave 32 | 33 | - name: ensure weave service is running. 34 | become: yes 35 | service: 36 | name: weave 37 | state: started 38 | enabled: yes 39 | tags: 40 | - weave 41 | 42 | - name: ensure weaveproxy service is running. 43 | become: yes 44 | service: 45 | name: weaveproxy 46 | state: started 47 | enabled: yes 48 | tags: 49 | - weave 50 | 51 | - name: wait for weave socket to be ready. 52 | wait_for: 53 | port: 6783 54 | delay: 10 55 | 56 | # Flush handlers so we restart the Docker process here with the weave network 57 | # enabled and containers correctly start in the weave network. 58 | - meta: flush_handlers 59 | 60 | # scope 61 | - include: scope.yml 62 | when: scope_enabled|bool 63 | -------------------------------------------------------------------------------- /roles/weave/tasks/scope.yml: -------------------------------------------------------------------------------- 1 | - name: download scope 2 | become: yes 3 | become_user: root 4 | get_url: 5 | url: "{{ scope_url }}" 6 | dest: "{{ scope_bin }}" 7 | mode: 0755 8 | validate_certs: no 9 | force: true 10 | environment: "{{ proxy_env }}" 11 | tags: 12 | - scope 13 | 14 | - name: deploy scope service 15 | become: yes 16 | become_user: root 17 | template: 18 | src: scope.service.j2 19 | dest: /etc/systemd/system/scope.service 20 | tags: 21 | - scope 22 | 23 | - name: ensure scope service is running. 24 | become: yes 25 | service: 26 | name: scope 27 | state: started 28 | enabled: yes 29 | tags: 30 | - scope 31 | -------------------------------------------------------------------------------- /roles/weave/templates/scope.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | After=docker.service 3 | Description=Weave Network Router 4 | Documentation=http://docs.weave.works/ 5 | Requires=docker.service 6 | 7 | [Service] 8 | TimeoutStartSec=0 9 | Restart=on-failure 10 | ExecStart={{ scope_bin }} launch {{ weave_launch_peers }} 11 | 12 | ExecStop={{ scope_bin }} stop 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /roles/weave/templates/weave.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | After=docker.service 3 | Description=Weave Network Router 4 | Documentation=http://docs.weave.works/ 5 | Requires=docker.service 6 | 7 | [Service] 8 | TimeoutStartSec=0 9 | EnvironmentFile=-/etc/weave.%H.env 10 | EnvironmentFile=-/etc/weave.env 11 | Environment=WEAVE_VERSION={{ weave_version }} 12 | 13 | ExecStartPre={{ weave_bin }} launch-router --no-dns {{ weave_launch_peers }} 14 | ExecStart=/usr/bin/docker attach weave 15 | ExecStartPost={{ weave_bin }} expose 16 | Restart=on-failure 17 | 18 | ExecStop={{ weave_bin }} stop-router 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /roles/weave/templates/weaveproxy.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | After=docker.service 3 | Description=Weave proxy for Docker API 4 | Documentation=http://docs.weave.works/ 5 | Requires=docker.service 6 | Requires=weave.service 7 | 8 | [Service] 9 | EnvironmentFile=-/etc/weave.%H.env 10 | EnvironmentFile=-/etc/weave.env 11 | Environment=WEAVE_VERSION={{ weave_version }} 12 | 13 | ExecStartPre={{ weave_bin }} launch-proxy --rewrite-inspect --without-dns 14 | ExecStart=/usr/bin/docker attach weaveproxy 15 | Restart=on-failure 16 | ExecStop={{ weave_bin }} stop-proxy 17 | 18 | [Install] 19 | WantedBy=multi-user.target 20 | -------------------------------------------------------------------------------- /roles/weave/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for weave 3 | -------------------------------------------------------------------------------- /roles/zookeeper/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | consul_dir: /etc/consul.d 3 | zookeeper_config_dir: /etc/zookeeper/conf 4 | zookeeper_image: "mesosphere/mesos:0.28.0-2.0.16.ubuntu1404" 5 | zookeeper_client_port: 2181 6 | zookeeper_leader_connect_port: 2888 7 | zookeeper_leader_election_port: 3888 8 | zookeeper_server_group: zookeeper_servers 9 | zookeeper_id: " 10 | {%- if zookeeper_host_list is defined -%} 11 | {%- for host in zookeeper_host_list.split() -%} 12 | {%- if host == ansible_eth0.ipv4.address -%} 13 | {{ loop.index }} 14 | {%- endif -%} 15 | {%- endfor -%} 16 | {%- else -%} 17 | {%- for host in groups[zookeeper_server_group] -%} 18 | {%- if host == 'default' or host == inventory_hostname or host == ansible_fqdn or host in ansible_all_ipv4_addresses -%} 19 | {{ loop.index }} 20 | {%- endif -%} 21 | {%- endfor -%} 22 | {%- endif -%} 23 | " 24 | -------------------------------------------------------------------------------- /roles/zookeeper/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for zookeeper 3 | - name: restart zookeeper 4 | service: 5 | name: zookeeper 6 | state: restarted 7 | become: yes 8 | 9 | - name: start zookeeper 10 | service: 11 | name: zookeeper 12 | state: started 13 | become: yes 14 | -------------------------------------------------------------------------------- /roles/zookeeper/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: create zookeeper config directory 2 | file: 3 | path: "{{ zookeeper_config_dir }}" 4 | state: directory 5 | follow: yes 6 | mode: 0755 7 | become: yes 8 | tags: 9 | - zookeeper 10 | 11 | - name: Create zookeeper config files 12 | template: 13 | src: "{{ item.src }}" 14 | dest: "{{ item.dest }}" 15 | become: yes 16 | with_items: 17 | - src: zoo.cfg.j2 18 | dest: "{{ zookeeper_config_dir }}/zoo.cfg" 19 | - src: environment.j2 20 | dest: "{{ zookeeper_config_dir }}/environment" 21 | - src: configuration.xsl.j2 22 | dest: "{{ zookeeper_config_dir }}/configuration.xsl" 23 | - src: log4j.properties.j2 24 | dest: "{{ zookeeper_config_dir }}/log4j.properties" 25 | notify: 26 | - reload systemd 27 | - restart zookeeper 28 | tags: 29 | - zookeeper 30 | 31 | - name: Create zookeeper myid file 32 | copy: 33 | content: "{{ zookeeper_id }}" 34 | dest: "{{ zookeeper_config_dir }}/myid" 35 | mode: 0644 36 | become: yes 37 | notify: 38 | - restart zookeeper 39 | tags: 40 | - zookeeper 41 | 42 | - name: deploy zookeeper service 43 | become: yes 44 | become_user: root 45 | template: 46 | src: zookeeper.service.j2 47 | dest: /etc/systemd/system/zookeeper.service 48 | notify: 49 | - reload systemd 50 | - restart zookeeper 51 | tags: 52 | - zookeeper 53 | 54 | - name: enable zookeeper 55 | become: yes 56 | service: 57 | name: zookeeper 58 | enabled: yes 59 | state: started 60 | tags: 61 | - zookeeper 62 | 63 | - name: set zookeeper consul service definition 64 | become: yes 65 | template: 66 | src: zookeeper-consul.j2 67 | dest: "{{ consul_dir }}/zookeeper.json" 68 | notify: 69 | - restart consul 70 | tags: 71 | - zookeeper 72 | -------------------------------------------------------------------------------- /roles/zookeeper/templates/configuration.xsl.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
namevaluedescription
21 | 22 | 23 |
24 |
25 | -------------------------------------------------------------------------------- /roles/zookeeper/templates/environment.j2: -------------------------------------------------------------------------------- 1 | NAME=zookeeper 2 | ZOOCFGDIR=/etc/$NAME/conf 3 | 4 | # TODO this is really ugly 5 | # How to find out, which jars are needed? 6 | # seems, that log4j requires the log4j.properties file to be in the classpath 7 | CLASSPATH="$ZOOCFGDIR:/usr/share/java/jline.jar:/usr/share/java/log4j-1.2.jar:/usr/share/java/xercesImpl.jar:/usr/share/java/xmlParserAPIs.jar:/usr/share/java/netty.jar:/usr/share/java/slf4j-api.jar:/usr/share/java/slf4j-log4j12.jar:/usr/share/java/zookeeper.jar" 8 | 9 | ZOOCFG="$ZOOCFGDIR/zoo.cfg" 10 | ZOO_LOG_DIR=/var/log/$NAME 11 | USER=$NAME 12 | GROUP=$NAME 13 | PIDDIR=/var/run/$NAME 14 | PIDFILE=$PIDDIR/$NAME.pid 15 | SCRIPTNAME=/etc/init.d/$NAME 16 | JAVA=/usr/bin/java 17 | ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain" 18 | ZOO_LOG4J_PROP="INFO,ROLLINGFILE" 19 | JMXLOCALONLY=false 20 | JAVA_OPTS="" -------------------------------------------------------------------------------- /roles/zookeeper/templates/log4j.properties.j2: -------------------------------------------------------------------------------- 1 | # 2 | # ZooKeeper Logging Configuration 3 | # 4 | 5 | # Format is " (, )+ 6 | 7 | log4j.rootLogger=${zookeeper.root.logger} 8 | 9 | # Example: console appender only 10 | # log4j.rootLogger=INFO, CONSOLE 11 | 12 | # Example with rolling log file 13 | #log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE 14 | 15 | # Example with rolling log file and tracing 16 | #log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE 17 | 18 | # 19 | # Log INFO level and above messages to the console 20 | # 21 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 22 | log4j.appender.CONSOLE.Threshold=INFO 23 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 24 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n 25 | 26 | # 27 | # Add ROLLINGFILE to rootLogger to get log file output 28 | # Log DEBUG level and above messages to a log file 29 | log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender 30 | log4j.appender.ROLLINGFILE.Threshold=DEBUG 31 | log4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/zookeeper.log 32 | 33 | # Max log file size of 10MB 34 | log4j.appender.ROLLINGFILE.MaxFileSize=10MB 35 | # uncomment the next line to limit number of backup files 36 | #log4j.appender.ROLLINGFILE.MaxBackupIndex=10 37 | 38 | log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout 39 | log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n 40 | 41 | 42 | # 43 | # Add TRACEFILE to rootLogger to get log file output 44 | # Log DEBUG level and above messages to a log file 45 | log4j.appender.TRACEFILE=org.apache.log4j.FileAppender 46 | log4j.appender.TRACEFILE.Threshold=TRACE 47 | log4j.appender.TRACEFILE.File=${zookeeper.log.dir}/zookeeper_trace.log 48 | 49 | log4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout 50 | ### Notice we are including log4j's NDC here (%x) 51 | log4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L][%x] - %m%n -------------------------------------------------------------------------------- /roles/zookeeper/templates/zoo.cfg.j2: -------------------------------------------------------------------------------- 1 | tickTime=2000 2 | dataDir=/var/lib/zookeeper/ 3 | clientPort={{ zookeeper_client_port }} 4 | initLimit=5 5 | syncLimit=2 6 | {% if zookeeper_conf is defined %} 7 | {% for host in zookeeper_conf.split() %} 8 | {{ host }} 9 | {% endfor %} 10 | {% else %} 11 | {% for host in groups[zookeeper_server_group] %} 12 | server.{{ loop.index }}={{ hostvars[host]['ansible_host'] }}:{{ zookeeper_leader_connect_port }}:{{ zookeeper_leader_election_port }} 13 | {% endfor %} 14 | {% endif %} 15 | -------------------------------------------------------------------------------- /roles/zookeeper/templates/zookeeper-consul.j2: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "name": "zookeeper", 4 | "port": {{ zookeeper_client_port }}, 5 | "tags": [ "zookeeper" ], 6 | "check": { 7 | "docker_container_id": "zookeeper", 8 | "shell": "/bin/bash", 9 | "script": "echo ruok | nc 127.0.0.1 {{ zookeeper_client_port }} | grep imok", 10 | "interval": "10s", 11 | "timeout": "3s" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /roles/zookeeper/templates/zookeeper.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Zookeeper 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | Restart=on-failure 8 | RestartSec=20 9 | TimeoutStartSec=0 10 | ExecStartPre=-/usr/bin/docker kill zookeeper 11 | ExecStartPre=-/usr/bin/docker rm zookeeper 12 | ExecStartPre=/usr/bin/docker pull {{ zookeeper_image }} 13 | ExecStart=/usr/bin/docker run --rm --net=host --name=zookeeper \ 14 | -v {{ zookeeper_config_dir }}/:{{ zookeeper_config_dir }}/ \ 15 | -p {{ zookeeper_client_port }}:{{ zookeeper_client_port }} \ 16 | -p {{ zookeeper_leader_connect_port }}:{{ zookeeper_leader_connect_port }} \ 17 | -p {{ zookeeper_leader_election_port }}:{{ zookeeper_leader_election_port }} \ 18 | {{ zookeeper_image }} \ 19 | /usr/share/zookeeper/bin/zkServer.sh start-foreground 20 | 21 | ExecStop=/usr/bin/docker stop zookeeper 22 | 23 | [Install] 24 | WantedBy=multi-user.target 25 | -------------------------------------------------------------------------------- /roles/zookeeper/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for zookeeper 3 | zookeeper_leader_port: "2888" 4 | zookeeper_election_port: "3888" 5 | -------------------------------------------------------------------------------- /rolling-upgrade-maintenance.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all:!role=bastion 3 | gather_facts: True 4 | tasks: 5 | - name: Wait for ssh port to become available from bastion server. 6 | wait_for: 7 | port: "{{ ansible_port }}" 8 | host: "{{ ansible_host }}" 9 | delay: 10 10 | timeout: 90 11 | delegate_to: "{{ bastion_ip }}" 12 | become: False 13 | when: bastion_ip is defined 14 | tags: ["facts"] 15 | 16 | - name: Wait for port 22 to become available from local server. 17 | local_action: "wait_for port={{ ansible_port }} host={{ ansible_host }} delay=10 timeout=90" 18 | become: False 19 | when: bastion_ip is not defined 20 | tags: ["facts"] 21 | 22 | - hosts: mesos_masters 23 | serial: "{{ serial | default(1) }}" 24 | roles: 25 | - { role: zookeeper, tags: ["zookeeper"] } 26 | - { role: docker, tags: ["docker"] } 27 | - { role: weave, tags: ["weave"], meta: "flush_handlers" } 28 | - { role: consul, tags: ["consul"] } 29 | - { role: mesos_consul, tags: ["mesos_consul"] } 30 | 31 | - hosts: mesos_agents 32 | serial: "{{ serial | default(1) }}" 33 | 34 | roles: 35 | - { role: mesos_maintenance, tags: ["mesos_maintenance"], mesos_maintenance_start: true } 36 | - { role: docker, tags: ["docker"] } 37 | - { role: weave, tags: ["weave"] } 38 | - { role: consul, tags: ["consul"] } 39 | - { role: mesos_consul, tags: ["mesos_consul"] } 40 | - { role: traefik, tags: ["traefik"] } 41 | - { role: mesos_maintenance, tags: ["mesos_maintenance"], mesos_maintenance_complete: true } 42 | -------------------------------------------------------------------------------- /rolling-upgrade-mesoscluster.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all:!role=bastion 3 | gather_facts: True 4 | tasks: 5 | - name: Wait for ssh port to become available from bastion server. 6 | wait_for: 7 | port: "{{ ansible_port }}" 8 | host: "{{ ansible_host }}" 9 | delay: 10 10 | timeout: 90 11 | delegate_to: "{{ bastion_ip }}" 12 | become: False 13 | when: bastion_ip is defined 14 | tags: ["facts"] 15 | 16 | - name: Wait for port 22 to become available from local server. 17 | local_action: "wait_for port={{ ansible_port }} host={{ ansible_host }} delay=10 timeout=90" 18 | become: False 19 | when: bastion_ip is not defined 20 | tags: ["facts"] 21 | 22 | - hosts: mesos_masters 23 | serial: "{{ serial | default(1) }}" 24 | roles: 25 | - { role: mesos, mesos_install_mode: "master" } 26 | - { role: marathon, when: marathon_enabled|bool } 27 | 28 | - hosts: mesos_agents 29 | serial: "{{ serial | default(1) }}" 30 | roles: 31 | - { role: mesos, mesos_install_mode: "agent" } 32 | -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all:!role=bastion 3 | gather_facts: false 4 | vars: 5 | ansible_python_interpreter: "PATH=/home/core/bin:$PATH python" 6 | tasks: 7 | - name: Wait for ssh port to become available from bastion server. 8 | wait_for: 9 | port: "{{ ansible_port }}" 10 | host: "{{ ansible_host }}" 11 | delay: 10 12 | timeout: 180 13 | delegate_to: "{{ bastion_ip }}" 14 | become: false 15 | when: bastion_ip is defined 16 | - name: Wait for port 22 to become available from local server. 17 | local_action: "wait_for port={{ ansible_port }} host={{ ansible_host }} delay=10 timeout=180" 18 | become: false 19 | when: bastion_ip is not defined 20 | 21 | 22 | - include: playbooks/coreos-bootstrap.yml 23 | 24 | - hosts: all:!role=bastion 25 | roles: 26 | - docker 27 | - weave 28 | - consul 29 | # @todo - fix vault integration with coreOS 30 | #- vault 31 | 32 | - hosts: all:!role=bastion 33 | roles: 34 | - { role: cadvisor, when: cadvisor_enabled|bool } 35 | - { role: prometheus, when: prometheus_enabled|bool } 36 | environment: 37 | DOCKER_HOST: "{{ docker_host }}" 38 | 39 | - hosts: mesos_masters 40 | roles: 41 | - zookeeper 42 | - { role: mesos, mesos_install_mode: "master" } 43 | - mesos_consul 44 | - { role: marathon, when: marathon_enabled|bool } 45 | environment: 46 | DOCKER_HOST: "{{ docker_host }}" 47 | 48 | - hosts: mesos_agents 49 | roles: 50 | - { role: mesos, mesos_install_mode: "agent" } 51 | environment: 52 | DOCKER_HOST: "{{ docker_host }}" 53 | 54 | - hosts: load_balancers 55 | roles: 56 | - { role: traefik, tags: ["traefik"] } 57 | environment: 58 | DOCKER_HOST: "{{ docker_host }}" 59 | 60 | # Installing DCOS frameworks and apps from one master. 61 | - include: dcos.yml 62 | 63 | - hosts: log_servers 64 | roles: 65 | - { role: logstash, when: elk_enabled|bool } 66 | environment: 67 | DOCKER_HOST: "{{ docker_host }}" 68 | 69 | - include: contrib-plugins/playbook.yml 70 | -------------------------------------------------------------------------------- /terraform/aws/keypair/main.tf: -------------------------------------------------------------------------------- 1 | # input variables 2 | variable "short_name" { default = "apollo" } 3 | variable "public_key_filename" { default = "~/.ssh/id_rsa_aws.pub" } 4 | 5 | # SSH keypair for the instances 6 | resource "aws_key_pair" "default" { 7 | key_name = "${var.short_name}" 8 | public_key = "${file(var.public_key_filename)}" 9 | } 10 | 11 | # output variables 12 | output "keypair_name" { 13 | value = "${aws_key_pair.default.key_name}" 14 | } 15 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/.gitignore: -------------------------------------------------------------------------------- 1 | etcd_discovery_url.txt 2 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/agent-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | units: 5 | - name: format-ebs-volume.service 6 | command: start 7 | content: | 8 | [Unit] 9 | Description=Formats the ebs volume if needed 10 | Before=docker.service 11 | [Service] 12 | Type=oneshot 13 | RemainAfterExit=yes 14 | ExecStart=/bin/bash -c '(/usr/sbin/blkid -t TYPE=ext4 | grep /dev/xvdb) || (/usr/sbin/wipefs -fa /dev/xvdb && /usr/sbin/mkfs.ext4 /dev/xvdb)' 15 | - name: var-lib-docker.mount 16 | command: start 17 | content: | 18 | [Unit] 19 | Description=Mount ephemeral to /var/lib/docker 20 | Requires=format-ebs-volume.service 21 | After=format-ebs-volume.service 22 | [Mount] 23 | What=/dev/xvdb 24 | Where=/var/lib/docker 25 | Type=ext4 26 | - name: docker.service 27 | drop-ins: 28 | - name: 10-wait-docker.conf 29 | content: | 30 | [Unit] 31 | After=var-lib-docker.mount 32 | Requires=var-lib-docker.mount 33 | etcd2: 34 | proxy: on 35 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 36 | discovery: ${etcd_discovery_url} 37 | fleet: 38 | metadata: "role=agent,region=${region}" 39 | public-ip: "$public_ipv4" 40 | etcd_servers: "http://localhost:2379" 41 | locksmith: 42 | endpoint: "http://localhost:2379" 43 | units: 44 | - name: etcd2.service 45 | command: start 46 | update: 47 | reboot-strategy: best-effort 48 | manage_etc_hosts: localhost 49 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/bastion-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | etcd2: 5 | proxy: on 6 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 7 | discovery: ${etcd_discovery_url} 8 | fleet: 9 | metadata: "role=bastion,region=${region}" 10 | etcd_servers: "http://localhost:2379" 11 | locksmith: 12 | endpoint: "http://localhost:2379" 13 | units: 14 | - name: docker.service 15 | command: start 16 | - name: etcd2.service 17 | command: start 18 | update: 19 | reboot-strategy: best-effort 20 | manage_etc_hosts: localhost 21 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/bin/ovpn-client-config: -------------------------------------------------------------------------------- 1 | ssh -t "core@$(terraform output bastion.ip)" sudo docker run --volumes-from ovpn-data --rm gosuri/openvpn ovpn_getclient "${1}" > "${1}-apollo.ovpn" 2 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/bin/ovpn-init: -------------------------------------------------------------------------------- 1 | ssh -t "core@$(terraform output bastion.ip)" sudo docker run --volumes-from ovpn-data --rm -it gosuri/openvpn ovpn_initpki 2 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/bin/ovpn-new-client: -------------------------------------------------------------------------------- 1 | ssh -t "core@$(terraform output bastion.ip)" sudo docker run --volumes-from ovpn-data --rm -it gosuri/openvpn easyrsa build-client-full "${1}" nopass 2 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/bin/ovpn-start: -------------------------------------------------------------------------------- 1 | ssh -t "core@$(terraform output bastion.ip)" sudo docker run --volumes-from ovpn-data -d -p 1194:1194/udp --cap-add=NET_ADMIN gosuri/openvpn 2 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/etcd_discovery_url.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Capgemini/Apollo/21f949d8cec5a07a97202cfcb67a0dbf8c90090b/terraform/aws/private-cloud/etcd_discovery_url.txt -------------------------------------------------------------------------------- /terraform/aws/private-cloud/master-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | etcd2: 5 | # $private_ipv4 is populated by the cloud provider 6 | # we don't have a $public_ipv4 in the private VPC 7 | advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001 8 | initial-advertise-peer-urls: http://$private_ipv4:2380 9 | # listen on both the official ports and the legacy ports 10 | # legacy ports can be omitted if your application doesn't depend on them 11 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 12 | listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001 13 | # Discovery is populated by Terraform 14 | discovery: ${etcd_discovery_url} 15 | fleet: 16 | metadata: "role=master,region=${region}" 17 | units: 18 | - name: etcd2.service 19 | command: start 20 | update: 21 | reboot-strategy: best-effort 22 | manage_etc_hosts: localhost 23 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/mesos-masters.tf: -------------------------------------------------------------------------------- 1 | module "master_amitype" { 2 | source = "github.com/terraform-community-modules/tf_aws_virttype" 3 | instance_type = "${var.master_instance_type}" 4 | } 5 | 6 | module "master_ami" { 7 | source = "github.com/terraform-community-modules/tf_aws_coreos_ami" 8 | region = "${var.region}" 9 | channel = "${var.coreos_channel}" 10 | virttype = "${module.master_amitype.prefer_hvm}" 11 | } 12 | 13 | resource "template_file" "master_cloud_init" { 14 | template = "master-cloud-config.yml.tpl" 15 | depends_on = ["template_file.etcd_discovery_url"] 16 | vars { 17 | etcd_discovery_url = "${file(var.etcd_discovery_url_file)}" 18 | size = "${var.masters}" 19 | region = "${var.region}" 20 | } 21 | } 22 | 23 | resource "aws_instance" "mesos-master" { 24 | instance_type = "${var.master_instance_type}" 25 | ami = "${module.master_ami.ami_id}" 26 | count = "${var.masters}" 27 | key_name = "${module.aws-keypair.keypair_name}" 28 | source_dest_check = false 29 | subnet_id = "${element(split(",", module.vpc.private_subnets), count.index)}" 30 | security_groups = ["${module.sg-default.security_group_id}"] 31 | depends_on = ["aws_instance.bastion"] 32 | user_data = "${template_file.master_cloud_init.rendered}" 33 | tags = { 34 | Name = "apollo-mesos-master-${count.index}" 35 | role = "mesos_masters" 36 | } 37 | connection { 38 | user = "core" 39 | private_key = "${var.private_key_file}" 40 | bastion_host = "${aws_eip.bastion.public_ip}" 41 | bastion_private_key = "${var.private_key_file}" 42 | } 43 | 44 | # Do some early bootstrapping of the CoreOS machines. This will install 45 | # python and pip so we can use as the ansible_python_interpreter in our playbooks 46 | provisioner "file" { 47 | source = "../../scripts/coreos" 48 | destination = "/tmp" 49 | } 50 | provisioner "remote-exec" { 51 | inline = [ 52 | "sudo chmod -R +x /tmp/coreos", 53 | "/tmp/coreos/bootstrap.sh", 54 | "~/bin/python /tmp/coreos/get-pip.py", 55 | "sudo mv /tmp/coreos/runner ~/bin/pip && sudo chmod 0755 ~/bin/pip", 56 | "sudo rm -rf /tmp/coreos" 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /terraform/aws/private-cloud/security_groups.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "bastion" { 2 | name = "bastion-apollo" 3 | description = "Security group for bastion instances that allows SSH and VPN traffic from internet" 4 | vpc_id = "${module.vpc.vpc_id}" 5 | 6 | # inbound http/https traffic from the private subnets to allow them to talk with the internet 7 | ingress { 8 | from_port = 80 9 | to_port = 80 10 | protocol = "tcp" 11 | cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] 12 | } 13 | 14 | ingress { 15 | from_port = 443 16 | to_port = 443 17 | protocol = "tcp" 18 | cidr_blocks = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] 19 | } 20 | 21 | # ssh 22 | ingress { 23 | from_port = 22 24 | to_port = 22 25 | protocol = "tcp" 26 | cidr_blocks = ["0.0.0.0/0"] 27 | } 28 | 29 | # openvpn 30 | ingress { 31 | from_port = 1194 32 | to_port = 1194 33 | protocol = "udp" 34 | cidr_blocks = ["0.0.0.0/0"] 35 | } 36 | 37 | # outbound access to the inernet 38 | egress { 39 | from_port = 80 40 | to_port = 80 41 | protocol = "tcp" 42 | cidr_blocks = ["0.0.0.0/0"] 43 | } 44 | 45 | egress { 46 | from_port = 443 47 | to_port = 443 48 | protocol = "tcp" 49 | cidr_blocks = ["0.0.0.0/0"] 50 | } 51 | 52 | tags { 53 | Name = "bastion-apollo-sg" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /terraform/aws/public-cloud/agent-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | units: 5 | - name: format-ebs-volume.service 6 | command: start 7 | content: | 8 | [Unit] 9 | Description=Formats the ebs volume if needed 10 | Before=docker.service 11 | [Service] 12 | Type=oneshot 13 | RemainAfterExit=yes 14 | ExecStart=/bin/bash -c '(/usr/sbin/blkid -t TYPE=ext4 | grep /dev/xvdb) || (/usr/sbin/wipefs -fa /dev/xvdb && /usr/sbin/mkfs.ext4 /dev/xvdb)' 15 | - name: var-lib-docker.mount 16 | command: start 17 | content: | 18 | [Unit] 19 | Description=Mount ephemeral to /var/lib/docker 20 | Requires=format-ebs-volume.service 21 | After=format-ebs-volume.service 22 | [Mount] 23 | What=/dev/xvdb 24 | Where=/var/lib/docker 25 | Type=ext4 26 | - name: docker.service 27 | drop-ins: 28 | - name: 10-wait-docker.conf 29 | content: | 30 | [Unit] 31 | After=var-lib-docker.mount 32 | Requires=var-lib-docker.mount 33 | etcd2: 34 | proxy: on 35 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 36 | discovery: ${etcd_discovery_url} 37 | fleet: 38 | metadata: "role=agent,region=${region}" 39 | public-ip: "$public_ipv4" 40 | etcd_servers: "http://localhost:2379" 41 | locksmith: 42 | endpoint: "http://localhost:2379" 43 | units: 44 | - name: etcd2.service 45 | command: start 46 | update: 47 | reboot-strategy: best-effort 48 | manage_etc_hosts: localhost 49 | -------------------------------------------------------------------------------- /terraform/aws/public-cloud/etcd_discovery_url.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Capgemini/Apollo/21f949d8cec5a07a97202cfcb67a0dbf8c90090b/terraform/aws/public-cloud/etcd_discovery_url.txt -------------------------------------------------------------------------------- /terraform/aws/public-cloud/master-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | etcd2: 5 | # $public_ipv4 and $private_ipv4 are populated by the cloud provider 6 | advertise-client-urls: http://$public_ipv4:2379 7 | initial-advertise-peer-urls: http://$private_ipv4:2380 8 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 9 | listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001 10 | discovery: ${etcd_discovery_url} 11 | fleet: 12 | metadata: "role=master,region=${region}" 13 | public-ip: "$public_ipv4" 14 | units: 15 | - name: etcd2.service 16 | command: start 17 | update: 18 | reboot-strategy: best-effort 19 | manage_etc_hosts: localhost 20 | -------------------------------------------------------------------------------- /terraform/aws/public-cloud/mesos-agents.tf: -------------------------------------------------------------------------------- 1 | module "agent_amitype" { 2 | source = "github.com/terraform-community-modules/tf_aws_virttype" 3 | instance_type = "${var.agent_instance_type}" 4 | } 5 | 6 | module "agent_ami" { 7 | source = "github.com/terraform-community-modules/tf_aws_coreos_ami" 8 | region = "${var.region}" 9 | channel = "${var.coreos_channel}" 10 | virttype = "${module.agent_amitype.prefer_hvm}" 11 | } 12 | 13 | resource "template_file" "agent_cloud_init" { 14 | template = "${file("agent-cloud-config.yml.tpl")}" 15 | depends_on = ["template_file.etcd_discovery_url"] 16 | vars { 17 | etcd_discovery_url = "${file(var.etcd_discovery_url_file)}" 18 | size = "${var.masters}" 19 | region = "${var.region}" 20 | } 21 | } 22 | 23 | resource "aws_instance" "mesos-agent" { 24 | instance_type = "${var.agent_instance_type}" 25 | ami = "${module.agent_ami.ami_id}" 26 | count = "${var.agents}" 27 | key_name = "${module.aws-keypair.keypair_name}" 28 | subnet_id = "${element(split(",", module.public_subnet.subnet_ids), count.index)}" 29 | source_dest_check = false 30 | security_groups = ["${module.sg-default.security_group_id}"] 31 | depends_on = ["aws_instance.mesos-master"] 32 | user_data = "${template_file.agent_cloud_init.rendered}" 33 | tags = { 34 | Name = "apollo-mesos-agent-${count.index}" 35 | role = "mesos_agents" 36 | } 37 | ebs_block_device { 38 | device_name = "/dev/xvdb" 39 | volume_size = "${var.agent_ebs_volume_size}" 40 | delete_on_termination = true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /terraform/aws/public-cloud/mesos-masters.tf: -------------------------------------------------------------------------------- 1 | module "master_amitype" { 2 | source = "github.com/terraform-community-modules/tf_aws_virttype" 3 | instance_type = "${var.master_instance_type}" 4 | } 5 | 6 | module "master_ami" { 7 | source = "github.com/terraform-community-modules/tf_aws_coreos_ami" 8 | region = "${var.region}" 9 | channel = "${var.coreos_channel}" 10 | virttype = "${module.master_amitype.prefer_hvm}" 11 | } 12 | 13 | resource "template_file" "master_cloud_init" { 14 | template = "${file("master-cloud-config.yml.tpl")}" 15 | depends_on = ["template_file.etcd_discovery_url"] 16 | vars { 17 | etcd_discovery_url = "${file(var.etcd_discovery_url_file)}" 18 | size = "${var.masters}" 19 | region = "${var.region}" 20 | } 21 | } 22 | 23 | resource "aws_instance" "mesos-master" { 24 | instance_type = "${var.master_instance_type}" 25 | ami = "${module.master_ami.ami_id}" 26 | count = "${var.masters}" 27 | key_name = "${module.aws-keypair.keypair_name}" 28 | subnet_id = "${element(split(",", module.public_subnet.subnet_ids), count.index)}" 29 | source_dest_check = false 30 | security_groups = ["${module.sg-default.security_group_id}"] 31 | user_data = "${template_file.master_cloud_init.rendered}" 32 | tags = { 33 | Name = "apollo-mesos-master-${count.index}" 34 | role = "mesos_masters" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /terraform/aws/sg-all-traffic/main.tf: -------------------------------------------------------------------------------- 1 | variable "security_group_name" { default = "default-apollo-mesos" } 2 | variable "vpc_id" {} 3 | variable "source_cidr_block" { default = "0.0.0.0/0" } 4 | 5 | # Security group that allows all traffic 6 | resource "aws_security_group" "default" { 7 | name = "${var.security_group_name}" 8 | description = "Default security group that allows all traffic" 9 | vpc_id = "${var.vpc_id}" 10 | 11 | # Allows inbound and outbound traffic from all instances in the VPC. 12 | ingress { 13 | from_port = "0" 14 | to_port = "0" 15 | protocol = "-1" 16 | self = true 17 | } 18 | 19 | # Allows all inbound traffic 20 | ingress { 21 | from_port = "0" 22 | to_port = "0" 23 | protocol = "-1" 24 | cidr_blocks = ["${var.source_cidr_block}"] 25 | } 26 | 27 | # Allows all outbound traffic. 28 | egress { 29 | from_port = 0 30 | to_port = 0 31 | protocol = "-1" 32 | cidr_blocks = ["${var.source_cidr_block}"] 33 | } 34 | tags { 35 | Name = "apollo-default-sg" 36 | } 37 | } 38 | 39 | # output variables 40 | output "security_group_id" { 41 | value = "${aws_security_group.default.id}" 42 | } 43 | -------------------------------------------------------------------------------- /terraform/digitalocean/.gitignore: -------------------------------------------------------------------------------- 1 | id_rsa 2 | id_rsa.pub 3 | etcd_discovery_url.txt 4 | -------------------------------------------------------------------------------- /terraform/digitalocean/agent-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | etcd2: 5 | proxy: on 6 | listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 7 | discovery: ${etcd_discovery_url} 8 | fleet: 9 | metadata: "role=agent,region=${region}" 10 | etcd_servers: "http://localhost:2379" 11 | locksmith: 12 | endpoint: "http://localhost:2379" 13 | units: 14 | - name: etcd2.service 15 | command: start 16 | update: 17 | reboot-strategy: best-effort 18 | write_files: 19 | - path: /run/systemd/system/etcd.service.d/30-certificates.conf 20 | permissions: 0644 21 | content: | 22 | [Service] 23 | Environment=ETCD_CA_FILE=/etc/ssl/etcd/certs/ca.pem 24 | Environment=ETCD_CERT_FILE=/etc/ssl/etcd/certs/etcd.pem 25 | Environment=ETCD_KEY_FILE=/etc/ssl/etcd/private/etcd.pem 26 | Environment=ETCD_PEER_CA_FILE=/etc/ssl/etcd/certs/ca.pem 27 | Environment=ETCD_PEER_CERT_FILE=/etc/ssl/etcd/certs/etcd.pem 28 | Environment=ETCD_PEER_KEY_FILE=/etc/ssl/etcd/private/etcd.pem 29 | - path: /etc/ssl/etcd/certs/ca.pem 30 | permissions: 0644 31 | content: "${etcd_ca}" 32 | - path: /etc/ssl/etcd/certs/etcd.pem 33 | permissions: 0644 34 | content: "${etcd_cert}" 35 | - path: /etc/ssl/etcd/private/etcd.pem 36 | permissions: 0644 37 | content: "${etcd_key}" 38 | manage_etc_hosts: localhost 39 | role: mesos_agents 40 | -------------------------------------------------------------------------------- /terraform/digitalocean/etcd_discovery_url.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /terraform/digitalocean/master-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | coreos: 4 | etcd2: 5 | discovery: ${etcd_discovery_url} 6 | advertise-client-urls: http://$public_ipv4:2379 7 | initial-advertise-peer-urls: http://$public_ipv4:2380 8 | listen-client-urls: http://0.0.0.0:2379 9 | listen-peer-urls: http://$public_ipv4:2380 10 | fleet: 11 | metadata: "role=master,region=${region}" 12 | units: 13 | - name: etcd2.service 14 | command: start 15 | update: 16 | reboot-strategy: best-effort 17 | write_files: 18 | - path: /run/systemd/system/etcd.service.d/30-certificates.conf 19 | permissions: 0644 20 | content: | 21 | [Service] 22 | Environment=ETCD_CA_FILE=/etc/ssl/etcd/certs/ca.pem 23 | Environment=ETCD_CERT_FILE=/etc/ssl/etcd/certs/etcd.pem 24 | Environment=ETCD_KEY_FILE=/etc/ssl/etcd/private/etcd.pem 25 | Environment=ETCD_PEER_CA_FILE=/etc/ssl/etcd/certs/ca.pem 26 | Environment=ETCD_PEER_CERT_FILE=/etc/ssl/etcd/certs/etcd.pem 27 | Environment=ETCD_PEER_KEY_FILE=/etc/ssl/etcd/private/etcd.pem 28 | - path: /etc/ssl/etcd/certs/ca.pem 29 | permissions: 0644 30 | content: "${etcd_ca}" 31 | - path: /etc/ssl/etcd/certs/etcd.pem 32 | permissions: 0644 33 | content: "${etcd_cert}" 34 | - path: /etc/ssl/etcd/private/etcd.pem 35 | permissions: 0644 36 | content: "${etcd_key}" 37 | manage_etc_hosts: localhost 38 | role: mesos_masters 39 | -------------------------------------------------------------------------------- /terraform/digitalocean/ssh.config: -------------------------------------------------------------------------------- 1 | Host * 2 | StrictHostKeyChecking no 3 | ServerAliveInterval 120 4 | ControlMaster auto 5 | ControlPath ~/.ssh/mux-%r@%h:%p 6 | ControlPersist 30m 7 | User core 8 | UserKnownHostsFile /dev/null 9 | -------------------------------------------------------------------------------- /terraform/gce/mesos-agent.tf: -------------------------------------------------------------------------------- 1 | /* Base packer build we use for provisioning master instances */ 2 | resource "atlas_artifact" "mesos-agent" { 3 | name = "${var.atlas_artifact.agent}" 4 | type = "googlecompute.image" 5 | version = "${var.atlas_artifact_version.agent}" 6 | } 7 | 8 | resource "google_compute_instance" "mesos-agent" { 9 | count = "${var.agents}" 10 | name = "apollo-mesos-agent-${count.index}" 11 | machine_type = "${var.instance_type.agent}" 12 | zone = "${var.zone}" 13 | tags = ["mesos-agent","http","https","ssh"] 14 | 15 | disk { 16 | image = "${atlas_artifact.mesos-agent.id}" 17 | } 18 | 19 | metadata { 20 | role = "mesos_agents" 21 | } 22 | 23 | network_interface { 24 | network = "default" 25 | access_config { 26 | // Ephemeral IP 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /terraform/gce/mesos-master.tf: -------------------------------------------------------------------------------- 1 | 2 | /* Base packer build we use for provisioning master instances */ 3 | resource "atlas_artifact" "mesos-master" { 4 | name = "${var.atlas_artifact.master}" 5 | type = "googlecompute.image" 6 | version = "${var.atlas_artifact_version.master}" 7 | } 8 | 9 | resource "google_compute_instance" "mesos-master" { 10 | count = "${var.masters}" 11 | name = "apollo-mesos-master-${count.index}" 12 | machine_type = "${var.instance_type.master}" 13 | zone = "${var.zone}" 14 | tags = ["mesos-master"] 15 | 16 | disk { 17 | image = "${atlas_artifact.mesos-master.id}" 18 | } 19 | 20 | # declare metadata for configuration of the node 21 | metadata { 22 | role = "mesos_masters" 23 | } 24 | 25 | network_interface { 26 | network = "default" 27 | access_config { 28 | // Ephemeral IP 29 | } 30 | } 31 | } 32 | 33 | resource "google_compute_firewall" "default" { 34 | name = "default-allow-all" 35 | network = "default" 36 | 37 | allow { 38 | protocol = "icmp" 39 | } 40 | 41 | allow { 42 | protocol = "tcp" 43 | ports = ["1-65535"] 44 | } 45 | 46 | allow { 47 | protocol = "udp" 48 | ports = ["1-65535"] 49 | } 50 | 51 | source_ranges = ["0.0.0.0/0"] 52 | } 53 | -------------------------------------------------------------------------------- /terraform/gce/outputs.tf: -------------------------------------------------------------------------------- 1 | output "master.1.ip" { 2 | value = "${google_compute_instance.mesos-master.0.network_interface.0.access_config.0.nat_ip}" 3 | } 4 | output "master.2.ip" { 5 | value = "${google_compute_instance.mesos-master.1.network_interface.0.access_config.0.nat_ip}" 6 | } 7 | output "master.3.ip" { 8 | value = "${google_compute_instance.mesos-master.2.network_interface.0.access_config.0.nat_ip}" 9 | } 10 | output "master_ips" { 11 | value = "${join(",", google_compute_instance.mesos-master.*.network_interface.0.access_config.0.nat_ip)}" 12 | } 13 | output "agent_ips" { 14 | value = "${join(",", google_compute_instance.mesos-agent.*.network_interface.0.access_config.0.nat_ip)}" 15 | } 16 | -------------------------------------------------------------------------------- /terraform/gce/provider.tf: -------------------------------------------------------------------------------- 1 | provider "google" { 2 | account_file = "${var.account_file}" 3 | project = "${var.project}" 4 | region = "${var.region}" 5 | } -------------------------------------------------------------------------------- /terraform/gce/variables.tf: -------------------------------------------------------------------------------- 1 | variable "account_file" { 2 | description = "The gce account file." 3 | default = "" 4 | } 5 | 6 | variable "project" { 7 | description = "The gce project." 8 | default = "" 9 | } 10 | 11 | variable "region" { 12 | description = "The AWS region to create resources in." 13 | default = "europe-west1" 14 | } 15 | 16 | variable "gce_user" { 17 | description = "The gce ssh user name." 18 | default = "Apollo" 19 | } 20 | 21 | variable "atlas_infrastructure" { 22 | description = "The Atlas infrastructure project to join." 23 | default = "capgemini/infrastructure" 24 | } 25 | 26 | variable "zone" { 27 | description = "Availability zone for Apollo." 28 | default = "europe-west1-b" 29 | } 30 | 31 | variable "agents" { 32 | description = "The number of agents." 33 | default = "1" 34 | } 35 | 36 | variable "masters" { 37 | description = "The number of masters." 38 | default = "3" 39 | } 40 | 41 | variable "instance_type" { 42 | default = { 43 | master = "n1-standard-2" 44 | agent = "n1-standard-2" 45 | } 46 | } 47 | 48 | variable "atlas_artifact" { 49 | default = { 50 | master = "capgemini/apollo-ubuntu-14.04-amd64" 51 | agent = "capgemini/apollo-ubuntu-14.04-amd64" 52 | } 53 | } 54 | 55 | variable "atlas_artifact_version" { 56 | default = { 57 | master = "1" 58 | agent = "1" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /terraform/rackspace/modules/keypair/main.tf: -------------------------------------------------------------------------------- 1 | # Variables 2 | variable "key_name" { default = "apollo" } 3 | variable "public_key_file" { default = "~/.ssh/id_rsa_rs.pub" } 4 | 5 | # SSH keypair resource 6 | resource "openstack_compute_keypair_v2" "default" { 7 | name = "${var.key_name}" 8 | public_key = "${file(var.public_key_file)}" 9 | } 10 | 11 | # Outputs 12 | output "keypair_name" { 13 | value = "${openstack_compute_keypair_v2.default.name}" 14 | } 15 | -------------------------------------------------------------------------------- /terraform/rackspace/modules/mesos_agents/agent-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # Disable login for root user, only allowing the core user to ssh 4 | write_files: 5 | - path: /etc/ssh/sshd_config 6 | permissions: 0600 7 | owner: root:root 8 | content: | 9 | # Use most defaults for sshd configuration. 10 | UsePrivilegeSeparation sandbox 11 | Subsystem sftp internal-sftp 12 | 13 | PermitRootLogin no 14 | AllowUsers core 15 | PasswordAuthentication no 16 | ChallengeResponseAuthentication no 17 | coreos: 18 | units: 19 | - name: format-ebs-volume.service 20 | command: start 21 | content: | 22 | [Unit] 23 | Description=Formats the ebs volume if needed 24 | Before=docker.service 25 | [Service] 26 | Type=oneshot 27 | RemainAfterExit=yes 28 | ExecStart=/bin/bash -c '(/usr/sbin/blkid -t TYPE=ext4 | grep /dev/xvdb) || (/usr/sbin/wipefs -fa /dev/xvdb && /usr/sbin/mkfs.ext4 /dev/xvdb)' 29 | - name: var-lib-docker.mount 30 | command: start 31 | content: | 32 | [Unit] 33 | Description=Mount ephemeral to /var/lib/docker 34 | Requires=format-ebs-volume.service 35 | After=format-ebs-volume.service 36 | [Mount] 37 | What=/dev/xvdb 38 | Where=/var/lib/docker 39 | Type=ext4 40 | - name: docker.service 41 | drop-ins: 42 | - name: 10-wait-docker.conf 43 | content: | 44 | [Unit] 45 | After=var-lib-docker.mount 46 | Requires=var-lib-docker.mount 47 | etcd2: 48 | # $public_ipv4 and v6 are populated by the cloud provider 49 | advertise-client-urls: "http://$public_ipv4:2379" 50 | initial-advertise-peer-urls: "http://$private_ipv4:2380" 51 | # listen on both the official ports and the legacy ports 52 | # legacy ports can be omitted if your application doesn't depend on them 53 | listen-client-urls: "http://0.0.0.0:2379,http://0.0.0.0:4001" 54 | listen-peer-urls: "http://$private_ipv4:2380,http://$private_ipv4:7001" 55 | # Discovery is populated by Terraform 56 | discovery: ${etcd_discovery_url} 57 | units: 58 | - name: etcd2.service 59 | command: start 60 | update: 61 | reboot-strategy: best-effort 62 | manage_etc_hosts: localhost 63 | -------------------------------------------------------------------------------- /terraform/rackspace/modules/mesos_masters/main.tf: -------------------------------------------------------------------------------- 1 | # Variables 2 | 3 | variable "region" { default = "LON" } 4 | variable "instance_type" { default = "general1-4" } 5 | variable "image_id" { default = "40155f16-21d4-4ac1-ad65-c409d94b8c7c" } 6 | variable "key_pair" { default = "apollo" } 7 | variable "public_network_id" { default = "00000000-0000-0000-0000-000000000000" } 8 | variable "public_network_name" { default = "PublicNet" } 9 | variable "private_network_id" { default = "11111111-1111-1111-1111-111111111111" } 10 | variable "private_network_name" { default = "ServiceNet" } 11 | variable "security_groups" { default = "default" } 12 | variable "etcd_discovery_url_file" {} 13 | variable "masters" { default = "3" } 14 | 15 | # Resources 16 | 17 | resource "template_file" "master_cloud_init" { 18 | template = "${path.module}/master-cloud-config.yml.tpl" 19 | vars { 20 | etcd_discovery_url = "${file(var.etcd_discovery_url_file)}" 21 | size = "${var.masters}" 22 | } 23 | } 24 | 25 | resource "openstack_compute_instance_v2" "mesos-master" { 26 | region = "${var.region}" 27 | name = "apollo-mesos-master-${count.index}" 28 | flavor_id = "${var.instance_type}" 29 | image_id = "${var.image_id}" 30 | count = "${var.masters}" 31 | key_pair = "${var.key_pair}" 32 | network = 33 | { 34 | uuid = "${var.public_network_id}" 35 | name = "${var.public_network_name}" 36 | } 37 | network = 38 | { 39 | uuid = "${var.private_network_id}" 40 | name = "${var.private_network_name}" 41 | } 42 | # security_groups = ["${var.security_groups}"] # Comment this in for Openstack providers that support security groups via terraform. 43 | config_drive = "true" 44 | user_data = "${template_file.master_cloud_init.rendered}" 45 | # Metadata needed by the terraform.py script in order to populate our Ansible inventory properly. 46 | metadata { 47 | role = "mesos_masters" 48 | dc = "${var.region}" 49 | } 50 | } 51 | 52 | # Outputs 53 | 54 | output "master_ips" { 55 | value = "${join(",", openstack_compute_instance_v2.mesos-master.*.access_ip_v4)}" 56 | } 57 | -------------------------------------------------------------------------------- /terraform/rackspace/modules/mesos_masters/master-cloud-config.yml.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # Disable login for root user, only allowing the core user to ssh 4 | write_files: 5 | - path: /etc/ssh/sshd_config 6 | permissions: 0600 7 | owner: root:root 8 | content: | 9 | # Use most defaults for sshd configuration. 10 | UsePrivilegeSeparation sandbox 11 | Subsystem sftp internal-sftp 12 | 13 | PermitRootLogin no 14 | AllowUsers core 15 | PasswordAuthentication no 16 | ChallengeResponseAuthentication no 17 | coreos: 18 | etcd2: 19 | # $public_ipv4 and v6 are populated by the cloud provider 20 | advertise-client-urls: "http://$public_ipv4:2379" 21 | initial-advertise-peer-urls: "http://$private_ipv4:2380" 22 | # listen on both the official ports and the legacy ports 23 | # legacy ports can be omitted if your application doesn't depend on them 24 | listen-client-urls: "http://0.0.0.0:2379,http://0.0.0.0:4001" 25 | listen-peer-urls: "http://$private_ipv4:2380,http://$private_ipv4:7001" 26 | # Discovery is populated by Terraform 27 | discovery: ${etcd_discovery_url} 28 | units: 29 | - name: etcd2.service 30 | command: start 31 | update: 32 | reboot-strategy: best-effort 33 | manage_etc_hosts: localhost 34 | -------------------------------------------------------------------------------- /terraform/rackspace/modules/sg-default/main.tf: -------------------------------------------------------------------------------- 1 | variable "security_group_name" { default = "default" } 2 | 3 | resource "openstack_compute_secgroup_v2" "default" { 4 | name = "${var.security_group_name}" 5 | description = "Default security group allowing all traffic" 6 | # Allows inbound and outbound traffic from all instances within this group. 7 | # Not quite necessary at the moment as the next rule allows all ingress and egress traffic. 8 | rule { 9 | from_port = 0 10 | to_port = 0 11 | ip_protocol = "-1" 12 | self = true 13 | } 14 | # Allows inbound and outbound traffic. 15 | rule { 16 | from_port = 0 17 | to_port = 0 18 | ip_protocol = "-1" 19 | cidr = "0.0.0.0/0" 20 | } 21 | } 22 | 23 | # Outputs 24 | output "security_group_name" { 25 | value = "${openstack_compute_secgroup_v2.default.name}" 26 | } 27 | -------------------------------------------------------------------------------- /terraform/scripts/coreos/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | set -e 4 | 5 | cd 6 | 7 | if [[ -e $HOME/.bootstrapped ]]; then 8 | exit 0 9 | fi 10 | 11 | PYPY_VERSION=2.4.0 12 | 13 | if [[ -e $HOME/pypy-$PYPY_VERSION-linux64.tar.bz2 ]]; then 14 | tar -xjf $HOME/pypy-$PYPY_VERSION-linux64.tar.bz2 15 | rm -rf $HOME/pypy-$PYPY_VERSION-linux64.tar.bz2 16 | else 17 | wget -O - https://bitbucket.org/pypy/pypy/downloads/pypy-$PYPY_VERSION-linux64.tar.bz2 |tar -xjf - 18 | fi 19 | 20 | mv -n pypy-$PYPY_VERSION-linux64 pypy 21 | 22 | ## library fixup 23 | mkdir -p pypy/lib 24 | ln -snf /lib64/libncurses.so.5.9 $HOME/pypy/lib/libtinfo.so.5 25 | 26 | mkdir -p $HOME/bin 27 | 28 | cat > $HOME/bin/python < (number of masters)/2 11 | # For standalone mode is always 1 12 | mesos_master_quorum: 1 13 | # Expected number of server nodes 14 | # For standalone mode is always 1 15 | consul_bootstrap_expect: 1 16 | 17 | coreos_update_channel: stable 18 | coreos_stable_min_version: 835.9.0 19 | coreos_beta_min_version: 877.1.0 20 | -------------------------------------------------------------------------------- /vagrant.yml: -------------------------------------------------------------------------------- 1 | masters: 2 | # Memory and Cpus setting 3 | ########################## 4 | mem: 1024 5 | cpus: 1 6 | # Actual instances 7 | ################## 8 | ips: 9 | - 172.31.1.11 10 | - 172.31.1.12 11 | - 172.31.1.13 12 | # By default only one agent is set, to increase that number just add new ips. 13 | agents: 14 | # Memory and Cpus setting 15 | ########################## 16 | mem: 1536 17 | cpus: 2 18 | # agent IPs - must be in the same private address range as the master instances 19 | # See http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces 20 | ips: 21 | - 172.31.1.14 22 | # Mesos master quorum: quorum > (number of masters)/2 23 | # For standalone mode is always 1 24 | mesos_master_quorum: 2 25 | # Expected number of server nodes 26 | # For standalone mode is always 1 27 | consul_bootstrap_expect: 3 28 | 29 | coreos_update_channel: stable 30 | coreos_stable_min_version: 835.9.0 31 | coreos_beta_min_version: 877.1.0 32 | -------------------------------------------------------------------------------- /vagrant_helper.rb: -------------------------------------------------------------------------------- 1 | # Gets environment variables with APOLLO_ prefix 2 | # We merge those variables with ansible.extra_vars in Vagrantfile 3 | def get_apollo_variables(env) 4 | apollo_env_vars = {} 5 | apollo_prefix = /^APOLLO_/ 6 | 7 | env.each { |key, value| 8 | if key.match(apollo_prefix) 9 | key_name = key.gsub(apollo_prefix, '').to_sym 10 | apollo_env_vars[key_name] = value 11 | end 12 | } 13 | 14 | return apollo_env_vars 15 | end 16 | 17 | # Automatically replace the discovery token on 'vagrant up' 18 | def etcd_discovery_token(num_instances) 19 | # Used to fetch a new discovery token for a cluster of size num_instances 20 | $new_discovery_url="https://discovery.etcd.io/new?size=#{num_instances}" 21 | 22 | if File.exists?('user-data') && ARGV[0].eql?('up') 23 | require 'open-uri' 24 | require 'yaml' 25 | 26 | token = open($new_discovery_url).read 27 | 28 | data = YAML.load(IO.readlines('user-data')[1..-1].join) 29 | 30 | if data.key? 'coreos' and data['coreos'].key? 'etcd' 31 | data['coreos']['etcd']['discovery'] = token 32 | end 33 | 34 | if data.key? 'coreos' and data['coreos'].key? 'etcd2' 35 | data['coreos']['etcd2']['discovery'] = token 36 | end 37 | 38 | # Fix for YAML.load() converting reboot-strategy from 'off' to `false` 39 | if data.key? 'coreos' and data['coreos'].key? 'update' and data['coreos']['update'].key? 'reboot-strategy' 40 | if data['coreos']['update']['reboot-strategy'] == false 41 | data['coreos']['update']['reboot-strategy'] = 'off' 42 | end 43 | end 44 | 45 | yaml = YAML.dump(data) 46 | File.open('user-data', 'w') { |file| file.write("#cloud-config\n\n#{yaml}") } 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: python:2.7 2 | no-response-timeout: 15 3 | build: 4 | steps: 5 | - install-packages: 6 | packages: unzip 7 | - pip-install: 8 | requirements_file: "requirements-test.txt" 9 | - capgemini/ansible-lint: 10 | name: run ansible-lint against the site.yml playbook 11 | playbook: site.yml 12 | - capgemini/terraform-install: 13 | version: 0.6.14 14 | - script: 15 | name: terraform validate 16 | code: | 17 | find terraform/aws/private-cloud/ -type d \( -path terraform/aws/private-cloud/bin -path .terraform \) -prune -exec sh -c '(cd {} && terraform validate)' ';' 18 | find terraform/aws/public-cloud/ -type d \( -path .terraform \) -prune -exec sh -c '(cd {} && terraform validate)' ';' 19 | find terraform/digitalocean/ -type d \( -path .terraform \) -prune -exec sh -c '(cd {} && terraform validate)' ';' 20 | find terraform/gce/ -type d \( -path .terraform \) -prune -exec sh -c '(cd {} && terraform validate)' ';' 21 | find terraform/rackspace/ -type d \( -path .terraform \) -prune -exec sh -c '(cd {} && terraform validate)' ';' 22 | - script: 23 | name: syntax-check ansible playbook 24 | code: | 25 | echo localhost > wercker_inventory 26 | ansible-galaxy install --force -r contrib-plugins/plugins.yml 27 | ansible-galaxy install --force -r requirements.yml 28 | ansible-playbook -i wercker_inventory --syntax-check site.yml 29 | - script: 30 | name: scripts testing 31 | cwd: bootstrap/tests 32 | code: | 33 | /bin/bash test.sh 34 | --------------------------------------------------------------------------------