diff --git a/README.md b/README.md index 3c0ec472..8cc871b6 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,13 @@ repository. To install this, follow the instructions below. Clocker for [Apache Brooklyn](https://brooklyn.apache.org/) is a set of open source, Apache Licensed tools designed to make working with [Docker](https://www.docker.com/) containers as simple as a few clicks. Clocker contains [Brooklyn blueprints](http://brooklyn.apache.org/v/latest/start/blueprints.html) -to enable deployment and management of [Docker Swarm](https://www.docker.com/products/docker-swarm) -and [Kubernetes](http://kubernetes.io/) clusters. +to enable deployment and management of [Docker Swarm](https://www.docker.com/products/docker-swarm), +[Amazon ECS](https://aws.amazon.com/ecs/) and [Kubernetes](http://kubernetes.io/) clusters. You will find the source code for the blueprints in this repository. * [Docker](./common/catalog/docker/) +* [ECS](./ecs/src/main/resources/ecs/) * [Swarm](./swarm/catalog/swarm/) * [Kubernetes](./kubernetes/catalog/kubernetes/) @@ -34,9 +35,11 @@ brooklyn.catalog: brooklyn.libraries: - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.etcd&a=brooklyn-etcd&v=2.3.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-common&v=2.1.0-SNAPSHOT" + - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-ecs&v=2.1.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-swarm&v=2.1.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-kubernetes&v=2.1.0-SNAPSHOT" items: + - classpath://io.brooklyn.clocker.ecs:ecs/catalog.bom - classpath://io.brooklyn.clocker.swarm:swarm/catalog.bom - classpath://io.brooklyn.clocker.kubernetes:kubernetes/catalog.bom ``` @@ -47,6 +50,7 @@ You must add the following JARs to `./lib/dropins`: * [brooklyn-etcd](https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.etcd&a=brooklyn-etcd&v=2.3.0-SNAPSHOT) * [common](https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-common&v=2.1.0-SNAPSHOT) +* [ecs](https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-ecs&v=2.1.0-SNAPSHOT) * [swarm](https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-swarm&v=2.1.0-SNAPSHOT) * [kubernetes](https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-kubernetes&v=2.1.0-SNAPSHOT) @@ -55,6 +59,7 @@ Then add the catalog entries using the following YAML: ```YAML brooklyn.catalog: items: + - classpath://ecs/catalog.bom - classpath://swarm/catalog.bom - classpath://kubernetes/catalog.bom ``` diff --git a/clocker.bom b/clocker.bom index 01ea8d16..1a6659cb 100644 --- a/clocker.bom +++ b/clocker.bom @@ -2,8 +2,10 @@ brooklyn.catalog: brooklyn.libraries: - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.etcd&a=brooklyn-etcd&v=2.3.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-common&v=2.1.0-SNAPSHOT" + - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-ecs&v=2.1.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-swarm&v=2.1.0-SNAPSHOT" - "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.brooklyn.clocker&a=clocker-kubernetes&v=2.1.0-SNAPSHOT" items: + - classpath://io.brooklyn.clocker.ecs:ecs/catalog.bom - classpath://io.brooklyn.clocker.swarm:swarm/catalog.bom - classpath://io.brooklyn.clocker.kubernetes:kubernetes/catalog.bom diff --git a/common/catalog/docker/catalog.bom b/common/catalog/docker/catalog.bom index fd3278cc..1a769786 100644 --- a/common/catalog/docker/catalog.bom +++ b/common/catalog/docker/catalog.bom @@ -1,13 +1,13 @@ brooklyn.catalog: items: - - classpath://io.brooklyn.clocker.common:docker/docker.bom + - classpath://io.brooklyn.clocker.common:docker/docker.bom - - id: docker-engine-template - name: "Docker Engine" - description: | - Creates a single docker engine. - itemType: template - iconUrl: classpath://io.brooklyn.clocker.common:icons/docker.png - item: - services: - - type: docker-engine \ No newline at end of file + - id: docker-engine-template + name: "Docker Engine" + description: | + Creates a single docker engine. + itemType: template + iconUrl: classpath://io.brooklyn.clocker.common:icons/docker.png + item: + services: + - type: docker-engine diff --git a/ecs/catalog/ecs/catalog.bom b/ecs/catalog/ecs/catalog.bom new file mode 100644 index 00000000..cddb229e --- /dev/null +++ b/ecs/catalog/ecs/catalog.bom @@ -0,0 +1,4 @@ +brooklyn.catalog: + items: + - classpath://io.brooklyn.clocker.common:docker/catalog.bom + - classpath://io.brooklyn.clocker.ecs:ecs/ecs.bom diff --git a/ecs/catalog/ecs/ecs.bom b/ecs/catalog/ecs/ecs.bom new file mode 100644 index 00000000..d4bc3cee --- /dev/null +++ b/ecs/catalog/ecs/ecs.bom @@ -0,0 +1,286 @@ +brooklyn.catalog: + version: "2.1.0-SNAPSHOT" # CLOCKER_VERSION + publish: + description: | + Resources for working with Docker and Amazon ECS from Apache Brooklyn + license_code: APACHE-2.0 + overview: README.md + + items: + - id: ecs-cluster-template + name: "EC2 Container Service Docker Cluster" + description: | + Creates a cluster of Docker engines for use with Amazon ECS + itemType: template + iconUrl: classpath://io.brooklyn.clocker.ecs:icons/ecs.png + item: + services: + - type: ecs-cluster + + - id: ecs-cluster + name: "EC2 Container Service Docker Cluster" + description: | + Creates a cluster of Docker engines for use with Amazon ECS + itemType: entity + iconUrl: classpath://io.brooklyn.clocker.ecs:icons/ecs.png + item: + type: org.apache.brooklyn.entity.stock.BasicApplication + + brooklyn.parameters: + # Duplicated parameters for UI visibility + - name: docker.initial.size + label: "Initial Cluster Size" + description: | + Size of the docker cluster when created initially + type: integer + default: 1 + - name: docker.max.size + label: "Maximum Cluster Size" + description: | + Maximum size the docker cluster can be scaled to + type: integer + default: 5 + - name: docker.sharedsecuritygroup.create + label: "Create Docker SharedSecurityGroup" + description: | + Clocker blueprint will configure security groups to allow access between docker nodes and + to allow external access to deployed apps + type: boolean + default: true + - name: ecs.cluster.name + label: "ECS Cluster Name" + description: | + The name of the ECS cluster + type: string + default: "clocker" + + brooklyn.children: + - type: ecs-docker-cluster + id: ecs-docker-cluster + name: "ecs-docker-cluster" + + - id: ecs-docker-cluster + name: "ECS Docker Cluster" + description: | + Creates a cluster of Docker engines, of configurable initial size, and + configures them for use with the Amazon EC2 comtainer service. + itemType: entity + item: + type: cluster + + brooklyn.parameters: + - name: docker.initial.size + label: "Initial Cluster Size" + description: | + Size of the Docker cluster when created initially + type: integer + default: 1 + - name: docker.max.size + label: "Maximum Cluster Size" + description: | + Maximum size the Docker cluster can be scaled to + type: integer + default: 5 + - name: docker.scaling.cpu.limit + label: "Docker Scaling CPU Limit" + description: | + The average CPU usage limit for the Docker cluster, before another node + will automatically be added. The default is 0.95 or 95% + type: double + default: 0.95 + - name: docker.recovery.quarantineFailedEntities + label: "Quarantine" + description: | + Quarantine failed entities instead of destroying them + type: boolean + default: true + - name: docker.recovery.failOnRecurringFailuresInThisDuration + label: "Fail Duration" + description: | + Reports entity as failed if it fails two or more times in this time window + type: long + default: 300000 + + brooklyn.policies: + - type: org.apache.brooklyn.policy.ha.ServiceReplacer + brooklyn.config: + failureSensorToMonitor: $brooklyn:sensor("ha.entityFailed") + failOnRecurringFailuresInThisDuration: + $brooklyn:config("docker.recovery.failOnRecurringFailuresInThisDuration") + - type: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy + brooklyn.config: + autoscaler.metric: + $brooklyn:sensor("org.apache.brooklyn.entity.machine.MachineAttributes", "cpu.average") + autoscaler.metricLowerBound: 0.00 + autoscaler.metricUpperBound: + $brooklyn:config("docker.scaling.cpu.limit") + autoscaler.minPoolSize: + $brooklyn:config("docker.initial.size") + autoscaler.maxPoolSize: + $brooklyn:config("docker.max.size") + autoscaler.resizeUpStabilizationDelay: 30s + autoscaler.resizeDownIterationMax: 0 # Disable scaling down + + brooklyn.enrichers: + - type: org.apache.brooklyn.enricher.stock.Aggregator + brooklyn.config: + uniqueTag: ecs-docker-cluster-cpu-averageing + enricher.sourceSensor: + $brooklyn:sensor("org.apache.brooklyn.entity.machine.MachineAttributes", "machine.cpu") + enricher.targetSensor: + $brooklyn:sensor("org.apache.brooklyn.entity.machine.MachineAttributes", "cpu.average") + enricher.aggregating.fromMembers: true + transformation: average + - type: org.apache.brooklyn.enricher.stock.Aggregator + brooklyn.config: + uniqueTag: ecs-docker-cluster-tasks-total + enricher.sourceSensor: $brooklyn:sensor("ecs.tasks.count") + enricher.targetSensor: $brooklyn:sensor("ecs.tasks.total") + enricher.aggregating.fromMembers: true + transformation: sum + + brooklyn.config: + cluster.initial.size: $brooklyn:config("docker.initial.size") + dynamiccluster.quarantineFailedEntities: + $brooklyn:config("docker.recovery.quarantineFailedEntities") + dynamiccluster.memberspec: + $brooklyn:entitySpec: + type: docker-engine-with-ecs + id: docker-engine + name: "docker-engine" + + - id: docker-engine-with-ecs + name: Docker Engine with ECS + description: | + A docker-engine customised with the ECS agent + itemType: entity + iconUrl: classpath://io.brooklyn.clocker.common:icons/docker.png + item: + type: docker-engine + + brooklyn.parameters: + - name: docker.recovery.stabilizationDelay + label: "Stabilization Delay" + description: | + Time period for which the service must be consistently in the same state to trigger an action. + Should be long enough that restart will not trigger failure. + type: org.apache.brooklyn.util.time.Duration + default: 5m + + brooklyn.enrichers: + - type: org.apache.brooklyn.policy.ha.ServiceFailureDetector + brooklyn.config: + serviceOnFire.stabilizationDelay: + $brooklyn:config("docker.recovery.stabilizationDelay") + entityFailed.stabilizationDelay: + $brooklyn:config("docker.recovery.stabilizationDelay") + entityRecovered.stabilizationDelay: + $brooklyn:config("docker.recovery.stabilizationDelay") + - type: org.apache.brooklyn.enricher.stock.Propagator + brooklyn.config: + uniqueTag: ecs-agent-tasks-propagator + producer: $brooklyn:child("ecs-agent") + propagating: + - $brooklyn:sensor("ecs.tasks.count") + + brooklyn.config: + provisioning.properties: + customizer: + $brooklyn:object: + type: org.apache.brooklyn.location.jclouds.networking.SharedLocationSecurityGroupCustomizer + object.fields: + tcpPortRanges: + - "32768-65535" + enabled: $brooklyn:config("docker.sharedsecuritygroup.create") + + brooklyn.children: + - type: ecs-agent + id: ecs-agent + name: "ecs-agent" + + - id: ecs-agent + name: "ECS Agent" + description: | + The ECS agent Docker container + itemType: entity + iconUrl: classpath://io.brooklyn.clocker.ecs:icons/ecs.png + item: + type: child-software-process + + brooklyn.parameters: + - name: ecs.agent.version + label: "ECS Agent Version" + type: string + default: "1.13.0" + - name: ecs.cluster.name + label: "ECS Cluster Name" + description: | + The name of the ECS cluster + type: string + default: "clocker" + + brooklyn.config: + shell.env: + ECS_AGENT_VERSION: $brooklyn:config("ecs.agent.version") + ECS_CLUSTER_NAME: $brooklyn:config("ecs.cluster.name") + + install.command: | + sudo yum install -y jq + sudo mkdir -p /var/log/ecs + sudo mkdir -p /var/lib/ecs/data + sudo sysctl -w net.ipv4.conf.all.route_localnet=1 + sudo iptables -t nat -A PREROUTING \ + -p tcp -d 169.254.170.2 --dport 80 \ + -j DNAT --to-destination 127.0.0.1:51679 + sudo iptables -t nat -A OUTPUT \ + -d 169.254.170.2 -p tcp -m tcp \ + --dport 80 -j REDIRECT --to-ports 51679 + + launch.command: | + docker run --name ecs-agent \ + --detach=true \ + --restart=on-failure:10 \ + --volume=/var/run/docker.sock:/var/run/docker.sock \ + --volume=/var/log/ecs/:/log \ + --volume=/var/lib/ecs/data:/data \ + --net=host \ + --env=ECS_LOGFILE=/log/ecs-agent.log \ + --env=ECS_LOGLEVEL=info \ + --env=ECS_DATADIR=/data \ + --env=ECS_CLUSTER=${ECS_CLUSTER_NAME} \ + --env=ECS_ENABLE_TASK_IAM_ROLE=true \ + --env=ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true \ + amazon/amazon-ecs-agent:v${ECS_AGENT_VERSION} + + checkRunning.command: | + [[ $(docker inspect --format "{{ .State.Running }}" ecs-agent) == "true" ]] + + brooklyn.initializers: + - type: org.apache.brooklyn.core.sensor.ssh.SshCommandSensor + brooklyn.config: + name: ecs.agent.version + description: | + ECS installed version details + targetType: string + command: | + curl http://localhost:51678/v1/metadata | + jq '.Version' + - type: org.apache.brooklyn.core.sensor.ssh.SshCommandSensor + brooklyn.config: + name: ecs.instance.arn + description: | + ECS instance ARN identifier + targetType: string + command: | + curl http://localhost:51678/v1/metadata | + jq '.ContainerInstanceArn' + - type: org.apache.brooklyn.core.sensor.ssh.SshCommandSensor + brooklyn.config: + name: ecs.tasks.count + description: | + ECS task count for the instance + targetType: integer + command: | + curl http://localhost:51678/v1/tasks | + jq '.Tasks[] | .Arn' ~/tmp/ecs/tasks.json | + wc -l diff --git a/ecs/examples/ecs-cluster.yaml b/ecs/examples/ecs-cluster.yaml new file mode 100644 index 00000000..ade3f3ce --- /dev/null +++ b/ecs/examples/ecs-cluster.yaml @@ -0,0 +1,33 @@ +id: ecs-cluster +name: "Amazon ECS Docker Cluster" +description: | + Creates a cluster of Docker Engines with the Amazon ECS Agent. + + Deploys on AWS using the configuread IAM profile set in 'templateOptions' + for the instances. See the ECS documentation for detailed instructions: + + http://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html + +location: + jclouds:aws-ec2: + region: eu-west-1 + privateKeyFile: "~/.ssh/ecs.pem" + loginUser.privateKeyFile: "~/.ssh/ecs.pem" + keyPair: "ecs" + templateOptions: + iamInstanceProfileArn: + "arn:aws:iam::12345678:instance-profile/clocker" + securityGroups: + - "sg-xxxxxx" + +services: + - type: ecs-cluster + name: "ecs-cluster" + brooklyn.config: + ecs.cluster.name: "clocker" + docker.initial.size: 2 + docker.max.size: 5 + docker.sharedsecuritygroup.create: true + provisioning.properties: + minRam: 10g + minCores: 4 diff --git a/ecs/pom.xml b/ecs/pom.xml new file mode 100644 index 00000000..ea394bfb --- /dev/null +++ b/ecs/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + + io.brooklyn.clocker + clocker-parent + 2.1.0-SNAPSHOT + + + Clocker :: ECS + clocker-ecs + jar + + + + + catalog + false + + + resources + false + + + tests + false + tests + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.12 + + + attach-artifact + package + + attach-artifact + + + + + ${project.basedir}/catalog/ecs/ecs.bom + bom + ecs + + + + + + + + + diff --git a/ecs/resources/icons/ecs.png b/ecs/resources/icons/ecs.png new file mode 100644 index 00000000..066088a9 Binary files /dev/null and b/ecs/resources/icons/ecs.png differ diff --git a/ecs/tests/ecs/ecs.tests.bom b/ecs/tests/ecs/ecs.tests.bom new file mode 100644 index 00000000..01948b07 --- /dev/null +++ b/ecs/tests/ecs/ecs.tests.bom @@ -0,0 +1,84 @@ +brooklyn.catalog: + version: "2.1.0-SNAPSHOT" # CLOCKER_VERSION + iconUrl: https://raw.githubusercontent.com/docker-library/docs/471fa6e4cb58062ccbf91afc111980f9c7004981/swarm/logo.png + dependsOn: + - tests/common.tests.bom + - tests/docker.tests.bom + license_code: APACHE-2.0 + +# NOTE This test requires a location in an Amazon EC2 region that has had an +# ECS cluster created already, named 'clocker-qa-test' and an IAM profile +# to access it also named 'clocker-qa-test' as in the following YAML fragment: +# +# location: +# jclouds:aws-ec2: +# region: eu-west-1 +# templateOptions: +# iamInstanceProfileName: "clocker-qa-test" + + items: + - id: ecs-cluster-tests + name: "ECS Cluster Tests" + description: | + Tests on the ECS cluster of Docker Engine entities + itemType: entity + item: + type: test-case + name: "ecs-cluster-tests" + + brooklyn.config: + docker.initial.size: 2 + docker.max.size: 3 + docker.scaling.cpu.limit: 0.95 + docker.recovery.stabilizationDelay: 10s + docker.recovery.failOnRecurringFailuresInThisDuration: 5m + + brooklyn.children: + - type: ecs-cluster + id: ecs-cluster + name: "ecs-cluster" + description: | + The ECS cluster to test + brooklyn.config: + ecs.cluster.name: "clocker-qa-test" + ecs.agent.version: "1.13.0" + + - type: test-case + name: "ecs-test-suite" + brooklyn.children: + - type: test-case + name: "GROUP-1 Test ECS entity" + brooklyn.config: + targetId: ecs-cluster + brooklyn.children: + - type: assert-up + name: "TEST-01 Assert up" + - type: assert-running + name: "TEST-02 Assert running" + - type: sensor-test + name: "TEST-03 Size of cluster is 2" + targetId: ecs-docker-cluster + timeout: 20m + sensor: group.members.count + assert: + equals: $brooklyn:config("docker.initial.size") + - type: sensor-test + name: "TEST-04 Number of tasks is 0" + targetId: ecs-docker-cluster + timeout: 20m + sensor: ecs.tasks.total + assert: + equals: 0 + - type: loop-test-case + name: "TEST-05 Check agent version" + brooklyn.config: + targetId: ecs-docker-cluster + test.spec: + $brooklyn:entitySpec: + type: sensor-test + name: "TEST-05-a Agent version sensor same as config" + targetId: ecs-agent + timeout: 20m + sensor: ecs.agent.versoin + assert: + contains: $brooklyn:config("ecs.agent.version") diff --git a/ecs/tests/ecs/tests.bom b/ecs/tests/ecs/tests.bom new file mode 100644 index 00000000..181e9153 --- /dev/null +++ b/ecs/tests/ecs/tests.bom @@ -0,0 +1,21 @@ +brooklyn.catalog: + version: "2.1.0-SNAPSHOT" # CLOCKER_VERSION + iconUrl: https://raw.githubusercontent.com/docker-library/docs/471fa6e4cb58062ccbf91afc111980f9c7004981/swarm/logo.png + dependsOn: + - tests/ecs.tests.bom + license_code: APACHE-2.0 + + items: + - id: ecs-tests + name: "ECS Tests" + description: | + Tests for ECS entities + itemType: template + item: + brooklyn.config: + timeout: 1h + timeout.initialStartup: 1h + timeout.runtimeAssertion: 1h + + services: + - type: ecs-cluster-tests diff --git a/pom.xml b/pom.xml index 98c1f6c8..00abd97c 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ common + ecs swarm kubernetes feature