Skip to content

Add deploy recipe for pallet deploy of an app #229

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions deployment/deploy-application-with-pallet/deploy.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
////
:Author: Hugo Duncan
:Email: hugo@hugoduncan.org
////

=== Deploy your Clojure Application

(((Embedded jetty)))
(((jenkins)))

===== Problem

You have a clojure application, containing a +main+, and packaged with +lein uberjar+. You want to deploy your clojure application to a server, and run it under process supervision.

===== Solution

Use http://palletops.com/[Pallet] to deploy your application to EC2
(or elsewhere), using http://smarden.org/runit/[runit] to supervise the server
process.

To demonstrate this, we're going to deploy
http://jenkins-ci.org/[jenkins] using its embedded jetty server.

To get started you create a new project with leiningen, using the +pallet+ template:

[source,console]
----
$ lein new pallet deployer
----

Add the +app-deploy-crate+, +java-crate+ and +runit-crate+ to your +:dependencies+ in
the generated +project.clj+ file. Pallet crates are jar files that
contain functions for installing, configuring and running a specific
library or application.

[source, clojure]
----
:dependencies [...
[com.palletops/app-deploy-crate "0.8.0-alpha.3"]
[com.palletops/java-crate "0.8.0-beta.5"]
[com.palletops/runit-crate "0.8.0-alpha.1"]
...]
----

We will require these crates in the definition of the +server-spec+
used by pallet to describe what we want on the server.

[source, clojure]
----
(ns deployer.groups.deployer
"Node definitions for deployer"
(:require
[pallet.api :refer [group-spec server-spec node-spec plan-fn]]
[pallet.crate.automated-admin-user :refer [automated-admin-user]]
[pallet.crate.app-deploy :as app-deploy]
[pallet.crate.java :as java]
[pallet.crate.runit :as runit]))

...

(def
^{:doc "Define a server spec for deployer"}
deployer-server
(server-spec
:extends ; <1>
[(java/server-spec {}) ; <2>
(runit/server-spec {}) ; <3>
(app-deploy/server-spec
{:app-root "/opt/jenkins" ; <4>
:artifacts
{:from-maven-repo
[{:coord '[org.jenkins-ci.main/jenkins-war "1.529" :extension "war"]
:path "jenkins.war"}]}
:repositories {"jenkins" ; <5>
{:url "http://repo.jenkins-ci.org/public"}}
:run-command "java -jar /opt/jenkins/jenkins.war"})]))
...
----

1. extends allows you to compose other +sever-spec+ definitions
3. ensures java is installed
3. ensures runit is installed
4. the +:app-root+ determines the root directory for the deployment artifacts
5. your project uberjar will be found by looking in a specific repository

Now we have the server described, we need to tell Pallet the
credentials we want to use on EC2:

[source,console]
----
$ lein pallet add-service aws aws-ec2 "your-aws-key" "your-aws-secret-key"
----

Deploy jenkins on a new ec2 node:

[source,console]
----
$ lein pallet up --phases install,configure,deploy
----

Jenkins will now be running on port 8080.

You can redeploy your application with:

[source,console]
----
$ lein pallet up --phases deploy
----

===== Discussion

You have many choices of where to run a server; on EC2 or other cloud, on a VPS host, or on some dedicated machine. Using http://palletops.com/[Pallet], you can deploy to any of these environments using the same code.

There are also many process supervision frameworks to choose from. We have used http://smarden.org/runit/[runit] which is the default for the +app-deploy+ crate, but you can use +upstart+ or +initd+,
for example.

===== See Also

* <<sec_using_chef_puppet>> on using chef or puppet to deploy
13 changes: 13 additions & 0 deletions deployment/deploy-application-with-pallet/deployer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# deployer

A pallet project designed to ... well, that part is up to you.

## Usage

FIXME

## License

Copyright © FIXME

