-
Notifications
You must be signed in to change notification settings - Fork 21
/
atom.xml
1069 lines (910 loc) · 76.8 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Pallet, DevOps for the JVM</title>
<link href="http://palletops.com/atom.xml" rel="self"/>
<link href="http://palletops.com/"/>
<updated>2014-09-22T14:01:57+00:00</updated>
<id>http://palletops.com/</id>
<author>
<name>Antoni Batchelli</name>
<email>[email protected]</email>
</author>
<!-- blog posts -->
<entry>
<title>Article: Run clojure projects on Docker with lein-uberimage</title>
<link href="http://palletops.com//blog/lein-uberimage"/>
<updated>2014-08-07T00:00:00+00:00</updated>
<id>http://palletops.com//blog/lein-uberimage</id>
<content type="html"><p>We built a lein plugin to make it easy to run clojure projects in Docker containers. This article first introduces containers and Docker, and then shows how you can effortlessly create such containers for your Clojure projects with <code>lein uberimage</code>. </p>
<p><image src="/images/docker-large-h-trans.png" alt="Docker logo" class="img-responsive"></p>
<h2>Why Containers and Why Docker</h2>
<p>A container is a lighweight form of computer virtualization. Containers run within a host, and a host can run many containers concurrently. Each container is functionally equivalent to a computer loaded with a full OS, but behind the scenes all containers in the same host are sharing the same host resources: kernel, memory, IO, and disk.</p>
<p>There are many ways of virtualization technologies used today, VirtualBox, Xen (used by Amazon Web Services) and vmware to name a few, but what makes containers special is their lightweight nature. Each container uses very little resources (disk, memory, cpu) and they all boot orders of magnitude faster than a virtual machine or
a computer.</p>
<p>Containers are very convenient for both development and production environments. For development, they provide a fast and simple way to run different and isolated runtime environments for each application. In production, they are very fast and efficient, with the added bonus that containers in production always match the ones in development; the same exact containers are used during all app&#39;s lifecycle.</p>
<p><a href="http://www.docker.com">Docker</a> is a novel container technology for Linux that provides a very low friction access to containers. Containers have been around for a while, and the Linux kernel has provided key container technologies for a while already. Docker wraps all these kernel features under a high level API and defines a standard container and image formats using union filesystems. To make containers easy to share and distribute, Docker also provides public and private image repositories. All these features have brought containers to the masses.</p>
<p>Although Docker is currently Linux only, you can use it on OSX installing <a href="http://boot2docker.io">boot2docker</a></p>
<p>For a more detailed introduction to Docker, check out this video on <a href="http://sysadmincasts.com/episodes/31-introduction-to-docker">sysadmincasts.com</a>.</p>
<h2>Docker images</h2>
<p>Each container is a process tree that is started from an existing image. These images contain a filesystem with the files necessary to run your application. Sometimes this entails a linux distribution and sometimes just one statically linked binary. The common practice in the Docker world is to build a custom image for each type of service you intend to run. This contrasts with other forms of virtualization where you start the VMs from a base image and then you configure them with the required software. In the case of VMs, the time it takes a VM to boot until it is ready to run your application is measured in minutes, whereas in Docker a container can boot in sub-second times.</p>
<h2>Building Docker images with uberimage</h2>
<p><code>lein-uberimage</code> builds a Docker image for clojure projects. The generated images contain a base operating system, a java runtime, and your project&#39;s <code>uberjar</code>. Once this image is built, you can instantiate as many containers as you need using this image, each container running your <code>uberjar</code>.</p>
<p>At the time of writing this, <code>lein-uberimage</code> requires that the project builds with <code>lein uberjar</code> and that the resulting jar can be run via <code>java -jar &lt;your-uberjar&gt;.jar</code>. This means your <code>project.clj</code> will have to have a <code>:main</code> entry pointing to the <code>-main</code> function in your code. This restriction will be removed in the future.</p>
<p>To build the Docker image for your project, run the following in your project&#39;s root:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage
</code></pre></div>
<p><code>uberimage</code> will call lein&#39;s <code>uberjar</code> to build the standalone jar file. Then it will build a new image with <code>Ubuntu 14.04</code>, <code>OpenJDK 7</code> and the freshly built jar. The image is also configured to run your jar file on boot. This task will return the <code>uuid</code> for this image.</p>
<p>From this image you just created, you can spawn as many containers as you need. The most basic way to start a container is this:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>docker run &lt;my-image-uuid&gt;
</code></pre></div>
<p>In most cases, your app won&#39;t be useful unless you can access it via known ports, and by default, Docker does not expose any ports of a container, so you need to tell Docker to expose those ports. Since you will be running many containers on the same host you need to ensure that not two containers are bound to the same port. For example, if your application listens on port 3000, you need to tell Docker to bind the container&#39;s port 3000 to any unbound port in the host, e.g. 8080:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>docker run -p 8080:3000 &lt;my-image-uuid&gt;
</code></pre></div>
<p>Once the container has started, just head over to <code>http://&lt;docker-host&gt;:8080</code> to access your newly deployed service. If you launch a second container with the same image, you cannot bind it to the same host port (8080 in this case) and you should instead map it to port 8081 <code>docker run -p 8081:3000 ...</code>.</p>
<h2>Trying It Out</h2>
<ul>
<li><a href="https://docs.docker.com/installation/#installation">Install</a> Docker.</li>
<li>Clone this <a href="https://github.com/tbatchelli/compojure-example">example clojure project</a>.</li>
<li>On the project root, run <code>lein uberimage</code> and copy the supplied image uuid</li>
<li>At the shell, run <code>docker run -d -p 3000:3000 &lt;image-uuid&gt;</code></li>
<li>Open the browser and head on to <code>http://&lt;docker-host&gt;:3000</code>. Docker-host could be <code>localhost</code> in case you are in linux, or the boot2docker IP address if you are using boot2docker.</li>
<li>Run <code>docker run -d -p 3001:3000 &lt;image-uuid&gt;</code> to run a second instance and check <code>http://&lt;docker-host&gt;:3001</code> with your browser. Notice the different IP address.</li>
</ul>
<h2>Additional Options</h2>
<p>In case the supplied OS and java versions are not what you&#39;re looking for, you can supply your own base image to <code>lein-uberimage</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage -b &lt;your-image-with-jvm&gt;
</code></pre></div>
<p>And in case your Docker is not locally installed on the default port or it is remote, you can override its url:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage -H http://&lt;host&gt;:&lt;port&gt;
</code></pre></div>
<h2>Concluding remarks</h2>
<p>There is not much more to it for now. This is our first stab at helping clojurians leverage containers. Please submit bugs and ideas to our project&#39;s <a href="https://github.com/palletops/lein-uberimage/issues">Issues</a> or drop by our chatroom <a href="http://webchat.freenode.net/?channels=pallet">#pallet</a> on freenode.</p>
<p><code>lein-uberimage</code> is build on top of <a href="https://github.com/palletops/clj-docker.">clj-docker</a>, a clojure wrapper over docker.</p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Alembic - a library to control your classpath</title>
<link href="http://palletops.com//alembic-clojure-classpath-control"/>
<updated>2013-04-29T00:00:00+00:00</updated>
<id>http://palletops.com//alembic-clojure-classpath-control</id>
<content type="html"><p>Working at the REPL in clojure flows well until you need to add a dependency.
The edit <code>project.clj</code> and restart your REPL dance is time consuming, and throws
away the state of your REPL.</p>
<p>Chas Emerick&#39;s <a href="https://github.com/cemerick/pomegranate">pomegranate</a> provides
all the functionality required to add dependencies to your classpath in a
running JVM instance, but comes at the cost of introducing a boatload of
dependencies that may conflict with your project&#39;s own dependencies.</p>
<p><a href="https://github.com/pallet/alembic">Alembic</a> is a new library that solves this
by using <a href="https://github.com/flatland/classlojure">classlojure</a> to put
<a href="https://github.com/cemerick/pomegranate">pomegranate</a> (and lein as a whole, in
fact), into a separate classloader. It then uses the same
<a href="https://github.com/tobias/dynapath">dynapath</a> library used by pomegranate, to
add the resolved dependencies into your classpath. This greatly cuts down the
chance of conflict, and will all but eliminate it if we can remove the <code>useful</code>
dependency from classlojure.</p>
<p>To use Alembic with nREPL or any other clojure REPL, you will need to add
Alembic to you development dependencies. For a leiningen based project, you can
do this by adding it to the <code>:dependencies</code> vector of the <code>:dev</code> profile in
<code>project.clj</code>.</p>
<div class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="ss">:profiles</span> <span class="p">{</span><span class="ss">:dev</span> <span class="p">{</span><span class="ss">:dependencies</span> <span class="p">[[</span><span class="nv">alembic</span> <span class="s">&quot;0.1.0&quot;</span><span class="p">]]}}</span>
</code></pre></div>
<p>You can enable Alembic on all you projects, by adding it to the <code>:dependencies</code>
vector of the <code>:user</code> profile in <code>~/.lein/profiles.clj</code>.</p>
<p>The main function in alembic today is <code>distill</code>, which adds a dependency to your
classpath. For example, to add <code>tools.logging</code>, you would call <code>distill</code> like
this:</p>
<div class="highlight"><pre><code class="language-clojure" data-lang="clojure"><span class="p">(</span><span class="nf">require</span> <span class="ss">&#39;alembic.still</span><span class="p">)</span>
<span class="p">(</span><span class="nf">alembic.still/distill</span> <span class="o">&#39;</span><span class="p">[</span><span class="nv">org.clojure/tools.logging</span> <span class="s">&quot;0.2.0&quot;</span><span class="p">])</span>
</code></pre></div>
<p>Transitive dependencies are of course added as well, which brings up the
possibility of version conflicts. Alembic will not add any new version of a
dependency if it is already on the classpath, and will warn about the possible
version conflict.</p>
<p>The <code>dependencies-added</code> function can be used to retrieve a sequence of the
dependencies you have added, so you can add them to your <code>project.clj</code> as
needed.</p>
<p><a href="https://github.com/pallet/alembic">Alembic</a> is in its infancy. Having lein
running in a classloader, off to the side as it were, will probably enable lots
more goodies. Look forward to your comments and suggestions, either in the
project&#39;s <a href="https://github.com/pallet/alembic">issues</a>, or on the
<a href="https://groups.google.com/forum/?fromgroups#!forum/clojure-tools">clojure-tools</a>
google group.</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Pallet training scheduled for March 14 and 15 at the Clojure/West Conference</title>
<link href="http://palletops.com//pallet-training-scheduled-for-march-14-15-at"/>
<updated>2011-12-13T00:00:00+00:00</updated>
<id>http://palletops.com//pallet-training-scheduled-for-march-14-15-at</id>
<content type="html"><div class="row">
<div class="span9 offset1">
<div class="alert-message block-message error">
<p>The Pallet Workshop at Clojure/West was cancelled. We
continue to offer on-site training.
<a href="mailto:[email protected]">Contact us</a> if you are
interested. </p>
</div>
</div>
</div>
<p><a href="http://www.regonline.com/Register/Checkin.aspx?EventID=1041359">Registration is now open!</a></p>
<p>We are very excited to announce that Clojure/West will be hosting a 2-day Pallet training session on March 14-15 with both Hugo Duncan and Toni Batchelli as instructors.&nbsp;</p>
<p><a href="http://clojurewest.org/">Clojure/West</a> will be held in San Jose on March 16-17 and <a href="http://clojurewest.org/">registration for the conference</a> is also open. Make sure you book your hotel rooms soon for an exceptional discount.</p>
<p>Below is the <a href="http://clojurewest.squarespace.com/training-pallet/">official announcement</a>:</p>
<p><span style="color: #626262; font-family: 'Lucida Sans Unicode', 'Lucida Grande', Tahoma, sans-serif; font-size: 12px; line-height: 21px;"> </span></p>
<p style="margin-bottom: 1em; margin-top: 0em;"><strong>Cost:&nbsp;</strong>$1200 (<a href="http://www.regonline.com/Register/Checkin.aspx?EventID=1041359"> <strong>Sign up before Jan 27th and get $200 off!</strong></a>)</p>
<p style="margin-bottom: 1em; margin-top: 0em;">Included: breakfast, lunch, breaks, power, wifi</p>
<p style="margin-bottom: 1em; margin-top: 0em;"><strong>Dates:</strong></p>
<ul style="list-style-type: square; margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2em;">
<li><a href="http://www.regonline.com/Register/Checkin.aspx?EventID=1041359">Wed Mar 14 - Thu Mar 15, 2012</a></li>
</ul>
<p style="margin-bottom: 1em; margin-top: 0em;"><strong>Instructors:</strong>&nbsp;Hugo Duncan, Antoni Batchelli</p>
<p style="margin-bottom: 1em; margin-top: 0em;">&nbsp;</p>
<p style="margin-bottom: 1em; margin-top: 0em;"><strong>Prerequisites:</strong></p>
<div>
<ul style="list-style-type: square; margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2em;">
<li>Basic knowledge of Clojure is assumed (this class will not teach Clojure)</li>
<li>Comfortable with installing and building open-source software.</li>
<li>Knowledge of configuration management systems is not assumed.</li>
<li>Bring your own laptop (computers are not provided).</li>
<li>You should have the following software installed prior to the class:
<ul style="list-style-type: square; margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2em;">
<li>Clojure 1.3</li>
<li>Preferred editor set up for Clojure</li>
<li>Leiningen</li>
</ul>
</li>
</ul>
</div>
<p style="margin-bottom: 1em; margin-top: 0em;"><strong>Course Description:</strong></p>
<p style="margin-bottom: 1em; margin-top: 0em;">Learn to use Pallet from the library's primary developers.</p>
<p style="margin-bottom: 1em; margin-top: 0em;">If you care about building infrastructure as code, for deployment&nbsp;locally on fixed infrastructure or to public and private clouds, then&nbsp;Pallet is the tool for you.</p>
<p style="margin-bottom: 1em; margin-top: 0em;">Pallet is a library for building infrastructure automation. Built on many of the principles of Clojure, Pallet uses functional programming techniques, such as composition, to support creating high level abstractions over different cloud providers, OS distros and versions,&nbsp;package managers and tasks. Using Pallet, you will code your infrastructure to directly express the components of your system, so that it can managed and scaled easily across OSs and cloud providers.</p>
<p style="margin-bottom: 1em; margin-top: 0em;">Pallet lets you:</p>
<ul style="list-style-type: square; margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2em;">
<li>Apply all your software development skills to managing your infrastructure.</li>
<li>Write re-usable infrastructure components, that can be used from development&nbsp;through to production, on local virtual machines, or on the cloud.</li>
<li>Make infrastructure and deployment an integral part of your applications.</li>
<li>Eliminate the low level work of maintaining the connections between the&nbsp;servers in your architecture by leveraging Pallet's first class support for&nbsp;discovering connection details at configuration time.</li>
</ul>
<p style="margin-bottom: 1em; margin-top: 0em;">What will you learn?</p>
<p style="margin-bottom: 1em; margin-top: 0em;">How to code your infrastructure in Pallet. The course will be hands-on. You will learn Pallet by starting and configuring virtual machines, on a real cloud, implementing some common components.</p>
<p style="margin-bottom: 1em; margin-top: 0em;">Topics:</p>
<ul style="list-style-type: square; margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2em;">
<li>Functional infrastructure: Learn how stateful infrastructure can be built&nbsp;using pure functional programming.</li>
<li>Actions: Pallet's actions provide a rich library of functions that form a&nbsp;language used to write code that will run on remote machines. Actions are&nbsp;designed to work across the whole range of operating systems supported by&nbsp;Pallet, giving you freedom to move between operating systems and versions.</li>
<li>Crates: Build high level abstractions by writing crates, which are clojure&nbsp;functions that call any mixture of actions or other crate functions. &nbsp;You&nbsp;are familiar with building abstractions using functions in Clojure, and the&nbsp;same techniques are used when you write crates in Pallet.</li>
<li>Phases: when configuring and running your infrastructure, there will be many&nbsp;operations you will wish to automate. &nbsp;We'll show you how Pallet's phases&nbsp;provide an open framework for you to automate as many tasks as you need,&nbsp;while taking full advantage of the composability of pallet.</li>
<li>Servers and groups: server-spec's in Pallet provide a mechanism for directly&nbsp;describing the configuration and operation of (software) server components&nbsp;in your architecture. group-spec's allow you to map the server-spec's to&nbsp;individual nodes. Using server-spec's, you will see how to code your&nbsp;infrastructure on a single vm, and then use the same server-spec's to deploy&nbsp;to a horizontally scaled cloud environment.</li>
<li>Stevedore: For some special cases, Pallet's actions may be too restrictive,&nbsp;and for these cases Pallet allows you to write script using clojure,&nbsp;enabling the use of all the rich data available about you infrastructure in&nbsp;arbitrary scripts.</li>
<li>Upcoming: Review the driving forces behind enhancements that will be coming&nbsp;to Pallet, and discuss how these will benefit you.</li>
</ul>
<p>&nbsp;</p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Pallet meetup at Clojure/Conj</title>
<link href="http://palletops.com//pallet-meetup-at-clojureconj"/>
<updated>2011-10-23T00:00:00+00:00</updated>
<id>http://palletops.com//pallet-meetup-at-clojureconj</id>
<content type="html"><p>We are trying to get together with all the Pallet users and lurkers that exist in the Clojure community a the <a href="http://clojure-conj.org/">Clojure/Conj</a> this November. We still don't know the details on where and at what date/time we'll be able to meet, but we will meet for sure.</p>
<p>We've setup a <a href="http://www.meetup.com/Pallet-Users-Group/events/38415062/">Pallet Users Meetup</a> to register RSVPs and also to communicate the specifics of this meetup once they're settled.&nbsp;</p>
<p>We're looking forward meeting you all!</p>
<p><a href="http://www.meetup.com/Pallet-Users-Group/events/38415062/">Please RSVP</a> so we know you're interested and we can plan accordingly!</p>
<p>&nbsp;</p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Create Hadoop clusters the easy peasy way with Pallet</title>
<link href="http://palletops.com//create-hadoop-clusters-the-easy-peasy-way-wit"/>
<updated>2011-07-28T00:00:00+00:00</updated>
<id>http://palletops.com//create-hadoop-clusters-the-easy-peasy-way-wit</id>
<content type="html"><p>Setting up a Hadoop cluster
<a href="http://hadoop.apache.org/common/docs/current/cluster_setup.html">is usually a pretty involved task</a>.
There are certain rules about how the cluster is to be
configured. These rules need to be followed strictly for the cluster
to work. For example, some nodes need to know how to talk to the other
nodes, and some nodes need to allow other nodes to talk to them. Go
ahead and check out the
<a href="http://hadoop.apache.org/common/docs/current/cluster_setup.html">official instructions</a>,
or this more detailed tutorial on
<a href="http://www.michael-noll.com/tutorials/running-hadoop-on-ubuntu-linux-multi-node-cluster/">setting up multi-node Hadoop clusters</a>. In
this article we describe a solution that will create a fully
functional hadoop cluster on any public cloud with very few steps, and
in a very flexible way.</p>
<p>We present <a href="https://github.com/pallet/pallet-hadoop"><code>pallet-hadoop</code></a>,
a library that builds a set of hadoop abstractions on top
<a href="https://github.com/pallet/pallet"><code>Pallet</code></a>.</p>
<p>One of the most defining aspects of <code>Pallet</code> is that it is a library,
not a service, and hence there is no server to install in your
network, just something that you embed in your code or use in your
scripts. Also, as a library, Pallet provides a set of abstractions to
make it easier for you to build cluster configurations on top of
it. These two aspects of Pallet are what has allowed us to provide a
solution to tame Hadoop cluster setups.</p>
<p>This work is a collaboration effort by
<a href="https://github.com/sritchie">Sam Ritchie (@sritchie09)</a>, who provided
tons of Hadoop insight and did most of the work on <code>pallet-hadoop</code>, and the
<a href="https://github.com/pallet">Pallet Team (@palletops)</a>, that provided
the <code>Hadoop Crate</code>.</p>
<p>Before we get into the details of how <code>pallet-hadoop</code> is implemented,
let&#39;s see how it works, by using the project
<a href="https://github.com/pallet/pallet-hadoop-example"><code>pallet-hadoop-example</code></a>
in GitHub.</p>
<h2>Build a Hadoop Cluster with Pallet-hadoop-example</h2>
<p>To start a hadoop cluster we will use a project called
<a href="https://github.com/pallet/pallet-hadoop-example"><code>pallet-hadoop-example</code></a>
that&#39;s hosted on github. That project&#39;s <code>README.md</code> file contains
<a href="https://github.com/pallet/pallet-hadoop-example">very detailed instructions</a>, which I&#39;ll summarize here.</p>
<ol>
<li><p>First we load pallet and pallet-hadoop at the REPL:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(use &#39;pallet-hadoop-example.core) (bootstrap)
```
</code></pre></div></li>
<li><p>Then we need to provide the credentials for pallet to connect to
EC2 (or any other cloud provider, really). You will need to have your
EC2 credentials available for this (how you identify yourself to the
cloud provider varies from provider to provider):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
user=&gt;; (def cloud-service
(compute-service &quot;aws-ec2&quot;
:identity &quot;&quot;
:credential &quot;&quot;))
```
</code></pre></div></li>
<li><p>Next we create a cluster. <code>pallet-hadoop-examples</code> provides a handy
function for this, which takes two parameters, the number of task
tracker nodes (slaves) and the memory devoted to each machine in the
cluster. The following will define a hadoop cluster with 2 <code>slave</code>
nodes and one <code>master</code> node (To keep things simple, the <code>master</code> node
of our example cluster will serve double duty as
<a href="http://wiki.apache.org/hadoop/JobTracker"><code>jobtracker</code></a> and
<a href="http://wiki.apache.org/hadoop/NameNode"><code>namenode</code></a>, while our
<code>slave</code> nodes will act as both
<a href="http://wiki.apache.org/hadoop/TaskTracker"><code>tasktrackers</code></a> and
<a href="http://wiki.apache.org/hadoop/DataNode"><code>datanodes</code></a>. These are the
four hadoop <code>roles</code> currently supported by <code>pallet-hadoop</code>.)</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
user=&gt; (def my-cluster (make-example-cluster 2 (* 4 1024)))
```
</code></pre></div></li>
<li><p>Now we are ready to instantiate our cluster on the cloud. For this
we just need to do:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
user=&gt; (create-cluster my-cluster cloud-service)
```
</code></pre></div></li>
</ol>
<p>And wait for it to come back.</p>
<ol>
<li><p>At this point, the cluster is all configured, and we should be able
to ssh into the jobtracker node. To find the IP address of the
jobtacker we can do the following:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
user=&gt; (jobtracker-ip cloud-service)
```
</code></pre></div></li>
</ol>
<p>There you go! You now have a fully functional hadoop cluster all set
up. To operate it, once you ssh into jobtracker, you just need to you
need to sudo as hadoop (<code>sudo su - hadoop</code>). The hadoop binaries are
found in <code>/usr/local/hadoop-0.20.2/</code>.</p>
<p>(To run your first MapReduce job on the cluster, see the &quot;Running Word Count&quot; section of <a href="https://github.com/pallet/pallet-hadoop-example"><code>pallet-hadoop-example</code> <code>README</code></a>.)</p>
<h2>Pallet-hadoop</h2>
<p><a href="https://github.com/pallet/pallet-hadoop"><code>Pallet-hadoop</code></a> is a library
built on top of pallet. Pallet provides a
<a href="https://github.com/pallet/pallet-apache-crates/blob/master/hadoop/src/pallet/crate/hadoop.clj"><code>hadoop-crate</code></a>
that takes care of the low level operation of hadoop: install it,
create the hadoop user with a preconfigured profile, create ssh
authorizations between nodes, write configuration files from a data
map, etc.</p>
<p><code>Pallet-hadoop</code> builds a set of abstractions on top of <code>pallet</code> and
the hadoop crate.</p>
<p>First, for each type of node, it defines what configuration phases
should be run for each role that a node plays. A node can play more
than one role at the same time, as we&#39;ll see later.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(def role-&gt;phase-map
{:default #{:bootstrap
:reinstall
:configure
:reconfigure
:authorize-jobtracker}
:namenode #{:start-namenode}
:datanode #{:start-hdfs}
:jobtracker #{:publish-ssh-key :start-jobtracker}
:tasktracker #{:start-mapred}})
```
</code></pre></div>
<p>For example, <code>jobtracker</code> is just like any other node, but
it creates and publishes its own public ssh key so that other nodes
can authorize it. This way, <code>jobtracker</code> can ssh to all the other
nodes (a requirement for a functioning hadoop cluster).</p>
<p>By default, each node bootstraps (setting basic configuration, e.g.
authorizing your own public ssh keys so you can ssh into each of the
nodes directly), installs and configures hadoop, and authorizes the
jobtracker.</p>
<p>Next it defines what will be done for each phase:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(defn hadoop-phases
&quot;Returns a map of all possible hadoop phases. IP-type specifies...&quot;
[{:keys [nodedefs ip-type]} properties]
(let [[jt-tag nn-tag]
(roles-&gt;tags [:jobtracker :namenode] nodedefs)
configure (phase
(h/configure ip-type nn-tag jt-tag properties))]
{:bootstrap automated-admin-user
:configure (phase (java :jdk)
(h/install :cloudera)
configure)
:reinstall (phase (h/install :cloudera)
configure)
:reconfigure configure
:publish-ssh-key h/publish-ssh-key
:authorize-jobtracker (phase (h/authorize-tag jt-tag))
:start-mapred h/task-tracker
:start-hdfs h/data-node
:start-jobtracker h/job-tracker
:start-namenode (phase (h/name-node &quot;/tmp/node-name/data&quot;))}))
```
</code></pre></div>
<p>These phases usually use the <code>hadoop crate</code> along with other crates in
<code>pallet</code>.</p>
<p>Next, it defines a function to create a <code>hadoop cluster spec</code>:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(defn cluster-spec
&quot;Generates a data representation of a hadoop cluster.
ip-type: `:public` or `:private`. (Hadoop keeps track of
jobtracker and namenode identity via IP address. This option toggles
the type of IP address used. (EC2 requires `:private`, while a local
cluster running on virtual machines will require `:public`.&quot;
[ip-type nodedefs &amp;amp; {:as options}]
{:pre [(#{:public :private} ip-type)]}
(merge {:base-machine-spec {}
:base-props {}}
options
{:ip-type ip-type
:nodedefs nodedefs}))
```
</code></pre></div>
<p>A cluster spec can take the following form:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(cluster-spec
:private
{:jobtracker (node-group [:jobtracker :namenode])
:slaves (slave-group 10)}
:base-machine-spec {:os-family :ubuntu
:os-version-matches &quot;10.10&quot;
:os-64-bit true
:min-ram (* 4 1024)}
:base-props {:hdfs-site
{:dfs.data.dir &quot;/mnt/dfs/data&quot;
:dfs.name.dir &quot;/mnt/dfs/name&quot;}
:mapred-site
{:mapred.local.dir &quot;/mnt/hadoop/mapred/local&quot;
:mapred.task.timeout 300000
:mapred.reduce.tasks 3
:mapred.tasktracker.map.tasks.maximum 3
:mapred.tasktracker.reduce.tasks.maximum 3
:mapred.child.java.opts &quot;-Xms1024m&quot;}})
```
</code></pre></div>
<p>In this example, we&#39;re defining a hadoop cluster that will use private
IP addresses for its communication, that will have two types of nodes:
a <code>jobtracker</code> node and <code>slave</code> nodes. <code>jobtracker</code> nodes will play
the roles of both <code>jobtracker</code> and <code>namenode</code>, while a <code>slave</code> will be
both a <code>datanode</code> and a <code>tasktracker</code>. There will be 10 slaves in this cluster.</p>
<p>Next, <code>:base-machine-spec</code> specifies on what type of hardware will be
used for all the nodes. This specifies a 64bit machine with 4GB of
RAM, running <code>Ubuntu 10.10</code>.</p>
<p><code>:base-props</code> provides the shared properties that we want to
customize. These are divided between <code>HDFS</code> properties (<code>:hdfs-site</code>)
and <code>MapReduce</code> properties (<code>:mapred-site</code>). These properties should
be self-explanatory.</p>
<p>Here are the full lists of options for
<a href="http://hadoop.apache.org/core/docs/r0.20.0/mapred-default.html">mapred</a>,
<a href="http://hadoop.apache.org/core/docs/r0.20.0/hdfs-default.html">hdfs</a>
and
<a href="http://hadoop.apache.org/core/docs/r0.20.0/core-default.html">core</a>.</p>
<h2>Future</h2>
<p>This work simplifies significantly the task of setting up a Hadoop
cluster, but also this is very much work in progress and we already
have plenty of ideas on how to provide the best Hadoop experience.</p>
<p><strong>Help us get there</strong> by sharing this post (see widgets
below) and by telling us about your use cases or any advice you think
would make this project rock even more, either by dropping by the #pallet
channel at <a href="http://freenode.net/irc_servers.shtml">freenode.net</a>, or
by emailing the <a href="mailto:[email protected]"><code>pallet</code> list</a> . </p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Zi, the Maven plugin in Clojure</title>
<link href="http://palletops.com//zi-the-maven-plugin-in-clojure"/>
<updated>2011-07-15T00:00:00+00:00</updated>
<id>http://palletops.com//zi-the-maven-plugin-in-clojure</id>
<content type="html"><p>YACMP doesn&#39;t trip off the tongue, so this clojure maven plugin is called <a href="http://bit.ly/zicljpops">Zi</a>, and it&#39;s written in clojure. Some highlights:</p>
<ul>
<li>lein style checkout projects -- develop your project&#39;s dependencies without repackaging them</li>
<li>no forking -- goals run in the maven process</li>
<li>can be installed globally -- some goals run without adding the plugin to the pom</li>
<li>written (mainly) in clojure -- can use all of clojure&#39;s expressive power and libraries</li>
</ul>
<h2>Why another maven plugin for clojure?</h2>
<p><a href="https://github.com/technomancy/leiningen">leiningen</a> and <a href="https://github.com/flatland/cake">cake</a> are both great tools for an ever expanding set of use cases, but there are still many reasons to fall back on maven.</p>
<p><a href="http://www.talios.com">Mark</a> has done a fantastic job with <a href="https://github.com/talios/clojure-maven-plugin">clojure-maven-plugin</a>, but it feels wrong coding in java to work with clojure code, and using clojure brings all of clojure&#39;s libraries within easy reach. Zi also works a little differently to clojure-maven-plugin.</p>
<h2>What&#39;s different</h2>
<p>The goals use a non-forked execution model -- they are executed within the maven process itself, which should make it faster.</p>
<p>The clojure compiler is available as a compiler plugin for maven-compiler-plugin (see Zi&#39;s pom for an example of this). The <code>compile</code> goal in Zi just extends maven-compiler-plugin to set the default language to clojure. It inherits the inclusion and exclusion mechanism, as well as the detection of out of date target files.</p>
<p>The plugin is designed to be &#39;fat&#39;, in that it comes with dependencies on <a href="http://bit.ly/ritzpops">ritz</a>, <a href="https://github.com/technomancy/swank-clojure">swank-clojure</a>, <a href="https://github.com/fogus/marginalia">marginalia</a>, etc, so the plugin can be installed globally and used against an maven based clojure project without explicitly adding zi as a plugin.</p>
<p>It doesn&#39;t have all the bells and whistles of clojure-maven-plugin yet, but it does have support for leiningen style checkouts.</p>
<p>Lein style checkouts allow you to develop your project&#39;s dependencies without having to re-jar them after each modification -- just symlink your lein projects in a project level <code>checkouts</code> directory. Support for maven based projects in <code>checkouts</code> is pending release of maven 3.0.4.</p>
<h2>So how do I use it?</h2>
<p>The <a href="http://bit.ly/zicljpops">Zi readme</a> has the details, bit here is an overview:</p>
<p>The plugin uses the <code>sourceDirectory</code> element from the <code>pom.xml</code>, and automatically translates any <code>/java</code> suffix to <code>/clojure</code>, which means it uses <code>src/main/clojure</code> by default.</p>
<p>To copy clojure source files to the output target directory, add the zi plugin, and add an execution for the <code>resource</code> goal.</p>
<p>To AOT compile, add an execution for the <code>compile</code> goal.</p>
<p>To start a <a href="http://bit.ly/ritzpops">ritz</a> server, <code>mvn zi:ritz</code></p>
<p>To start a <a href="https://github.com/technomancy/swank-clojure">swank-clojure</a> server, <code>mvn zi:swank-clojure</code>.</p>
<p>To generate <a href="https://github.com/fogus/marginalia">marginalia</a> documentation, <code>mvn zi:marginalia</code></p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Pallet 0.4.10 - environments, parallel lift and converge, and virtualbox too!</title>
<link href="http://palletops.com//pallet-0410-environments-parallel-lift-and-co"/>
<updated>2011-03-14T00:00:00+00:00</updated>
<id>http://palletops.com//pallet-0410-environments-parallel-lift-and-co</id>
<content type="html"><p>This week saw the release of 0.4.10.</p>
<p>The pace of pallet development has picked up over the last couple of months.
Much of this has been driven by
<a href="http://blog.gogrid.com/2011/02/08/agile-development-at-gogrid-with-pallet-and-jclouds-presentation/">our work at GoGrid</a>,
where we are applying pallet to automate fully functional GoGrid environments
for use by development teams for test and development. Thanks
<a href="htp://gogrid.com">GoGrid</a>!</p>
<p>The 0.4.x cycle has seen us switch to gitflow and to frequent releases to avoid
dependence on SNAPSHOTS. Personally, this has made development much more
enjoyable - hopefully it makes life easier for users of pallet too.</p>
<h2>0.4.10 Release</h2>
<p>Major changes since 0.4.0 include parallel converges and lifts, support for
vmfest, and environments.</p>
<p>Parallel converge ensures that the wait when starting nodes is minimised,
executing requests for all nodes to be created in parallel. Parallel lift
applies each phase across all nodes in parallel. Phases still run sequentially
(running each phase waits for all nodes to complete the previous
phase). Parallel converge and lift are not the default yet, but will be in
0.5.0.</p>
<p>To try out parallel lift and converge, add the following to your config.clj:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
:environment {:algorithms
{:lift-fn
pallet.core/parallel-lift
:converge-fn
pallet.core/parallel-adjust-node-counts}}
```
</code></pre></div>
<p>Which brings us to environments. Environments are a powerful way of injecting
data into your crates, and provide a customisation mechanism, as seen above. An
:environment can be specified at the top level of the defpallet in config.clj,
or at the individual service provider level (same level as :provider), or in the
actual call to lift and converge. As an example use case, here is the
environment I use for running live tests in virtualbox via vmfest:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
:environment
{:phases
{:bootstrap (fn [request]
(pallet.resource.package/package-manager
request :configure
:proxy &quot;http://192.168.1.37:3128&quot;))}
:proxy &quot;http://192.168.1.37:3128&quot;
:mirror {:apache &quot;http://apache.mirror.iweb.ca/&quot;}
:image {:min-ram 256 :bridged-network &quot;en1: AirPort&quot;}}
```
</code></pre></div>
<p>This example extends the bootstrap phase of all nodes to add a proxy for the
package manager, adds a proxy for remote-file operations, selects a mirror for
apache downloads, and specifies a default template for new nodes.</p>
<p>To access arbitrary data from the environment, use pallet.environment/get-for.</p>
<p>Finally, vmfest is Toni Batchelli&#39;s great new lib for using VirtualBox from
clojure. Toni is simplifying the setup before announcing this more generally,
but it works very well, and is now my default development and testing setup for
pallet. If you want to give it a try, give tbatchelli a shout on #pallet in
freenode IRC. <a href="https://github.com/tbatchelli/vmfest">vmfest is on github</a>.</p>
<p>For full details, check the <a href="https://github.com/pallet/pallet/wiki/ReleaseNotes">release notes</a>.</p>
<h2>Upcoming</h2>
<p>Expect a post with a more in depth example of using environements soon. There
are some other interesting features in the pipeline, including the use of spot
instances on EC2 - stay tuned...</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Working with Non-Cloud Servers in Pallet</title>
<link href="http://palletops.com//working-with-non-cloud-servers-in-pallet"/>
<updated>2010-12-06T00:00:00+00:00</updated>
<id>http://palletops.com//working-with-non-cloud-servers-in-pallet</id>
<content type="html"><p>If have tried to configure local vm&#39;s or non-virtualised servers in
<a href="http://palletops.com">Pallet</a>, you might well have given up. The recent
<a href="http://palletops.com/pallet-release-030-agile-cloud-development">0.3 release</a>
has made working with existing servers much easier, however.</p>
<p>Pallet now has a <code>node-list</code> provider, which you can use to specify the tags and
address of the machine that you want to manage.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(require &#39;pallet.compute.node-list)
(def service
(pallet.compute/compute-service
&quot;node-list&quot;
:node-list [(pallet.compute.node-list/make-node
&quot;hostname&quot; &quot;tag&quot; &quot;192.168.2.23&quot; :ubuntu)])
```
</code></pre></div>
<p>Use <code>defnode</code> and <code>lift</code> to configure the machines based on the tag.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(require &#39;pallet.core)
(pallet.core/defnode tag
:configure (pallet.resource/phase
(pallet.resource.package/package &quot;wget&quot;)))
(pallet.core/lift tag)
```
</code></pre></div>
<p>Pallet has it&#39;s roots in <a href="http://jclouds.org/">jclouds</a>, and was originally
meant to work directly with a cloud provisioning api. Adding the abitility to
work with a fixed list of nodes was a simple case of wiring up a subset of
pallet&#39;s capabilities. The <code>converge</code> command has the capability of starting and
stopping nodes, and is obviously not supported by <code>node-list</code>.</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: How to Configure your Credentials in Pallet</title>
<link href="http://palletops.com//how-to-configure-your-cloud-credentials-in-pa"/>
<updated>2010-11-18T00:00:00+00:00</updated>
<id>http://palletops.com//how-to-configure-your-cloud-credentials-in-pa</id>
<content type="html"><p>The recent
<a href="http://palletops.com/pallet-release-030-agile-cloud-development">0.3.0 release</a>
of <a href="https://github.com/hugoduncan/pallet">pallet</a> added a new way to configure
your cloud credentials, using a clojure file, <code>~/.pallet/config.clj</code>.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(defpallet
:providers
{:aws {:provider &quot;ec2&quot;
:identity &quot;key&quot;
:credential &quot;secret-key&quot;}
:rs {:provider &quot;cloudservers&quot;
:identity &quot;username&quot;
:credential &quot;key&quot;}})
```
</code></pre></div>
<p>The provider key, <code>:aws</code> and <code>:rs</code> above, has to be unqiue, but you can have
multiple accounts for the same provider. The provider string is the
<a href="http://jclouds.org/">jclouds</a> provider string, and can be found with a call to
<code>pallet.compute/supported-providers</code>, or using the lein plugin,
<code>pallet lein providers</code> (in which case you can see if you have the appropriate
jclouds provider jars set up correctly). Pallet uses jcloud&#39;s terminology,
<code>identity</code> and <code>credential</code>, but your cloud provider will probably use different
terms for these.</p>
<p>To create a compute service object from this file, that you can pass to <code>lift</code>
or <code>converge</code>, you use <code>pallet.compute/compute-service-from-config</code>. By default,
the first provider entry will be used, and you can specify an alternative
provider by passing the key to the function.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(pallet.compute/compute-service-from-config &quot;rs&quot;)
```
</code></pre></div>
<p>The <code>config.clj</code> file is read automatically by the lein and cake plugins, and
in lein, you can switch between providers using the <code>-P</code> command line option.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` bash
lein pallet -P rs nodes
```
</code></pre></div>
<h2>Admin User</h2>
<p>At the same time, the <code>config.clj</code> file can be used to set the admin user, that
is used by pallet to run the node configuration. By default in pallet, this is
set to your current username and uses your id_rsa key.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(defpallet
:admin-user
{:username &quot;admin&quot;
:private-key-path &quot;/path/to/private-key&quot;
:public-key-path &quot;/path/to/public-key&quot;})
```
</code></pre></div>
<p>Another possibility, which could be useful if you are working in a team
environment, is to set the admin user in the project code.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(ns pallet.config
(:require [pallet.utils :as utils]))
(def admin-user (utils/make-user &quot;admin&quot;))
```
</code></pre></div>
<h2>settings.xml</h2>
<p>The <code>config/clj</code> file is an alternative to the existing <code>settings.xml</code>.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` xml
&lt;settings&gt;
&lt;profiles&gt;
&lt;profile&gt;
&lt;id&gt;rackspacedev&lt;/id&gt;
&lt;activation&gt;
&lt;activeByDefault&gt;false&lt;/activeByDefault&gt;
&lt;/activation&gt;
&lt;properties&gt;
&lt;jclouds.compute.provider&gt;
cloudservers
&lt;/jclouds.compute.provider&gt;
&lt;jclouds.compute.identity&gt;
username
&lt;/jclouds.compute.identity&gt;
&lt;jclouds.compute.credential&gt;
key
&lt;/jclouds.compute.credential&gt;
&lt;/properties&gt;
&lt;/profile&gt;
&lt;profile&gt;
&lt;id&gt;aws&lt;/id&gt;
&lt;activation&gt;
&lt;activeByDefault&gt;true&lt;/activeByDefault&gt;
&lt;/activation&gt;
&lt;properties&gt;
&lt;jclouds.compute.provider&gt;
ec2
&lt;/jclouds.compute.provider&gt;
&lt;jclouds.compute.identity&gt;
key
&lt;/jclouds.compute.identity&gt;
&lt;jclouds.compute.credential&gt;
secret key
&lt;/jclouds.compute.credential&gt;
&lt;/properties&gt;
&lt;/profile&gt;
&lt;/profiles&gt;
&lt;/settings&gt;
```
</code></pre></div>
<p>To create a compute service object from <code>settings.xml</code>, you use
<code>pallet.compute/compute-service-from-settings</code>. The default is determined by the
active profile. You can specify a different profile by passing the profile&#39;s id
to the function.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text">``` clojure
(pallet.compute/compute-service-from-settigs &quot;rackspacedev&quot;)
```
</code></pre></div></content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>Article: Pallet release 0.3.0</title>
<link href="http://palletops.com//pallet-release-030-agile-cloud-development"/>
<updated>2010-10-15T00:00:00+00:00</updated>
<id>http://palletops.com//pallet-release-030-agile-cloud-development</id>
<content type="html"><p>What better way to start this blog, than by announcing the latest release of <a href="http://github.com/hugoduncan/pallet">Pallet</a>. Perhaps the biggest news around this release is that the pallet community is growing rapidly, and the 0.3.0 release has seen great input from many contributors. I really appreciate all the ideas and contributions!</p>
<p>A particular shout out to David Santiago and Charles Duffy. David has contributed a new <a href="https://github.com/hugoduncan/pallet/blob/pallet-0.3.0/src/pallet/crate/postgres.clj">Postgres crate</a>, and has put together a <a href="http://github.com/davidsantiago/cake-pallet">cake plugin</a> for pallet. Charles has much improved the bash <a href="https://github.com/hugoduncan/pallet/blob/pallet-0.3.0/resources/stevedore/hashlib.bash">hashlib</a> used to propogate state during lifts on a node.</p>
<p><a href="http://cemerick.com">Chas Emerick</a> has been promoting Pallet as part of his talk at the first <a href="http://clojure-conj.org/">clojure-conj</a> conference, and followed that up with a <a href="http://cemerick.com/2010/11/02/continuous-deployment-of-clojure-web-applications/">blog post</a> and <a href="https://github.com/cemerick/clojure-web-deploy-conj">project code</a>. The post has an fantastic screen cast on using pallet together with Hudson.</p>
<p>Toni Batchelli (aka <a href="http://disclojure.org/">disclojure</a>) has given a couple of talks: a <a href="http://www.scribd.com/doc/39275742/Pallet-Bacug">great technical introduction</a>, and a <a href="http://www.scribd.com/doc/40391319/Pallet-Gogrid">slightly higher level overview</a>. He has also vastly improved the <a href="http://github.com/hugoduncan/pallet-examples">pallet examples</a>.</p>
<p>Finally, Adrian Cole of <a href="http://jclouds.org">jclouds</a>, the foundation of pallet, has been lavish in his support, even giving a <a href="http://oredev.org/2010/speakers/adrian-cole">workshop on pallet</a> at <a href="http://oredev.org/2010">&Oslash;redev</a> in Sweden!</p>
<h2>What's new</h2>
<p>Some highlights from the <a href="https://github.com/hugoduncan/pallet/wiki/ReleaseNotes">release notes</a>.</p>
<ul>
<li>Added ~/.pallet/config.clj as a way of configuring your credentials, and the default admin user. The admin user can also be configured in project code in the pallet.config namespace.</li>
<li>Added a "node-list" provider, which simplifies working with pre-existing vms and servers that are not managed through a cloud.</li>
<li>Added a tomcat task, that can provide a near zero config way of deploying a war file.</li>
<li>cent-os and amzn-linux support are vastly improved.</li>
</ul>
<p>Look out for more, in-depth, posts on the new features.</p>
<h2>Looking ahead</h2>
<p>One of the first things we will be doing in the 0.4.0-SNAPSHOT is splitting out the crates into a separate repository. Hopefully this will be the first step in creating an ecosystem of pallet crates. Stay tuned for further posts on this.</p>
<h2>Trying it</h2>
<p>The release is available on <a href="http://clojars.org/org.cloudhoist/pallet">clojars</a>.</p>
<p>Both #pallet on freenode IRC, which is a bustling place these days, and the <a href="http://groups.google.com/group/pallet-clj">mailing list</a> are great places to ask, should you have any questions.</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<!-- news -->
<entry>
<title>News: Run clojure projects on Docker with lein-uberimage</title>
<link href="http://palletops.com//blog/lein-uberimage"/>
<updated>2014-08-07T00:00:00+00:00</updated>
<id>http://palletops.com//blog/lein-uberimage</id>
<content type="html"><p>We built a lein plugin to make it easy to run clojure projects in Docker containers. This article first introduces containers and Docker, and then shows how you can effortlessly create such containers for your Clojure projects with <code>lein uberimage</code>. </p>
<p><image src="/images/docker-large-h-trans.png" alt="Docker logo" class="img-responsive"></p>
<h2>Why Containers and Why Docker</h2>
<p>A container is a lighweight form of computer virtualization. Containers run within a host, and a host can run many containers concurrently. Each container is functionally equivalent to a computer loaded with a full OS, but behind the scenes all containers in the same host are sharing the same host resources: kernel, memory, IO, and disk.</p>
<p>There are many ways of virtualization technologies used today, VirtualBox, Xen (used by Amazon Web Services) and vmware to name a few, but what makes containers special is their lightweight nature. Each container uses very little resources (disk, memory, cpu) and they all boot orders of magnitude faster than a virtual machine or
a computer.</p>
<p>Containers are very convenient for both development and production environments. For development, they provide a fast and simple way to run different and isolated runtime environments for each application. In production, they are very fast and efficient, with the added bonus that containers in production always match the ones in development; the same exact containers are used during all app&#39;s lifecycle.</p>
<p><a href="http://www.docker.com">Docker</a> is a novel container technology for Linux that provides a very low friction access to containers. Containers have been around for a while, and the Linux kernel has provided key container technologies for a while already. Docker wraps all these kernel features under a high level API and defines a standard container and image formats using union filesystems. To make containers easy to share and distribute, Docker also provides public and private image repositories. All these features have brought containers to the masses.</p>
<p>Although Docker is currently Linux only, you can use it on OSX installing <a href="http://boot2docker.io">boot2docker</a></p>
<p>For a more detailed introduction to Docker, check out this video on <a href="http://sysadmincasts.com/episodes/31-introduction-to-docker">sysadmincasts.com</a>.</p>
<h2>Docker images</h2>
<p>Each container is a process tree that is started from an existing image. These images contain a filesystem with the files necessary to run your application. Sometimes this entails a linux distribution and sometimes just one statically linked binary. The common practice in the Docker world is to build a custom image for each type of service you intend to run. This contrasts with other forms of virtualization where you start the VMs from a base image and then you configure them with the required software. In the case of VMs, the time it takes a VM to boot until it is ready to run your application is measured in minutes, whereas in Docker a container can boot in sub-second times.</p>
<h2>Building Docker images with uberimage</h2>
<p><code>lein-uberimage</code> builds a Docker image for clojure projects. The generated images contain a base operating system, a java runtime, and your project&#39;s <code>uberjar</code>. Once this image is built, you can instantiate as many containers as you need using this image, each container running your <code>uberjar</code>.</p>
<p>At the time of writing this, <code>lein-uberimage</code> requires that the project builds with <code>lein uberjar</code> and that the resulting jar can be run via <code>java -jar &lt;your-uberjar&gt;.jar</code>. This means your <code>project.clj</code> will have to have a <code>:main</code> entry pointing to the <code>-main</code> function in your code. This restriction will be removed in the future.</p>
<p>To build the Docker image for your project, run the following in your project&#39;s root:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage
</code></pre></div>
<p><code>uberimage</code> will call lein&#39;s <code>uberjar</code> to build the standalone jar file. Then it will build a new image with <code>Ubuntu 14.04</code>, <code>OpenJDK 7</code> and the freshly built jar. The image is also configured to run your jar file on boot. This task will return the <code>uuid</code> for this image.</p>
<p>From this image you just created, you can spawn as many containers as you need. The most basic way to start a container is this:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>docker run &lt;my-image-uuid&gt;
</code></pre></div>
<p>In most cases, your app won&#39;t be useful unless you can access it via known ports, and by default, Docker does not expose any ports of a container, so you need to tell Docker to expose those ports. Since you will be running many containers on the same host you need to ensure that not two containers are bound to the same port. For example, if your application listens on port 3000, you need to tell Docker to bind the container&#39;s port 3000 to any unbound port in the host, e.g. 8080:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>docker run -p 8080:3000 &lt;my-image-uuid&gt;
</code></pre></div>
<p>Once the container has started, just head over to <code>http://&lt;docker-host&gt;:8080</code> to access your newly deployed service. If you launch a second container with the same image, you cannot bind it to the same host port (8080 in this case) and you should instead map it to port 8081 <code>docker run -p 8081:3000 ...</code>.</p>
<h2>Trying It Out</h2>
<ul>
<li><a href="https://docs.docker.com/installation/#installation">Install</a> Docker.</li>
<li>Clone this <a href="https://github.com/tbatchelli/compojure-example">example clojure project</a>.</li>
<li>On the project root, run <code>lein uberimage</code> and copy the supplied image uuid</li>
<li>At the shell, run <code>docker run -d -p 3000:3000 &lt;image-uuid&gt;</code></li>
<li>Open the browser and head on to <code>http://&lt;docker-host&gt;:3000</code>. Docker-host could be <code>localhost</code> in case you are in linux, or the boot2docker IP address if you are using boot2docker.</li>
<li>Run <code>docker run -d -p 3001:3000 &lt;image-uuid&gt;</code> to run a second instance and check <code>http://&lt;docker-host&gt;:3001</code> with your browser. Notice the different IP address.</li>
</ul>
<h2>Additional Options</h2>
<p>In case the supplied OS and java versions are not what you&#39;re looking for, you can supply your own base image to <code>lein-uberimage</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage -b &lt;your-image-with-jvm&gt;
</code></pre></div>
<p>And in case your Docker is not locally installed on the default port or it is remote, you can override its url:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>lein uberimage -H http://&lt;host&gt;:&lt;port&gt;
</code></pre></div>
<h2>Concluding remarks</h2>
<p>There is not much more to it for now. This is our first stab at helping clojurians leverage containers. Please submit bugs and ideas to our project&#39;s <a href="https://github.com/palletops/lein-uberimage/issues">Issues</a> or drop by our chatroom <a href="http://webchat.freenode.net/?channels=pallet">#pallet</a> on freenode.</p>
<p><code>lein-uberimage</code> is build on top of <a href="https://github.com/palletops/clj-docker.">clj-docker</a>, a clojure wrapper over docker.</p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>News: Hugo Duncan talking about Pallet at EuroClojure 2012</title>
<link href="http://palletops.com//news/Euroclojure-2012-Pallet-Talk/"/>
<updated>2012-06-11T00:00:00+00:00</updated>
<id>http://palletops.com//news/Euroclojure-2012-Pallet-Talk/</id>
<content type="html"><p>Hugo Duncan gave a <a href="http://vimeo.com/45562554">talk on pallet basics</a> at
<a href="http://euroclojure.com/2012/">EuroClojure 2012</a>.</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>News: Toni Batchelli talking about Pallet at Clojure/West 2012</title>
<link href="http://palletops.com//news/Clojure-West-2012-Pallet-Talk/"/>
<updated>2012-05-17T00:00:00+00:00</updated>
<id>http://palletops.com//news/Clojure-West-2012-Pallet-Talk/</id>
<content type="html"><p>Toni Batchelli gave a <a href="http://bit.ly/KweuSg">great talk on pallet basics</a> at
<a href="http://clojurewest.org/">Clojure/West 2012</a>.</p>
</content>
<author>
<name>Hugo Duncan</name>
<uri></uri>
</author>
</entry>
<entry>
<title>News: MostlyLazy interview on Pallet at Clojure Conj 2011</title>
<link href="http://palletops.com//news/MostlyLazy-podcast-interview/"/>
<updated>2012-02-03T00:00:00+00:00</updated>
<id>http://palletops.com//news/MostlyLazy-podcast-interview/</id>
<content type="html"><p>Last year we attended <a href="http://clojureconj.org">Clojure Conj</a> and
<a href="http://cemerick.com">Chas Emerick</a> interviewed us for his
<a href="http://mostlylazy.com">MostlyLazy podcast</a>. Chas published
<a href="http://mostlylazy.com/2012/02/03/episode-0-0-4-antoni-batchelli-and-hugo-duncan-at-clojure-conj-2011/">this interview today</a>,
and he has also done a terrific job at summarizing the topics covered
in the accompanying blog post.</p>
<p><a href="http://mostlylazy.com/2012/02/03/episode-0-0-4-antoni-batchelli-and-hugo-duncan-at-clojure-conj-2011/">Head over to Mostly Lazy</a> to listen to this 23min interview.</p>
</content>
<author>
<name>Antoni Batchelli</name>
<uri></uri>
</author>
</entry>
<entry>
<title>News: Pallet Training at Clojure/West is $1000 until Jan 27th</title>
<link href="http://palletops.com//news/pallet-training-early-bird/"/>
<updated>2012-01-18T00:00:00+00:00</updated>
<id>http://palletops.com//news/pallet-training-early-bird/</id>
<content type="html"><div class="row">
<div class="span9 offset1">
<div class="alert-message block-message error">
<p>The Pallet Workshop at Clojure/West was cancelled. We
continue to offer on-site training.
<a href="mailto:[email protected]">Contact us</a> if you are
interested. </p>
</div>
</div>
</div>
<p><a href="http://clojurewest.org">Clojure/West</a> has decided to offer Early Bird
pricing until