Distributed under the Eclipse Public License.
10 changes: 10 additions & 0 deletions deployment/deploy-application-with-pallet/deployer/pallet.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(require
'[deployer.groups.deployer :refer [deployer]])

(defproject deployer
:provider {:jclouds
{:node-spec
{:image {:os-family :ubuntu :os-version-matches "12.04"
:os-64-bit true}}}}

:groups [deployer])
30 changes: 30 additions & 0 deletions deployment/deploy-application-with-pallet/deployer/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
(defproject deployer "0.1.0-SNAPSHOT"
:description "FIXME Pallet project for deployer"
:dependencies [[org.clojure/clojure "1.4.0"]
[com.palletops/pallet "0.8.0-RC.1"]
[com.palletops/pallet-jclouds "1.5.3"]
[com.palletops/app-deploy "0.8.0-alpha.2"]
[com.palletops/runit "0.8.0-alpha.1"]
;; To get started we include all jclouds compute providers.
;; You may wish to replace this with the specific jclouds
;; providers you use, to reduce dependency sizes.
[org.jclouds/jclouds-allblobstore "1.5.5"]
[org.jclouds/jclouds-allcompute "1.5.5"]
[org.jclouds.driver/jclouds-slf4j "1.5.5"
;; the declared version is old and can overrule the
;; resolved version
:exclusions [org.slf4j/slf4j-api]]
[org.jclouds.driver/jclouds-sshj "1.5.5"]
[ch.qos.logback/logback-classic "1.0.9"]]
:profiles {:dev
{:dependencies
[[com.palletops/pallet "0.8.0-RC.1"
:classifier "tests"]]
:plugins
[[com.palletops/pallet-lein "0.8.0-alpha.1"]]}
:leiningen/reply
{:dependencies [[org.slf4j/jcl-over-slf4j "1.7.2"]]
:exclusions [commons-logging]}}
:local-repo-classpath true
:repositories
{"sonatype" "https://oss.sonatype.org/content/repositories/releases/"})
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<configuration scan="true" scanPeriod="1 seconds" debug="false">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>

<appender name="COMPUTEFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/jclouds-compute.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/old/jclouds-compute.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>

<appender name="WIREFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/jclouds-wire.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/old/jclouds-wire.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>

<appender name="PALLETFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/pallet.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/old/pallet.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} %msg%n</pattern>
</encoder>
</appender>

<appender name="VMFESTFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/vmfest.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/old/vmfest.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>3</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date %level [%thread] %logger{10} %msg%n</pattern>
</encoder>
</appender>

<logger name="jclouds.headers" level="INFO">
<appender-ref ref="WIREFILE" />
</logger>

<logger name="jclouds.wire" level="INFO">
<appender-ref ref="WIREFILE" />
</logger>

<logger name="jclouds.compute" level="INFO">
<appender-ref ref="COMPUTEFILE" />
</logger>

<logger name="jclouds.ssh" level="INFO">
<appender-ref ref="COMPUTEFILE" />
</logger>

<logger name="clj-ssh.ssh" level="INFO">
<!-- Set this to TRACE to debug ssh keys -->
<appender-ref ref="COMPUTEFILE" />
</logger>

<logger name="pallet" level="DEBUG">
<appender-ref ref="PALLETFILE" />
</logger>

<logger name="vmfest" level="DEBUG">
<appender-ref ref="VMFESTFILE" />
</logger>

<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>

<logger name="clj-ssh.ssh" level="ERROR"/>
<logger name="pallet.action-plan" level="INFO"/>
<logger name="pallet.action-plan" level="INFO"/>
<logger name="pallet.algo.fsm" level="WARN"/>
<logger name="pallet.algo.fsmop" level="WARN"/>
<logger name="pallet.configure" level="INFO"/>
<logger name="pallet.core.api" level="DEBUG"/>
<logger name="pallet.core.operations" level="DEBUG"/>
<logger name="pallet.core.primitives" level="DEBUG"/>
<logger name="pallet.crate.nohup" level="DEBUG"/>
<logger name="pallet.execute" level="DEBUG"/>
<logger name="pallet.executors" level="INFO"/>
<logger name="pallet.project" level="INFO"/>
<logger name="pallet.stevedore" level="INFO"/>
<logger name="pallet.transport" level="DEBUG"/>

</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(ns deployer.groups.deployer
"Node defintions for deployer"
(:require
[pallet.core :refer [group-spec server-spec node-spec plan-fn]]
[pallet.crate.automated-admin-user :refer [automated-admin-user]]
[pallet.crate.app-deploy :as app-deploy]
[pallet.crate.runit :as runit]))

(def default-node-spec
(node-spec
:image {:os-family :ubuntu}
:hardware {:min-cores 1}))

(def
^{:doc "Defines the type of node deployer will run on"}
base-server
(server-spec
:phases
{:bootstrap (plan-fn (automated-admin-user))}))

(def
^{:doc "Define a server spec for deployer"}
deployer-server
(server-spec
:extends [(app-deploy/server-spec
{:artifacts
{:from-maven-repo [{:coord '[your-project-id "0.1.0"]
:path "your-project.jar"}]}})
(runit/server-spec {})]))

(def
^{:doc "Defines a group spec that can be passed to converge or lift."}
deployer
(group-spec
"deployer"
:extends [base-server deployer-server]
:node-spec default-node-spec))
1 change: 1 addition & 0 deletions deployment/deployment.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
== Deployment & Distribution

include::deploy-on-lein/deploy-on-lein.asciidoc[]
include::deploy-application-with-pallet/deploy.asciidoc[]