Build Your Own PaaS with Docker - مهندسی داده · 2015-04-21 · Build Your Own PaaS with...

Post on 20-May-2020

8 views 0 download

Transcript of Build Your Own PaaS with Docker - مهندسی داده · 2015-04-21 · Build Your Own PaaS with...

BuildYourOwnPaaSwithDocker

TableofContents

BuildYourOwnPaaSwithDocker

Credits

AbouttheAuthor

AbouttheReviewers

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmore

Whysubscribe?

FreeaccessforPacktaccountholders

Preface

Whatthisbookcovers

Whatyouneedforthisbook

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Errata

Piracy

Questions

1.InstallingDocker

WhatisDocker?

DockeronUbuntuTrusty14.04LTS

UpgradingDockeronUbuntuTrusty14.04LTS

Userpermissions

DockeronMacOSX

Installation

UpgradingDockeronMacOSX

DockeronWindows

Installation

UpgradingDockeronWindows

DockeronAmazonEC2

Installation

Openports

UpgradingDockeronAmazonEC2

Userpermissions

DisplayingHelloWorld

Summary

2.ExploringDocker

TheDockerimage

TheDockercontainer

TheDockercommand-lineinterface

TheDockerRegistryHub

Browsingrepositories

Exploringpublishedimages

Summary

3.CreatingOurFirstPaaSImage

TheWordPressimage

Movingfromthedefaults

Ourobjective

Preparingforcaching

Raisingtheuploadlimit

Plugininstallation

Makingourchangespersist

HostingimagesourcesonGitHub

PublishinganimageontheDockerRegistryHub

Automatedbuilds

Summary

4.GivingContainersDataandParameters

Datavolumes

Mountingahostdirectoryasadatavolume

Mountingadatavolumecontainer

Backingupandrestoringdatavolumes

Creatingadatavolumeimages

Datavolumeimage

Exposingmountpoints

TheDockerfile

HostingonGitHub

PublishingontheDockerRegistryHub

Runningadatavolumecontainer

Passingparameterstocontainers

Creatingaparameterizedimage

Summary

5.ConnectingContainers

Manuallyconnectingcontainers

Exploringthecontentsofadatavolumecontainer

ConnectingcontainersusingDockerCompose

InstallingDockerCompose

BasicDockerComposecommands

Service

Usingtheruncommand

Usingthescalecommand

SettingupourPaaSwithDockerCompose

ConnectingcontainersusingCrane

InstallingCrane

Usage

Configuration

Summary

6.ReverseProxyRequests

Explainingtheproblem

Findingasolution

Implementingthesolution

ImplementationwithHAProxy

InstallingHAProxy

ConfiguringHAProxy

AddingmoredomainstoHAProxy

ImplementationwithNginx

InstallingNginx

ConfiguringNginx

AddingmoredomainstoNginx

Automatingtheprocessofmappingdomains

Summary

7.DeploymentonOurPaaS

Theproblemwithourcurrentsetup

Thetools/servicesavailable

Dokku–Docker-poweredmini-Heroku

Installation

CreatingasampleDokkuapp

HowDokkuworks

Thereceiveprocess

Dokkuplugins

Dokkudomainsplugin

Dokku-docker-options

VolumepluginforDokku

Dokku-link

MariaDBpluginforDokku

SettingupaWordPressappwithDokku

Startingmultipleapps

AddingadomaintoDokku

MorenotesonDokku

Summary

8.What’sNext?

WhatisaTwelve-Factorapp?

Flynn

Deis

Rocket

Orchestrationtools

Summary

Index

BuildYourOwnPaaSwithDocker

BuildYourOwnPaaSwithDockerCopyright©2015PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.NeithertheauthornorPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:April2015

Productionreference:1010415

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78439-394-6

www.packtpub.com

CreditsAuthor

OskarHane

Reviewers

DonaldSimpson

LawrenceTaylor

CommissioningEditor

SarahCrofton

AcquisitionEditor

RebeccaYoue

ContentDevelopmentEditor

MerwynD’Souza

TechnicalEditors

NarsimhaPai

MaheshRao

CopyEditors

DiptiKapadia

VikrantPhadke

ProjectCoordinator

NehaBhatnagar

Proofreaders

TingBaker

SimranBhogal

Indexer

MariammalChettiyar

ProductionCoordinator

ManuJoseph

CoverWork

ManuJoseph

AbouttheAuthorOskarHaneisafullstackdeveloper,with15yearsofexperienceinthedevelopmentanddeploymentofwebapplications.Duringthisperiod,hemostlyworkedwithstart-upsandsmall,fast-movingcompanies.Heisthecofounderofseveralcompaniesandhasbeenworkingasanindependentcontractorforthepastfewyears.Thesedays,OskarworkswithNeo4j,theworld’sleadinggraphdatabase,wherehespendsmostofhistimeonthefrontend,writingJavaScript.

HelivesinSwedenwithhiswifeanddaughter.Heenjoysprogrammingaswellasallkindsofsportsandoutdooractivities,suchashuntingandfishing.

AbouttheReviewersDonaldSimpsonisanexperiencedbuildmanager,softwaredeveloper,andinformationtechnologyconsultantbasedinScotland,UK.

Hespecializesinhelpingorganizationsimprovethequalityandreducethecostofsoftwaredevelopmentthroughtheadoptionofcontinuousintegrationandcontinuousdeliverybestpractices.

HehasdesignedandimplementedfullyautomatedcodeandenvironmentbuildsolutionsforarangeofclientsandAgileprojects.

YoucanfindoutmoreaboutDonaldonhiswebsite(www.donaldsimpson.co.uk).

LawrenceTaylorisarmedwithaPhDinmathematics.Hehas7yearsofexperienceindevelopingsoftwareinavarietyofsectors,fromfinancetotravel.Charredbyhisnumber-theoreticpast,heisdrawntotheabstractionsandtechniquesrequiredtodesignandbuildextensiblesoftwaresystems.

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<service@packtpub.com>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

PrefaceDockerisanopensourceprojectwithahigh-levelAPIthatprovidessoftwarecontainerstorunprocessesinisolation.PackaginganappinacontainerthatcanrunonanyLinuxserver(aswellasonOSXandWindows)helpsdevelopersfocusondevelopingtheappinsteadofserversetupsandotherDevOpsoperations.

WhatthisbookcoversChapter1,InstallingDocker,takesyouthroughtheDockerinstallationprocesstostartacontainer.

Chapter2,ExploringDocker,givesyouaninsightintohowDockerworksandtheterminologyusedandintroducespublicimages.

Chapter3,CreatingOurFirstPaaSImage,showsyouhowtocreateyourowncustomDockerimagethatwillbeapartofyourPaaS.

Chapter4,GivingContainersDataandParameters,teachesyouaboutthedatastoringalternativesavailableandhowtopassparameterstoyourPaaScontainers.

Chapter5,ConnectingContainers,showsyouhowtomanuallyconnectcontainersinordertoformacompleteplatform,andintroducestwotoolsthatgiveyoumorecontrolovermulticontainerplatforms.

Chapter6,ReverseProxyRequests,explainstheproblemandprovidesasolutiontohavingmultiplecontainersonthesamehost,wheremorethanonehostshouldbereachableonthesameport.

Chapter7,DeploymentonOurPaaS,takesyouthroughtheprocessofdeployingcodetoyourPaaS.Here,youlearnhowtocreateyourownmini-HerokuwithDokku.

Chapter8,What’sNext?,introducesafewprojectsthatareintheirearlystagesandlookpromisingforthefutureofaDockerbasedPaaS.

WhatyouneedforthisbookAPC/laptoprunningOSX,Linux,orWindowsInternetconnection

WhothisbookisforThisbookisintendedforthosewhowanttolearnhowtotakefulladvantageofseparatingservicesintomodulecontainersandconnectingthemtoformacompleteplatform.Youmayhave,perhaps,heardofDockerbutneverinstalledorusedit;or,youmayhaveinstalleditandrunafullstackcontainer,notseparatingservicesinmodulecontainersthatconnect.Ineithercase,thisbookwillgiveyoualltheinsightsandknowledgerequiredtorunyourownPaaS.

ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Aftersomedependentimagesaredownloaded,weshouldbeabletoseeourrunningcontainerwhenweexecutedocker.ps.”

Ablockofcodeissetasfollows:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8">

<title>Hello</title>

</head>

<body>

<h1>Firstedit!</h1>

</body>

</html>

Anycommand-lineinputoroutputiswrittenasfollows:

curl-sSLhttps://get.docker.com/ubuntu/|sudosh

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:“OpentheFinderwindowandnavigatetoyourApplicationsfolder;locateboot2dockeranddouble-clickonit.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<feedback@packtpub.com>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<questions@packtpub.com>,andwewilldoourbesttoaddresstheproblem.

Chapter1.InstallingDockerInthischapter,wewillfindoutwheretodownloadandhowtoinstallDockeronvariousoperatingsystems.SomebasicDockercommandswillbeusedsothatwecanverifywhethertheinstallationwassuccessfulandtointeractwithDockerfortheveryfirsttime.

Thefollowingtopicsarecoveredinthischapter:

WhatisDocker?DockeronUbuntuTrusty14.04LTSDockeronMacOSXDockeronWindowsDockeronAmazonEC2

Thisbookwilltakeyouthroughallthesteps,frominstallingDockertorunningyourownPlatformasaService(PaaS)sothatyoucanpushyourcodewithouthavingtothinkaboutinfrastructureorserverprovisioning.

Thethemeofthisbookwillbetocreateamodularwebapplicationusinganisolatedwebserverandadatabase.

WhatisDocker?OnDocker’swebsite,http://www.docker.com,thefollowingdefinitionisprovidedforDocker:

“Dockerisanopenplatformfordevelopersandsysadminstobuild,ship,andrundistributedapplications.”

WhatthismeansinamorepracticalsenseisthatDockerisawayofenclosingservicesinisolatedenvironments,calledcontainers,sothattheycanbepackagedwithalltheyneedintermsoflibrariesanddependenciesandthedevelopercanbecertainthattheservicewillrunwhereverDockerruns.

DockeronUbuntuTrusty14.04LTSTheOS,flavorandversion,whereit’seasiesttoinstallDockerisinUbuntuTrusty14.04LTS.Thisisaprettyquicktasksincewecanusethebuilt-inpackagemanagerapt-get.

NoteNotethatDockeriscalleddocker.iohereandjustdockeronotherplatformssinceUbuntu(andDebian)alreadyhasapackagenameddocker.

Firstweopenaterminalandexecutethesecommandsonebyone:

sudoapt-getupdate

sudoapt-getinstalldocker.io

source/etc/bash_completion.d/docker.io

Here,wefirstupdatethelistsofthepacketmanagerapt-getinordertogetinformationaboutallthepackages,versions,anddependenciesthatareavailable.ThenextlineactuallyinstallsDocker,andafterthat,weenableUbuntutotab-completeourDockercommands.

Whenyou’vedonethiswithouterrors,runsudodocker.ioversionjusttoverifythatitworksasexpected.

NoteNotethatthisinstallsthelatestreleasedUbuntupackageversion,whichmightnotnecessarilybethelatestreleasedDockerversion.

InordertohavethelatestversionfromanalternativeDocker-maintainedrepository,wecanexecutethefollowingcommand:

curl-sSLhttps://get.docker.com/ubuntu/|sudosh

ThisaddsanalternativerepositorymaintainedbytheDockerteamandinstallsDockerforyouasamuchmoreupdatedversionthantheonethatcomesviatheUbunturepository.NotethattheDockerpackageisnamedlxc-dockerwhenitisinstalledthisway.ThecommandusedtorunDockercommandsisstilldocker.

UpgradingDockeronUbuntuTrusty14.04LTSTocheckanddownloadupgrades,allyouhavetodoistoexecutethiscommandinaterminal:

sudoapt-getupdate&&sudoapt-getupgrade

UserpermissionsForconvenience,it’spreferredtoaddourusertothesystem’sDockerusergroupsothatwecancontrolDockerwithoutusingsudo.ThisgivesouruserpermissiontoexecuteDockercommands.

ReplaceUSERwithyourusernamebeforeyourunthecode:

sudogpasswd-aUSERdocker

Youmighthavetologoutandloginagainforittowork.Whenyouareloggedbackin,rundockerpstoverifythattherearenopermissionproblems.

NoteMoredetailedinformationcanbefoundintheofficialinstallationguideathttps://docs.docker.com/installation/ubuntulinux/.

DockeronMacOSXTobeabletouseDockeronMacOSX,wehavetoruntheDockerserviceinsideavirtualmachine(VM)sinceDockerusesLinux-specificfeaturestorun.Wedon’thavetogetfrightenedbythissincetheinstallationprocessisveryshortandstraightforward.

InstallationThereisanOSXinstallerthatinstallseverythingweneed,thatis,VirtualBox,boot2docker,andDocker.

VirtualBoxisavirtualizerinwhichwecanrunthelightweightLinuxdistribution,andboot2dockerisavirtualmachinethatrunscompletelyintheRAMandoccupiesjustabout27MBofspace.

NoteThelatestreleasedversionoftheOSXinstallercanbefoundathttps://github.com/boot2docker/osx-installer/releases/latest.

Now,let’stakealookathowtheinstallationshouldbedonewiththefollowingsteps:

1. DownloadtheinstallerbyclickingonthebuttonnamedBoot2Docker-1.3.0.pkgtogetthe.pkgfile,asshowninthefollowingscreenshot:

2. Double-clickonthedownloaded.pkgfileandgothroughwiththeinstallationprocess.

3. OpentheFinderwindowandnavigatetoyourApplicationsfolder;locateboot2dockeranddouble-clickonit.Aterminalwindowwillopenandissueafewcommands,asshownhere:

ThisrunsaLinuxVM,namedboot2docker-vm,thathasDockerpre-installedinVirtualBox.TheDockerserviceintheVMrunsindaemon(background)mode,andaDockerclientisinstalledinOSX,whichcommunicatesdirectlywiththeDockerdaemoninsidetheVMviatheDockerRemoteAPI.

4. Youwillseeascreensimilartothefollowingscreenshot,whichtellsyoutosetsomeenvironmentvariables:

Weopenupthe~/.bash_profilefileandpastethreelinesfromouroutput,asfollows,attheendofthisfile:

exportDOCKER_HOST=tcp://192.168.59.103:2376

export.DOCKER_CERT_PATH=/Users/xxx/.boot2docker/certs/boot2docker-vm

exportDOCKER_TLS_VERIFY=1

ThereasonwhywedothisissothatourDockerclientknowswheretofindtheDockerdaemon.IfyouwanttofindtheIPinthefuture,youcandosobyexecutingtheboot2dockeripcommand.Addingtheprecedinglineswillsetthesevariableseverytimeanewterminalsessionstarts.Whenyou’redone,closetheterminalwindow.Then,openanewwindowandtypeecho$DOCKER_HOSTtoverifythattheenvironmentvariableissetasitshouldbe.YoushouldseetheIPandportyourboot2dockerVMprinted.

5. TypedockerversiontoverifythatyoucanusetheDockercommand.Anoutputthatlookssimilartothelastfewlinesoftheprecedingscreenshotwillmeanthatwehavesucceeded.

UpgradingDockeronMacOSXSinceDockerisrelativelynew,therecouldbealothappeningineveryupdate,somakesurethatyoucheckforupdatesonaregularbasis.Fromtimetotime,gototheMacOSXinstallerdownloadpageandcheckwhetherthereisanupgradeavailable.Ifthereis,executethesecommandstoupdateit:

boot2dockerstop

boot2dockerdownload

boot2dockerstart

DockeronWindowsJustaswehavetoinstallaLinuxvirtualmachinewheninstallingDockerinOSX,wehavetodothesameinWindowsinordertorunDockerbecauseoftheLinuxkernelfeaturesthatDockerbuildson.OSXhasanativeDockerclientthatdirectlycommunicateswiththeDockerdaemoninsidethevirtualmachine,butthereisn’toneavailableforWindowsyet.ThereisanativeWindowsversionoftheDockerclientcoming,butitwillnotbeavailablebythetimethisbookispublished.

InstallationThereisaWindowsinstallerthatinstallseverythingweneedinordertorunDocker.Forthis,gotohttps://github.com/boot2docker/windows-installer/releases/latest.

Now,let’stakealookathowtheinstallationshouldbedonewiththehelpofthefollowingsteps:

1. Clickonthedocker-install.exebuttontodownloadthe.exefile,asshowninthefollowingscreenshot:

2. Whenthedownloadiscomplete,runthedownloadedinstaller.Followthroughtheinstallationprocess,andyouwillgetVirtualBox,msysGit,andboot2dockerinstalled.

3. GotoyourProgramFilesfolderandclickonthenewlyinstalledboot2dockertostartusingDocker.Ifyouarepromptedtoenterapassphrase,justpressEnter.

4. TypedockerversiontoverifythatyoucanusetheDockercommand.

UpgradingDockeronWindowsAnewsoftwarechangesoftenandtokeepboot2dockerupdated,invokethesecommands:

boot2dockerstop

boot2dockerdownload

boot2dockerstart

DockeronAmazonEC2Throughoutthisbook,IwilluseanAmazonEC2instance,andsinceitisasuperbplacetohostyourPaaS,Iwillrecommendthatyoudothesame.

EC2standsforElasticComputeCloud,anditisaninfrastructuretypeofservice.AmazonEC2offersvirtualserversthatarecreatedandavailablewithinaminuteoforderingthem.

NoteAmazonhasinstancesnamedt[x].microthatyoucanuseforfreefor750hourspermonth.Youcanreadmoreaboutthemathttp://aws.amazon.com/free.

AmazonhasitsownLinuxnamedAmazonLinuxAMIthatcanbeusedtorunDocker.

InstallationLet’sseehowtheinstallationisdonewiththefollowingsteps:

1. Createanaccountathttp://aws.amazon.comandgotoAmazon’sCreateEC2InstanceWizardathttps://console.aws.amazon.com/ec2/v2/home?#LaunchInstanceWizard.

Thenextstepsareshowninthescreenshotasfollows:

2. ClickonCommunityAMIsinthemenuontheleft-handsideandselectthelatestamzn-ami-pv.Makesurethatyouselectthepvversionandnotthehvmversionsothatyouhaveavirtualizationthatismorestableandhaslessoverhead,asshownhere:

3. Whenit’stimetochooseaninstancetype,youcanchooset1.microort2.microfornowiftheyareavailable.Themicroinstancesareverylimitedintheirperformance,butsincetheyareavailableinthefreeusagetierinsomeregionsandthisisnotforalivesiteatthemoment,wecanusethem.ClickonNext:ConfigureInstanceDetailsandthenclickontheReviewandLaunchbutton,asshowninthefollowingscreenshot:

4. VerifyallthedetailsonthesummarypageandclickontheLaunchInstancebutton.5. Youwillbepromptedwhetheryouwanttouseanexistingkey-pairorcreateanew

one.IfthisisyourfirsttimecreatinganAmazonEC2instance,youwillwanttocreateanewkey-pair.Thismakesiteasytosecurelyconnecttoyourinstances.

6. Downloadthenewkey-pair,moveittoyour~/.ssh/folder,andremovethe.txtextension.

7. It’salsoimportanttosetthecorrectuserpermissionsonthefileorSSHwillrefusetouseit.

InLinuxoronaMac,thisishowtheterminalcommandtodothislooks:

mv~/Downloads/amz.pem.txt~/.ssh/amz.pem

chmod600~/.ssh/amz.pem

OnWindows,savethekeyanywhereanduseatoolsuchasPuTTYgentoconvertittoa.ppkfile,soyoucanuseitwhenconnectingusingPuTTY.

8. Youwillbepromptedtochooseasecuritygroupforyourinstance.Pickthedefaultonesincethiswon’tbeaproductionserver.Whenit’stimetouseaproductionserver,wemightwanttoaddmoresecuritytoourinstance.

9. Nowwe’reupandrunning!Let’sconnecttoit.ClickontheViewInstancesbuttonandselectyournewlycreatedinstanceinthelist,asshownhere:

10. Inthebottomofthescreen,youcanseesomeinformationabouttheinstance.YoushouldbelookingforthepublicDNSinformation.Thisishowitshouldlook:

ec2-54-187-234-27.us-west-2.compute.amazonaws.com

11. OnaLinuxorMac,openaterminalandconnecttoit:

sshec2-user@ec2-54-187-234-27.us-west-2.compute.amazonaws.com-i

~/.ssh/amz.pem

Thescreenshotisdisplayedasfollows:

Weusetheec2-useruserthatisthedefaultuserforAmazon’sLinuxinstances,andamz.pemisthekeywedownloadedearlier.ReplacetheURLwithyourpublicDNSinformationfromthelaststep.

Whenaskedwhetheryouwanttocontinuebecauseofanunknownhost,typeyes.

OnWindows,usePuTTYandmakesurethatyouhavespecifiedtheconvertedprivatekeyfromstep4inthePuTTYAuthtab.

12. Onceyouareconnectedtotheinstance,installDocker:

sudoyumupdate

sudoyuminstall-ydocker

sudoservicedockerstart

13. Totestwhetherit’sworkingasexpected,typedockerversionandmakesurethere’snoerror.Youshouldseeafewlineswiththeclientversion,APIversion,andsoon.

OpenportsAmazon’sdefaultsecuritypolicyistoblockthedefaultportsusedtoexposeservicesfromDocker,sowehavetochangethis.

WegobacktotheEC2dashboardandclickontheSecurityGroupsoptioninthemenuSelectthesecuritygroupthatyourEC2instanceusesandselecttheInboundtabDockerusesportsinarangefrom49000-50000,soweaddaruleforthis,asshowninthefollowingscreenshot:

UpgradingDockeronAmazonEC2UpgradinganAmazonLinuxAMIinstanceisaseasyasitisforUbuntu.Typesudoyumupdateandconfirmwhetherthere’sanupdatewaiting.Thiscommandwilllistalltheavailableupdatesanduponyourconfirmation,installthem.

UserpermissionsDockerrequirescommandstoberunbyusersinthedockerusergroup.Forconvenience,weaddourusertotheDockergroupsothatwecancontrolDockerwithoutusingsudo:

sudogpasswd-aec2-userdocker

Youmighthavetologoutandloginagainforittowork.Whenyouareloggedbackin,rundockerpstoverifythattherearenopermissionproblems.Youshouldseearowofcapitalizedwords,suchasCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES.

DisplayingHelloWorldNowthatwehaveDockerrunningonamachineofourchoice,it’stimetomakeDockerworkforus.HereareafewverybasiccommandsthatwecanuseforsomebasicinteractionwiththeDockerdaemon.

Inthenextchapter,alltheconceptsandphrasesusedinDockerwillbeexplained:

dockerps:Thisliststherunningcontainersdockerps-a:Thislistsallthecontainers,bothrunningandexiteddockerimages:Thislistslocal(downloadedandlocallycreated)imagesdockerrun:Thiswilllaunchanewinstancecontainerfromanimagedockerstop:Thisisusedtostopacontainer

Let’strythefirstoneinthescreenshotshownbelow:

Asexpected,wehavenothingrunningyet.

Launchingacontainerisaseasyasdockerrun[image][command].Iftheimagedoesn’texistlocally,DockerwilldownloaditfromtheDockerRegistryHubandlaunchyourcontainerwhenit’sdownloaded.

Thefollowingstepsaredisplayedasfollows:

TypethefollowingcommandinaterminaltolaunchacontainerthatprintsthestringHello,letmeoutofhereandthenexits:

dockerrunoskarhane/helloecho"Hello,letmeoutofhere"

Thisisnotveryuseful,butwejustranacommandinUbuntuinsidethecontainer.

Ifwetypedockerpsagain,wecanseethatwestillhavenorunningcontainerssinceweexitedtheonewejuststartedstraightaway.Tryusingdockerps-ainstead,andtrydockerimages.

SummaryInthischapter,welearnedthatDockercanbeusedonmostoperatingsystemsandthattheinstallationprocessvariesalotdependingontheOS.WehadourfirstinteractionwiththeDockerdaemonandlaunchedourfirstcontainerinDocker.Eventhoughallthecontainerdidwaswriteacommand,that’showeasyitistostartandrunsomethinginsideaguestoperatingsystem.

Wehavealsointroducedthethemethatshowswhatthisbookisallabout,runningamulticontainerwebappofawebservercontainerandaMySQLcontainer:yourownPaaS.

Inthenextchapter,wewillfurtherexploreDocker,itsterminology,andthecommunityaroundit.

Chapter2.ExploringDockerAfterreadingthischapter,youwillfindyourselfmorecomfortabletalkingaboutandusingDocker.Thefollowingtopicswillbecoveredhere:

TheDockerimageTheDockercontainerTheDockercommand-lineinterfaceTheDockerRegistryHub

YouwillfindthesetopicsimportantwhenbuildingyourPaaS,andyouwilluseandinteractwithallofthemthroughoutthisbook.

TheDockerimageInthebeginning,itcanbehardtounderstandthedifferencebetweenaDockerimageandaDocker(orLinux)container.

ImaginethatourLinuxkernelislayerzero.WheneverwerunaDockerimage,alayerisputontopofourkernellayer.Thisimage,layerone,isaread-onlyimageandcannotbechangedorcannotholdastate.

ADockerimagecanbuildontopofanotherDockerimagethatbuildsontopofanotherDockerimageandsoon.Thefirstimagelayeriscalledabaseimage,andallotherlayersexceptthelastimagelayerarecalledparentimages.TheyinheritallthepropertiesandsettingsoftheirparentimagesandaddtheirownconfigurationintheDockerfile.

DockerimagesareidentifiedbyanimageID,whichisa64-characterlonghexadecimalstring,butwhenworkingwithimages,wewillalmostneverreferenceanimagebythisIDbutusetheimagenamesinstead.TolistallourlocallyavailableDockerimages,weusethedockerimagescommand.Takealookatthefollowingimagetoseehowtheimagesarelisted:

Imagescanbedistributedwithdifferentversionsforustochoosefrom,andthemechanismforthisiscalledtags.Theprecedingscreenshotillustratesthiswiththeneo4jimagethathasalatestanda2.1.5tag.Thisishowthecommandusedtopullaspecifictaglooks:

dockerpullubuntu:14.04

dockerpullubuntu:12.02

TheDockercontainerADockercontaineriscreatedthemomentweexecutedockerrunimagename.Awriteablelayerisaddedontopofalltheimagelayers.ThislayerhasprocessesrunningontheCPUandcanhavetwodifferentstates:runningorexited.Thisisthecontainer.WhenwestartacontainerwiththeDockerruncommand,itenterstherunningstateuntilit,forsomereason,stopsbyitselforisstoppedbyusandthenenterstheexitedstate.

Whenwehaveacontainerrunning,allthechangeswemaketoitsfilesystemarepermanentbetweenstartandstop.Rememberthatchangesmadetothecontainer’sfilesystemarenotwrittentotheunderlyingDockerimage.

Wecanstartasmanyinstancesofrunningcontainersaswewantfromthesameimage;theywillalllivesidebyside,totallyseparatedbyeachother.Allthechangeswemaketoacontainerarelimitedtothatcontaineronly.

Ifchangesaremadetothecontainer’sunderlyingimage,therunningcontainerisunaffectedandthereisnoautoupdatehappening.Ifwewanttoupdateourcontainertoanewerversionofitsimage,wehavetobecarefulandmakesurethatwehavesetupthedatastructureinacorrectway,otherwisewehavetheriskoflosingallthedatainthecontainer.Laterinthisbook,Iwillshowyouwheretokeepimportantdatawithouttheriskoflosingit.

Thecorrespondingscreenshotisshownasfollows:

A64-characterlonghexadecimalstringcalledcontainerIDidentifiesDockercontainers.ThisIDcanbeusedwheninteractingwiththecontainer,anddependingonhowmanycontainerswehaverunning,wewillusuallyonlyhavetotypethefirstfourcharactersofthecontainerID.Wecanusethecontainernameaswell,butit’softeneasiertotypethebeginningoftheID.

TheDockercommand-lineinterfaceThecommandlineinterfaceiswherewecommunicatewiththedaemonusingtheDockercommand.TheDockerdaemonisthebackgroundprocessthatreceivesthecommandsthataretypedbyus.

Inthepreviouschapter,weranafewDockercommandstostartandstopcontainersaswellastolistcontainersandimages.Now,wearegoingtolearnafewmorethatwillhelpuswhenhandlingcontainersforourPaaS,asfollows:

dockerlogs<container-ID|name>:EverythingthatiswrittentotheSTDOUTcontainerswillendupinthefilethatcanbeaccessedviathiscommand.Thisisaveryhandywaytooutputinformationfromwithinacontainer,asshownhere:

dockerexport<container-ID|name>:Ifyouhaveacontainerthatholdsdatathatyouwanttoexport,thisisthecommandtobeused.ThiscreatesatararchiveandsendsittoSTDOUT:

dockercpCONTAINER:PATHHOSTPATH:Ifyoudon’twantthewholefilesystemfromacontainerbutjustonedirectoryorafile,youcanusedockercpinsteadofexport,asshowninthefollowingscreenshot:

TheDockerRegistryHubOneimportantpartofDocker’spopularityisitscommunityandtheeasewithwhichyoucanshare,find,andextendDockerimages.ThecentralplaceforthisistheDockerRegistryHubthatcanbefoundathttps://hub.docker.com/.

BrowsingrepositoriesHere,wecansearchand,inmanyways,browseforimagerepositoriestofindexactlywhatwe’reafter.Ifwetakealookatthepopularones,wewillseewhatothersareusingthemost.

IfweclickontheUbunturepository,wewillseelotsofinformationabouttheimage,thetagsthatareavailable,users’comments,thenumberofstarsithas,andwhenitwasupdated.

Thescreenshotisdisplayedasfollows:

Ifweclickonataginthemainview,we’llseesomethingcalledtheDockerfile.Thisistheimagedescriptionthatrunswhenanimageisbeingcreated.Furtherinthisbook,we’llwriteourown.

Ifyou’reinterestedinanimageintheDockerhub,IrecommendthatyoureadtheInformation/READMEaswellastheotherusers’comments.Often,youwillfindvaluableinformationtherethatwillhelpyoutochoosetherightimageandshowyouhowtorunitinthewaythemaintainingdeveloperintendedto.

Often,youwillfindimagesthatalmostfityourneedssincemostimagesarequitegeneral,butasadeveloper,youmightneedspecificsettingsorservicesinstalled.

ExploringpublishedimagesTaketheofficialWordPressDockerimage,forexample(https://registry.hub.docker.com/_/wordpress/).You’llfinditontheDockerhub’sbrowsepageoryoucansearchforit.

Let’sforgetabouttheseshortcomingsfornowandseewhattheinformationpagesays:

ThisimagereadsthesettingsfromtheDockercontainer’senvironmentvariables.This

meansthatimagehastobestartedwiththeenvironmentvariablesinjectedusingthedockerrun–ecommand,oryoucan--linkanothercontainertoitthatinjectsthesevariables.We’lldiscusscontainerlinkingmorelaterinthisbook.

Let’sseewhatwe’llgetifweweretopullthisimage.ClickonthelinktotheDockerfileintheapachedirectory:

FROMphp:5.6-apache

RUNa2enmodrewrite

#installthePHPextensionsweneed

RUNapt-getupdate&&apt-getinstall-ylibpng12-devlibjpeg-dev&&rm-rf

/var/lib/apt/lists/*\

&&docker-php-ext-configuregd--with-png-dir=/usr--with-jpeg-dir=/usr

\

&&docker-php-ext-installgd

RUNdocker-php-ext-installmysqli

VOLUME/var/www/html

ENVWORDPRESS_VERSION4.1.1

ENVWORDPRESS_UPSTREAM_VERSION4.1.1

ENVWORDPRESS_SHA115d38fe6c73121a20e63ccd8070153b89b2de6a9

#upstreamtarballsinclude./wordpress/sothisgivesus

/usr/src/wordpress

RUNcurl-owordpress.tar.gz-SLhttps://wordpress.org/wordpress-

${WORDPRESS_UPSTREAM_VERSION}.tar.gz\

&&echo"$WORDPRESS_SHA1*wordpress.tar.gz"|sha1sum-c-\

&&tar-xzfwordpress.tar.gz-C/usr/src/\

&&rmwordpress.tar.gz

COPYdocker-entrypoint.sh/entrypoint.sh

#grr,ENTRYPOINTresetsCMDnow

ENTRYPOINT["/entrypoint.sh"]

CMD["apache2-foreground"]

Ok,weseethatitbuildsonDebianWheezyandinstallsApache2,PHP5,andsomeotherstuff.Afterthat,itsetsabunchofenvironmentvariablesandthendownloadsWordPress.

WeseeafewlinesstartingwiththecommandCOPY.ThismeansthatfilesareshippedwiththeDockerimageandarecopiedtotheinsideofthecontainerwhenit’sstarted.Thisishowthedocker-apache.conffileshippedwiththeWordPressimagelooks:

<VirtualHost*:80>

DocumentRoot/var/www/html

<Directory/var/www/html>

AllowOverrideall

</Directory>

</VirtualHost>

#vim:syntax=apachets=4sw=4sts=4srnoet

TheprecedinglineofcodetellsApachewheretolookforfiles.

Whataboutthedocker-entrypoint.shfile?

TheENTRYPOINTkeywordtellstheDockerdaemonthatifnothingelseisspecified,thisfileshouldbeexecutedwheneverthecontainerisrun.Itisasifthewholecontainerisanexecutablefile.

Ifwetakealookatwhatispresentinsidethisfile,we’llseethatitbasicallysetsuptheconnectiontotheMySQLdatabaseandconfigures.htaccessandWordPress:

#!/bin/bash

set-e

if[-z"$MYSQL_PORT_3306_TCP"];then

echo>&2'error:missingMYSQL_PORT_3306_TCPenvironmentvariable'

echo>&2'Didyouforgetto--linksome_mysql_container:mysql?'

exit1

fi

ThefirstthingthatisdoneistocheckwhethertheuserhassetenvironmentvariablesfortheMySQLconnection.Ifnot,itexitsandwritessomeinfotoSTDERR.

Whydon’tyoutryandseewhetheryoucantriggertheMySQLerrorthatwriteserror:missingMYSQL_PORT_3306_TCPenvironmentvariabletotheSTDERR,asfollows:

dockerrun–-namesome-wordpress–dwordpress

The--namesome-wordpresscommandnamesthecontainer,sowecanreferenceitby

thisnamelater.Also,the–dargumenttellsthecontainertorunindetachedmode,whichmeansthatitdoesnotlistentocommandsfromwherewestarteditanymore.ThelastwordpressargumentisthenameoftheDockerimagewewanttorun.

Ifwecheckthelogforournewcontainer,we’llseewhatthescreenshotshowsus:theexpectederrormessage.

Let’srunaMySQLcontainerandseewhetherwecangetittowork.Navigatetohttps://registry.hub.docker.com/_/mysql/inordertogettotheofficialMySQLdockerrepositoryontheDockerregistryhub.Here,itstatesthatinordertostartaMySQLinstance,weneedtoinvokedockerrun—namesome-mysql-eMYSQL_ROOT_PASSWORD=mysecretpassword-dmysqlintheshell.Sincewearedoingthisforeducationalpurposesatthemoment,wedon’thavetochooseastrongrootuserpassword.Aftersomedependentimagesaredownloaded,weshouldbeabletoseeourrunningcontainerwhenweexecutedockerps.Ifwedo,havealookattheinstallationlogbyrunningdockerlogssome-mysql,asshownhere:

Great,nowwehavearunningMySQLcontainerthatisneededtostartaWordPressinstance.Let’sstartanewWordPressinstancewiththeMySQLlinkinplace:

dockerrun--namesome-wordpress--linksome-mysql:mysql–p80-dwordpress

The--linkparameterexposesthesome-mysqlcontainers’environmentvariables,interface,andexposedportsviatheenvironmentvariablesinjectedtothesome-wordpresscontainer.

Toopenaportthatcanbereachedfromtheoutside,port80isexposedviathe–p80parameter.

IfyougetanerrormessagesayingErrorresponsefromdaemon:Conflict,Thenamesome-wordpressisalreadyassignedtoa11c101cacaf.,youhavetodelete(orrename)thatcontainertobeabletoassignsome-wordpresstoacontaineragain.Youneedtogivethenewcontaineranewnameordeletetheold(failing)WordPresscontainer.Invokedockerrmsome-wordpresstodeletetheoldcontainerusingthedesiredname.

Whenyouhavethecontainerrunning,invokedockerpscommandtofindoutwhichofourportswasassignedtothecontainer’sprivateport80.

Wecaneitherlookattheportscolumninthecontainerlist,orwecaninvokedockerportsome-wordpress80toexplicitlyfindit,asshownhere:

Inmycase,itwasport49155.

EnteryourDockerhosts’ip:portinyourwebbrowsertoseewhetheryoucanreachit.Ifyou’reonyourlocalcomputerrunningWindowsorOSX,youcanfindyourDockerIPbyinvokingboot2dockerip.Ifyou’reonalocalLinux,127.0.0.1shouldbefine.

I’mdoingthisonAmazonEC2,soIhavetogototheEC2ManagementconsoletogetmypublicIPorpublicDNS.

Pointyourwebbrowsertohttp://yourip:yourport(inmycase,http://myamazon-dns.com:49155)andyoushouldbepresentedwiththis:

NoteThedefaultAmazonAWSsecuritypolicyistoblockthedefaultDockerpublicports,sowehavetochangethisintheSecurityGroupssectionintheEC2dashboard.SeetheDockeronAmazonEC2sectioninChapter1,InstallingDocker,forhowtodothis.

Wonderful,itworks!

SummaryTheDockerimagecanbeseenasaread-onlytemplateforcontainers,specifyingwhat’ssupposedtobeinstalled,copied,configured,andexposedwhenacontainerisstarted.

WelearnedmoreabouthowwecaninteractwiththeDockerdaemonandwithindividualDockercontainerstoreadlogs,copyfiles,andexportthecompletefilesystem.

TheDockerhubwasintroducedandwelookedatwhattheofficialWordPressDockerimageconsistedofandhowtheyconfiguredtheOSintheDockerfileaswellasinanENTRYPOINTfiletosomeextent.

WedownloadedandrantheWordPressimagethatfailedasexpected,andwefixeditbylinkingtherequiredMySQLcontainertoit.

Inthenextchapter,wewillcreateaDockerfileandpublishaDockerimagetotheDockerregistryhubsothatwehaveawaytogetourcustomizedDockerimagestowhereverwedecidetoplaceourPaaS.

Chapter3.CreatingOurFirstPaaSImageYouarenowreadytowriteyourownDockerfiles,publishthemtotheDockerRegistryHub,andcreatecontainersforthem.Inthischapteryouwill:

BuildyourownimageontopofanotherHostyourDockerfilesinyourGitHubaccountPublishanimageontheDockerRegistryHub

TheWordPressimageForthisproject,wearegoingtousetheofficialWordPressDockerimageasabase,whichhasApache2asitswebserver.

NoteIfyouplantohostsiteswithalotoftraffic,IwouldrecommendusinganimagebasedonNginxinsteadofApache2asthewebserver.IhavehadgreatsuccessrunningWordPresssiteswithNginxandthememcachedplugin,WP-FFPC.Itcanbeabittrickytosetup,andthat’swhyit’soutofthescopeofthisbook.

Firstofall,let’srunaMySQLcontainerandaWordPresscontainerandlinktothemtoseewhathappens:

dockerrun--namesome-mysql-eMYSQL_ROOT_PASSWORD=mysecretpassword-d

mysql

dockerrun--namesome-wordpress--linksome-mysql:mysql-d-p80wordpress

The–p80optiontellsDockertoexposetheprivateport80totheouterworld.Tofindoutwhichpublicportisboundtotheprivateport80,rundockerpscommandandlookintheportscolumnorinvokethedockerport<container-ID|name>80command.

Thescreenshotisshownbelow:

Inmycase,thepublicportis49154.EnterthefullURLintheformofhttp://public_ip:public_portinyourwebbrowser.I’mdoingthisonanAmazonEC2instance.Igetapublicdomain,whichishttp://ec2-54-187-234-27.us-west-2.compute.amazonaws.com:49154inmycase.

Thescreenshotisdisplayedbelow:

TheWordPressinstallationpagewelcomesus,whichmeansthattheWordPressandtheMySQLcontainersareworkingproperly.

MovingfromthedefaultsNowwehaveadefaultinstallationofWordPressrunonApache2.SomeWordPresspluginsrequireyoutomakechangestothewebserver’sconfiguration.Howcanwedothat?WhatifwewanttoeditsomeofthefilesintheWordPressdirectory?

ThefirstthingweneedtodoistogetourowncopyoftheofficialWordPressrepositorysothatwecanexploretheDockerfile.ThecurrentURLthatisusedtogettherepositoryishttps://github.com/docker-library/wordpress.ClickonthislinkfromtheWordPressrepopageontheDockerRegistryHub.

Youcanclone,fork,orjustdownloadthesourceforthisDockerimage.Itdoesn’tmatterhowyougetitbecausewe’renotgoingtouseitlateron.Thisimageisfortestingandexploringpurposes.IusedmyEC2instancetodothis.

Openthefileinanytexteditortoviewitscontent.Ifyouare—likeme—usingtheterminal,youcanuseviapache/Dockerfiletoopenitinthevifileeditor.ThecurrentDockerfilefortheofficialWordPressimagelookslikethis:

FROMphp:5.6-apache

RUNa2enmodrewrite

#installthePHPextensionsweneed

RUNapt-getupdate&&apt-getinstall-ylibpng12-devlibjpeg-dev&&rm-rf

/var/lib/apt/lists/*\

&&docker-php-ext-configuregd--with-png-dir=/usr--with-jpeg-dir=/usr

\

&&docker-php-ext-installgd

RUNdocker-php-ext-installmysqli

VOLUME/var/www/html

ENVWORDPRESS_VERSION4.1.1

ENVWORDPRESS_UPSTREAM_VERSION4.1.1

ENVWORDPRESS_SHA115d38fe6c73121a20e63ccd8070153b89b2de6a9

#upstreamtarballsinclude./wordpress/sothisgivesus

/usr/src/wordpress

RUNcurl-owordpress.tar.gz-SLhttps://wordpress.org/wordpress-

${WORDPRESS_UPSTREAM_VERSION}.tar.gz\

&&echo"$WORDPRESS_SHA1*wordpress.tar.gz"|sha1sum-c-\

&&tar-xzfwordpress.tar.gz-C/usr/src/\

&&rmwordpress.tar.gz

COPYdocker-entrypoint.sh/entrypoint.sh

#grr,ENTRYPOINTresetsCMDnow

ENTRYPOINT["/entrypoint.sh"]

CMD["apache2-foreground"]

Thisimageusesthephp:5.6-apacheimageasabaseanddownloadsandextractsWordPress4.1to/usr/src/wordpress.ThenitaddsanENTRYPOINTandstartsApache2intheforeground.

OurobjectiveTomakethisWordPressimageuseableformorethandemopurposes,weneedtomodifytheDockerfileinthreeways.Ourobjectivesareasfollows:

PreparingApacheforcaching(throughtheWPSuperCacheplugin)RaisingtheuploadlimitinbothPHPandApache2Installingtwoplugins:WPSuperCacheandWPMailSMTP

PreparingforcachingTherearetwosmallstepstobeperformedtoobtainwebsitecachingthroughWPSuperCache—weneedtoenablethemod_headersandmod_expiresmodulesinApache2.

Online5intheDockerfile,youcanseeRUNa2enmodrewrite.Thea2enmodcommandenablesmodulesinApache2,andmodulesaredisabledbythea2dismodcommand.Enablingourdesiredmodulesisaseasyasappendingthemtothatline:

RUNa2enmodrewriteexpiresheaders

Wemakethoseedits,buildanewimage,andseewhathappens.Ittakesalongtimetobuildtheseimages,sincePHPisbuiltfromsource.Whatwearelookingforarelinesthatstatethatourmodulesareenabled.Theywillshowupforjustafewsecondsinthebuildprocess.

YouinitiateabuildfromaDockerfilebyexecutingthis:

dockerbuild–tmod-wp.

The–tmod-wpcommandsetsthenameofournewimagetomod-wp.

Thescreenshotisshownbelow:

Thebuildshouldrunthroughthewholeprocesswithoutanyerrors,andthenthepreparationforthecachepluginisdone.

RaisingtheuploadlimitThedefaultuploadsizeislimitedto2MBbyPHP.Thislimitistoolow,especiallysincebloggingfrommobilephonesispopularandthesizeofamobilephonephotoorvideoisoftenbiggerthanthis.Iwouldliketohavetheoptiontouploadvideosdirectlyonmyblogs,andtheycanbeupto32MB.

Forthislimittoberaised,weneedtochangethelimitfortwoparametersinthePHPconfigurationfile:upload_max_filesizeandpost_max_size.

Lookingatthephp:5.6-Apacheimage,whichisthebaseimageoftheWordPressimage,DockerfileweseethatitrunsDebianandPHPconfigurationfilesaresupposedtobeinthe/usr/local/etc/php/conf.d/directory.Thismeansthatifweaddafiletothatdirectory,itshouldgetreadinandparsed.

NoteTheDockerfileforPHP5.6canbefoundathttps://github.com/docker-library/php/blob/master/5.6/Dockerfile.

Toverifythattheuploadlimitisaslowassaidbefore,IstartedandinstalledanunmodifiedWordPresscontainer.ThenIclickedontheAddnewmediabutton.

Itsaysthattheuploadlimitis2MB.

Let’saddaconfigurationfilenamedupload-limit.initotheconfigurationdirectory,andaddthetwoparameterstothefile.

Thesecommands,allofwhichshouldbeonasingleline,areaddedtoourDockerfilerightabovethelinewemodifiedwhenpreparingApacheforcaching:

RUNtouch/usr/local/etc/php/conf.d/upload-limit.ini\

&&echo"upload_max_filesize=32M">>

/usr/local/etc/php/conf.d/upload-limit.ini\

&&echo"post_max_size=32M">>/usr/local/etc/php/conf.d/upload-

limit.ini

#Pasteabovethisline.

RUNa2enmodrewriteexpiresheaders

Onceagain,buildtheimagetoensurethatnoerrorsareproduced.Ifyougetanerrorsayingthattheimagenamealreadyexists,youcandeletetheoldimagewiththedockerrmimod-wpcommandorchangethenametomod-wp:latest,whichwillupdatetheimage’stagtolatest.

Whenthebuildfinishes,werunanewcontainerfromthenewimagetocheckoutwhattheWordPressadministrationinterfacesays.Wecanrunacontainerfromournewimage,likethis:

dockerrun--namesome-mysql-eMYSQL_ROOT_PASSWORD=mysecretpassword-d

mysql

dockerrun--namesome-wordpress--linksome-mysql:mysql-d-p80mod-

wp:latest

Wecannowseethatwecanuploadbiggerfiles.Justtoverify,ifyouuploadafilebiggerthan2MB,itwillprovethatthelimithasbeenraised.

PlugininstallationHere,wearegoingtodownloadandinstalltwopluginsthatwewantinallourfutureWordPresssites.Allthetasksforthesepluginswillbedoneintheentrypointfile,sincewehavetoeditafewfilesintheWordPressinstallation.

ThefirstpluginisWPSuperCache.WepreparedApache2forthisearlier,andnowit’stimetousethat.Withthisplugin,oursitewillrunfasteranddemandfewerresourcesfromourhost.

ThesecondpluginisWPMailSMTP,withthehelpofwhichWordPresscansendoutgoinge-mails.Thiscontainerdoesnot(andshouldnot)includeamailserver.Withthisplugin,wecanmakeWordPresssende-mailsviaanexternalSMTP(Gmail,yourISPs,oranythingelse).

NoteEventhoughIhavehostedandmanagedmyownmailserverforafewyearsnow,itisahasslewithkeepingituptodateandmanagingspamfiltersandredundancy.We’rebetteroffleavingthattothespecialists.

AllpluginswillbedownloadedwithCURLandunpackedwithunzip.CURLisalreadyinstalledbutunzipisnot,sowehavetoaddittoourDockerfile,closetothetopwheretheapt-getinstallcommandisrunning:

RUNapt-getupdate&&apt-getinstall-yunziprsync&&rm-r

/var/lib/apt/lists/*

Ifwedon’tdothis,wewillgeterrormessagesduringthebuildprocess.

Sincetherearetwopluginswehavetodownload,extract,andactivate,wewillcreateafunctioninthedocker-entrypoint.shfile.

ThisfunctionwillgotoWordpress’pluginsiteandlookforthedownloadURLforthelatestversionoftheplugin.ItwilldownloadandthenextractittothepluginfolderinourWordpressinstallation:

dl_and_move_plugin(){

name="$1"

curl-O$(curl-i-s"https://wordpress.org/plugins/$name/"|egrep-o

"https://downloads.wordpress.org/plugin/[^']+")

unzip-o"$name".*.zip-d$(pwd)/wp-content/plugins

}

Nowthatwehavethefunctionthere,wecanaddtheselinesneartheendofthefile,justabovethelinethatsayschown–Rwww-data:www-data..:

dl_and_move_plugin"wp-super-cache"

dl_and_move_plugin"wp-mail-smtp"

Placethefunctionandthefunctioncallsclosetothebottom—inthedocker-

entrypoint.shfile,justabovetheexeccommand.

Wewillbuildtheimageagainandstartacontainersothatwecanverifythateverythingisworkingaswewant:

dockerbuild–tmod-wp:latest

Thiswilltakeawhile,andwhenit’sready,youcanfireupaMySQLcontainerandamod-wpcontainer:

dockerrun--namesome-mysql-eMYSQL_ROOT_PASSWORD=mysecretpassword-d

mysql

dockerrun--namesome-wordpress--linksome-mysql:mysql-d-p80mod-

wp:latest

Ifyougetanerrorthattellsyouthatyoualreadyhaveacontainerwiththatname,eitherremovetheoldcontainerwithdockerrmsome-wordpressoruseanothernameforthenewcontainer.

Gettheportbyinvokingdockerps,andlookfortheportbindingtoport80ontheWordPresscontainer.ThenloadtheURLintoyourbrowser.Thistime,installWordPress,login,andgotothepluginspage,asshowninthefollowingscreenshot:

Thislooksjustlikewewantitto!Great!

Let’sgoaheadandactivateandsetupthesepluginsjusttoverifythattheywork.StartwiththeWPMailSMTPplugin.IwillusemyGmailaccountasthesender,butyoucanchoosewhichSMTPyouwant.HereisascreenshotshowingthesettingsforGmail:

Fromthebottomofthispage,youcansendateste-mail.IstronglyrecommenddoingthisbecauseGmailsometimesblocksnewSMTPclients.IfyougetanerrormessagesayingPleaseloginviayourwebbrowserandthentryagain,you’vetriggeredthat.Inthatcase,you’llsoongetane-mailfromGoogleexplainingsuspiciousactivityandaskingyoutogothroughafewstepstomakeitwork.Thisisannoyingbutit’sagoodthing.

Nowlet’smoveontotheWPSuperCacheplugin.Goaheadandactivatethepluginfromthepluginpage.Beforewecanenableit,wehavetogotoSettings|Permalinks,check

thePostnamebutton,andsave.

ThengotoSettings|WPSuperCache.

ClickonCachingOnandthenonUpdateStatus.NowclickontheAdvancedtabandenablemod_rewritecaching,asshown:

ScrolldowntotheMiscellaneoussectionandchecktheboxesthatareshowninthefollowingscreenshot.Ifyouwanttoknowexactlywhatallofthesecheckboxesdo,youcanrefertotheplugins’documents.

Whenyou’vesavedthis,you’llgetanoticeatthetopsayingthatyouneedtoupdatetherewriterules,asshown:

ScrolldownthepageandclickontheUpdateMod_RewriteRulesbuttontoupdatetherewriterules,asshown:

Thecacheplugins’statusshouldnowbegreen,andallofthesetupshouldbedone.Sinceweareloggedintothiswebbrowser,wewillnotbeservedcachedpages.Thisisimportanttoknow,andtheadvantageisthatyouwon’thavetodisablethewholecachepluginjusttoseetheuncachedversionofyoursite.Openanotherwebbrowser(notjustanotherwindowortabinyourcurrentbrowser,unlessyouareusingincognitoorprivatemode)andgotoyourWordPressinstance.ClickontheHelloWorldtitleonthepost.Gobacktothestartpage.Clickonthetitleagain.Itfeelsprettyfast,right?

Toverifythatitworks,youcanopenthedevelopmenttoolsinyourbrowser.Makesurethatyoudon’thavecachingdisabledinyourbrowserwhenthedevelopmenttollsareopen.ClickontheNetworktab,thenclickonthepost’stitleagain,andtheninspectthatcall,asshowninthefollowingscreenshot:

Thisisjustwhatwewantedtosee.Great!

MakingourchangespersistNowthatwehavemadeourchanges,wewanttocreateourownDockerfiletobuildontopoftheofficialWordPressimage.

ThisiswhattheDockerfileshouldlooklike:

FROMwordpress:latest

RUNapt-getupdate&&apt-getinstall-yunzip&&rm-r

/var/lib/apt/lists/*

RUNtouch/usr/local/etc/php/conf.d/upload-limit.ini\

&&echo"upload_max_filesize=32M">>

/usr/local/etc/php/conf.d/upload-limit.ini\

&&echo"post_max_size=32M">>/usr/local/etc/php/conf.d/upload-

limit.ini

RUNa2enmodexpiresheaders

VOLUME/var/www/html

COPYdocker-entrypoint.sh/entrypoint.sh

ENTRYPOINT["/entrypoint.sh"]

CMD["apache2","-DFOREGROUND"]

HostingimagesourcesonGitHubTheDockerRegistryHubhasverygoodsupportforautomaticfetchingofimageupdatesfrombothBitbucketandGitHub.Youcanpickwhateveryouwant,butforthisbook,IwilluseGitHub.Ihaveaccountsonbothservicesandtheyarebothexcellent.

AtGitHub,createanewemptyrepositorycalledmy-docker-imagesandaddanappropriatelicenseifyoulike.

NoteThisbookwillnotgointohowtoaddyourSSHkeystoGitHubandsoon.Thereareexcellentguidesforthisonline.GitHubhasagreatguideathttps://help.github.com/articles/generating-ssh-keys/.

Let’screateabranchandcopyourfilesforthemodifiedDockerimagetoit.

Clonetherepositorylocallysothatyoucanaddfilestoit.Makesureyouarenotinsideyourwordpress-masterdirectory,butonthesamelevelasitis:

gitclonegit@github.com:yourusername/my-docker-images.git

Theoutputofthiscommandisasfollows:

We’llexecutethesecommandsonebyone:

cdmy-docker-images

gitcheckout-bwordpress

gitadd.

gitcommit–m"Addingnewfiles."

gitpushoriginwordpress

GotoyourGitHubpageandtrytofindtheWordPressbranch.

ForeverynewDockerimagewewanttocreateandpublishontheDockerRegistryHub,weneedtocreateanewbranchinthisGitHubrepository.IfyouhavealotofDockerimagesandtheimageshavealotofversions,youmightwanttoconsideradifferentstructure,butforthisbook,thisapproachwillbegreat!

Allfilesareinplace,andyoucanclickonthemtoverifythatthecontentsarewhatwewouldexpect.

PublishinganimageontheDockerRegistryHubIfyou’renotamemberoftheDockerRegistryHub(https://hub.docker.com),nowisthetimetoregistersothatyoucanpublishyourimagesonthepublicDockerrepository,whichcanbeaccessedfromanywhere.

AutomatedbuildsWhenyouaddarepository,youshouldchoosetheAutomatedBuildoptionsothatyoucanfetchcodefromGitHub(orBitbucket),asshowninthefollowingscreenshot:

We’llconnectwithourGitHubaccountandselecttherepositorywejustcreatedandpushedtomy-docker-images.

WewillstarttoaddourWordPressimage,solet’ssettherepositorynametowordpressonthenextscreen.It’simportantthatyouenterthisnamecorrectly,sinceitcannotbechangedlater.

Atthistime,wewilljustuseonetagforourimage—thelatesttag.Ensurethatthesource:TypeissettoBranchandthatyou’veenteredwordpressasitsname.

Choosetoaddthisasapublicrepositoryandchecktheactivecheckbox.ThismeansthatifyoupushanyupdatestothisonGitHub,theRegistryHubwillautomaticallypullitandpublishitschanges,asshowninthefollowingscreenshot:

TheRegistryHubwillnowpullyourbranchandtrytobuildyourDockerimagetoverifythatitworks.YoucanheadovertotheBuildDetailstabtoseetheprogress.Sinceit’stheofficialWordPressimagebase,itshouldgoprettyfastiftheycachetheimagesontheirbuildservers.Ifnot,itcouldtakeafewminutes,sincePHPiscompiledfromsource.

Thisisshowninthefollowingscreenshot:

Wow!We’vejustpublishedanimageontheDockerRegistryHub,whichmeansthatanyonecanfetchandruncontainersontopofit.ThestatuswillgofromBuildingtoFinishedwhentheimageispublished.

Thenextstepwouldbetoactuallypullitourselvestoverifythatitworksasexpected:

dockerpulloskarhane/wordpress

dockerimages

dockerrun--namemysql-eMYSQL_ROOT_PASSWORD=mysecretpassword-dmysql

dockerrun--namemy-wordpress--linkmysql:mysql-d-p80

oskarhane/wordpress

dockerps

Openyourwebbrowserandheadovertoyournewcontainer.YoushouldbepresentedwiththeWordPresssetuppage.

SummaryInthischapter,youlearnedquitealot.ThemostpartwasaboutmodifyingtheDockerfileandENTRYPOINTfilesinordertogettheDockerimagethatwewanted.Bashknowledgeandprogrammingskillsareveryconvenient,butsinceallofthisismostlyaboutinstallation,movingfiles,andeditingsettingsfiles,verybasicknowledgecanbeenough.

GitHubisanexcellentplacetohostyourDockerrepositories,andit’sveryeasytosetupanewrepositorytogetstarted.TheDockerRegistryHubtakesyourGitHubrepositoryandletsyoupickabranch.ThisbranchwillbethesourceforapublicDockerimagethatanyonecanpullanduse.

Onequestionarisesthough;whataboutourdata?It’strappedinsidetheseMySQLandWordPresscontainers.Thenextchapterwillshowyouhowtohandleyourdata.

Chapter4.GivingContainersDataandParametersTheWordPressdatainsidetheWordPresscontainerandthedatabase’sdatainsidetheMySQLcontainermaynotbewhatwewant.It’sconsideredgoodpracticetokeepthedataoutsidetheservicecontainersbecauseyoumaywanttoseparatethedatafromtheservicecontainer.Inthischapter,we’llcoverthefollowingtopics:

DatavolumesCreatingadatavolumeimageHostonGitHubPublishingonDockerRegistryHubRunningonDockerRegistryHubPassingparameterstocontainersCreatingaparameterizedimage

DatavolumesTherearetwowaysinwhichwecanmountexternalvolumesonourcontainers.Adatavolumeletsyousharedatabetweencontainers,andthedatainsidethedatavolumeisuntouchedifyouupdate,stop,orevendeleteyourservicecontainer.

Adatavolumeismountedwiththe–voptioninthedockerrunstatement:

dockerrun–v/host/dir:container/dir

Youcanaddasmanydatavolumesasyouwanttoacontainer,simplybyaddingmultiple–vdirectives.

Averygoodthingaboutdatavolumesisthatthecontainersthatgetdatavolumespassedintothemdon’tknowaboutit,anddon’tneedtoknowaboutiteither.Nochangesareneededforthecontainer;itworksjustasifitwerewritingtothelocalfilesystem.Youcanoverrideexistingdirectoriesinsidecontainers,whichisacommonthingtodo.Oneusageofthisistohavethewebroot(usuallyat/var/wwwinsidethecontainer)inadirectoryattheDockerhost.

MountingahostdirectoryasadatavolumeYoucanmountadirectory(orfile)fromyourhostonyourcontainer:

dockerrun–d--namesome-wordpress–v/home/web/wp-one:/var/wwwwordpress

Thiswillmountthehost’slocaldirectory,/home/web/wp-one,as/var/wwwonthecontainer.Ifyouwanttogivethecontaineronlythereadpermission,youcanchangethedirectiveto–v/home/web/wp-one:/var/www:rowherethe:roistheread-onlyflag.

It’snotverycommontouseahostdirectoryasadatavolumeinproduction,sincedatainadirectoryisn’tveryportable.Butit’sveryconvenientwhentestinghowyourservicecontainerbehaveswhenthesourcecodechanges.

Anychangeyoumakeinthehostdirectoryisdirectinthecontainer’smounteddatavolume.

MountingadatavolumecontainerAmorecommonwayofhandlingdataistouseacontainerwhoseonlytaskistoholddata.Theservicesrunninginthecontainershouldbeasfewaspossible,thuskeepingitasstableaspossible.

DatavolumecontainerscanhaveexposedvolumesviatheDockerfile’sVOLUMEkeyword,andthesevolumeswillbemountedontheservicecontainerwhileusingthedatavolumecontainerwiththe--volumes-fromdirective.

AverysimpleDockerfilewithaVOLUMEdirectivecanlooklikethis:

FROMubuntu:latest

VOLUME["/var/www"]

AcontainerusingtheprecedingDockerfilewillmount/var/www.Tomountthevolumesfromadatacontainerontoaservicecontainer,wecreatethedatacontainerandthenmountit,asfollows:

dockerrun–d--namedata-containerour-data-container

dockerrun–d--namesome-wordpress--volumes-fromdata-containerwordpress

BackingupandrestoringdatavolumesSincethedatainadatavolumeissharedbetweencontainers,it’seasytoaccessthedatabymountingitontoatemporarycontainer.Here’showyoucancreatea.zipfile(fromyourhost)fromthedatainsideadatavolumecontainerthathasVOLUME["/var/www"]initsDockerfile:

dockerrun--volumes-fromdata-container-v$(pwd):/hostubuntuzip-r

/host/data-containers-www/var/www

Thiscreatesa.zipfilenameddata-containers-www.zip,containingwhatwasinthe.wwwdatacontainerfromvardirectory.This.zipfileplacesthatcontentinyourcurrenthostdirectory.

CreatingadatavolumeimagesSinceourdatavolumecontainerwilljustholdourdata,weshouldkeepitassmallaspossibletostartwithsothatitdoesn’ttakelotsofunnecessaryspaceontheserver.Thedatainsidethecontainercan,ofcourse,growtobeasbigasthespaceontheserver’sdisk.Wedon’tneedanythingfancyatall;wejustneedaworkingfilestoragesystem.

Forthisbook,we’llkeepallourdata(MySQLdatabasefilesandWordPressfiles)inthesamecontainer.Youcan,ofcourse,separatethemintotwodatavolumecontainersnamedsomethinglikedbdataandwebdata.

DatavolumeimageOurdatavolumeimagedoesnotneedanythingotherthanaworkingfilesystemthatwecanreadandwriteto.That’swhyourbaseimageofchoicewillbeBusyBox.ThisishowBusyBoxdescribesitself:

“BusyBoxcombinestinyversionsofmanycommonUNIXutilitiesintoasinglesmallexecutable.ItprovidesreplacementsformostoftheutilitiesyouusuallyfindinGNUfileutils,shellutils,etc.TheutilitiesinBusyBoxgenerallyhavefeweroptionsthantheirfull-featuredGNUcousins;however,theoptionsthatareincludedprovidetheexpectedfunctionalityandbehaveverymuchliketheirGNUcounterparts.BusyBoxprovidesafairlycompleteenvironmentforanysmallorembeddedsystem.”

Thatsoundsgreat!We’llgoaheadandaddthistoourDockerfile:

FROMbusybox:latest

ExposingmountpointsThereisaVOLUMEinstructionfortheDockerfile,whereyoucandefinewhichdirectoriestoexposetoothercontainerswhenthisdatavolumecontainerisaddedusing--volumes-fromattribute.Inourdatavolumecontainers,wefirstneedtoaddadirectoryforMySQLdata.Let’stakealookinsidetheMySQLimagewewillbeusingtoseewhichdirectoryisusedforthedatastorage,andexposethatdirectorytoourdatavolumecontainersothatwecanownit:

RUNmkdir–p/var/lib/mysql

VOLUME["/var/lib/mysql"]

WealsowantourWordPressinstallationinthiscontainer,includingall.phpfilesandgraphicimages.Onceagain,wegototheimagewewillbeusingandfindoutwhichdirectorywillbeused.Inthiscase,it’s/var/www/html.WhenyouaddthistotheDockerfile,don’taddnewlines;justappendthelineswiththeMySQLdatadirectory:

RUNmkdir-p/var/lib/mysql&&mkdir-p/var/www/html

VOLUME["/var/lib/mysql","/var/www/html"]

TheDockerfileThefollowingisasimpleDockerfileforthedataimage:

FROMbusybox:latest

MAINTAINEROskarHane<oh@oskarhane.com>

RUNmkdir-p/var/lib/mysql&&mkdir-p/var/www/html

VOLUME["/var/lib/mysql","/var/www/html"]

Andthat’sit!WhenpublishingimagestotheDockerRegistryHub,it’sgoodtoincludeaMAINTAINERinstructionintheDockerfilessothatyoucanbecontactedifsomeonewants,forsomereason.

HostingonGitHubWhenweuseourknowledgeonhowtohostDockerimagesourcesonGitHubandhowtopublishimagesontheDockerRegistryHub,it’llbenoproblemcreatingourdatavolumeimage.

Let’screateabranchandaDockerfileandaddthecontentforourdatavolumeimage:

gitcheckout-bdata

viDockerfile

gitaddDockerfile

Onlinenumber2intheprecedingcode,youcanusethetexteditorofyourchoice.Ijusthappentofindvisuitsmyneeds.ThecontentyoushouldaddtotheDockerfileisthis:

FROMbusybox:latest

MAINTAINEROskarHane<oh@oskarhane.com>

RUNmkdir/var/lib/mysql&&mkdir/var/www/html

VOLUME["/var/lib/mysql","/var/www/html"]

Replacethemaintainerinformationwithyournameande-mail.

Youcan—andshould—alwaysensurethatitworksbeforecommittingandpushingtoGitHub.Todoso,youneedtobuildaDockerimagefromyourDockerfile:

dockerbuild–tdata-test.

Makesureyounoticethedotattheendoftheline,whichmeansthatDockershouldlookforaDockerfileinthecurrentdirectory.DockerwilltrytobuildanimagefromtheinstructionsinourDockerfile.Itshouldbeprettyfast,sinceit’sasmallbaseimageandthere’snothingbutacoupleofVOLUMEinstructionsontopofit.

Thescreenshotisasfollows:

Wheneverythingworksaswewant,it’stimetocommitthechangesandpushittoourGitHubrepository:

gitcommit–m"Dockerfilefordatavolumeadded."

gitpushorigindata

Whenyouhavepushedittotherepository,headovertoGitHubtoverifythatyournewbranchispresentthere.

ThefollowingscreenshotshowstheGitHubrepository:

PublishingontheDockerRegistryHubNowthatwehaveournewbranchonGitHub,wecangototheDockerHubRegistryandcreateanewautomatedbuild,nameddata.ItwillhaveourGitHubdatabranchassource.

Waitforthebuildtofinish,andthentrytopulltheimagewithyourDockerdaemontoverifythatit’sthereandit’sworking.

Thescreenshotwillbeasfollows:

Amazing!Checkoutthesizeoftheimage;it’sjustlessthan2.5MB.Thisisperfectsincewejustwanttostoredatainit.Acontainerontopofthisimagecan,ofcourse,beasbigasyourharddriveallows.Thisisjusttoshowhowbigtheimageis.Theimageisread-only,remember?

RunningadatavolumecontainerDatavolumecontainersarespecial;theycanbestoppedandstillfulfilltheirpurpose.Personally,Iliketoseeallcontainersinusewhenexecutingdockerpscommand,sinceIliketodeletestoppedcontainersonceinawhile.

Thisistotallyuptoyou.Ifyou’reokaywithkeepingthecontainerstopped,youcanstartitusingthiscommand:

dockerrun–doskarhane/datatrue

Thetrueargumentisjusttheretoenteravalidcommand,andthe–dargumentplacesthecontainerindetachedmode,runninginthebackground.

Ifyouwanttokeepthecontainerrunning,youneedtoplaceaserviceintheforeground,likethis:

dockerrun–doskarhane/datatail–f/dev/null

Theoutputoftheprecedingcommandisasfollows:

Thetail–f/dev/nullcommandisacommandthatneverends,sothecontainerwillberunninguntilwestopit.Resource-wise,thetailcommandisprettyharmless.

PassingparameterstocontainersWehaveseenhowtogivecontainersparametersorenvironmentvariableswhenstartingtheofficialMySQLcontainer:

dockerrun--namemysql-one-eMYSQL_ROOT_PASSWORD=pw-dmysql

The–eMYSQL_ROOT_PASSWORD=pwcommandisanexampleshowinghowyoucandoit.ItmeansthattheMYSQL_ROOT_PASSWORDenvironmentvariableinsidethecontainerhaspwasthevalue.

ThisisaveryconvenientwaytohaveconfigurablecontainerswhereyoucanhaveasetupscriptasENTRYPOINToraforegroundscriptconfiguringpasswords;hosts;test,staging,orproductionenvironments;andothersettingsthatthecontainerneeds.

CreatingaparameterizedimageJusttogetthehangofthisfeature,whichisverygood,let’screateasmallDockerimagethatconvertsastringtouppercaseorlowercase,dependingonthestateofanenvironmentvariable.

TheDockerimagewillbebasedonthelatestDebiandistributionandwillhaveonlyanENTRYPOINTcommand.ThisistheDockerfile:

FROMdebian:latest

ADD./case.sh/root/case.sh

RUNchmod+x/root/case.sh

ENTRYPOINT/root/case.sh

Thistakesthecase.shfilefromourcurrentdirectory,addsittothecontainer,makesitexecutable,andassignsitasENTRYPOINT.

Thecase.shfilemaylooksomethinglikethis:

#!/bin/bash

if[-z"$STR"];then

echo"NoSTRstringspecified."

exit0

fi

if[-z"$TO_CASE"];then

echo"NoTO_CASEspecified."

exit0

fi

if["$TO_CASE"="upper"];then

echo"${STR^^*}"

exit0

fi

if["$TO_CASE"="lower"];then

echo"${STR,,*}"

exit0

fi

echo"TO_CASEwasnotupperorlower"

Thisfilecheckswhetherthe$STRand$TO_CASEenvironmentvariablesareset.Ifthecheckonwhether$TO_CASEisupperorlowerisdoneandifthatfails,anerrormessagesayingthatweonlyhandleupperandlowerisdisplayed.

If$TO_STRwassettoupperorlower,thecontentoftheenvironmentvariable$STRistransformedtouppercaseorlowercaserespectively,andthenprintedtostdout.

Let’strythis!

Herearesomecommandswecantry:

dockerrun–icase

dockerrun–i-eSTR="MyString"case

dockerrun–i-eSTR="MyString"–eTO_CASE=camelcase

dockerrun–i-eSTR="MyString"–eTO_CASE=uppercase

dockerrun–i-eSTR="MyString"–eTO_CASE=lowercase

Thisseemstobeworkingasexpected,atleastforthispurpose.Nowwehavecreatedacontainerthattakesparametersandactsuponthem.

SummaryInthischapter,youlearnedthatyoucankeepyourdataoutofyourservicecontainersusingdatavolumes.Datavolumescanbeanyoneofdirectories,filesfromthehost’sfilesystem,ordatavolumecontainers.

WeexploredhowwecanpassparameterstocontainersandhowtoreadthemfrominsideENTRYPOINT.Parametersareagreatwaytoconfigurecontainers,makingiteasiertocreatemoregeneralizedDockerimages.

WecreatedadatavolumecontainerandpublishedittotheDockerRegistryHub,preparingusforthenextchapter,wherewewillconnectourthreecontainerstocreateonelooselycoupledunit.

Chapter5.ConnectingContainersIt’stimetoconnectallourthreecontainerstoformasingleunitofmodularizedparts.I’llintroduceyoutotwoservices,DockerComposeandCrane,whichcanbeusedtoautomatethis.We’llgothroughthefollowingtopicsinthischapter:

ManuallyconnectingcontainerstogetherExploringthecontentsofadatavolumecontainerConnectingcontainerstoaconfigurationfileusingDockerComposeConnectingcontainerstoaconfigurationfileusingCrane

ManuallyconnectingcontainersLet’stakealookathowtoconnectourservicecontainerstoourdatavolumecontainer.First,wehavetorunourdatavolumecontainer,thenrunourMySQLcontainer,andlastlyrunourWordPresscontainer,asshowninthefollowingcommand:

dockerrun-d--namedata-oneoskarhane/datatail-f/dev/null

dockerrun--namemysql-one--volumes-fromdata-one-e

MYSQL_ROOT_PASSWORD=mysecretpassword-dmysql

dockerrun--namewordpress-one--volumes-fromdata-one--linkmysql-

one:mysql-d-p80oskarhane/wordpress

Here,wehavefiredupandnamedthedatavolumecontainerdata-one.ThenextlinefiresuptheMySQLcontainer,namedmysql-one,andgivesitthedatavolumecontainer.ThelastlinefiresupourWordPresscontainer,namedwordpress-one,linksmysql-oneastheMySQLlink,andgivesitthedatavolumecontainer.

Thefollowingoutputisdisplayed:

Openyourwebbrowserandheadovertothecontainer’sURLandportinordertoverifythatalltheservicesarerunningandthecontainersaretiedtogetherastheyshouldbe.Youshouldseethe,nowfamiliar,WordPressinstallationpage.

Asyoumayhavefiguredoutbynow,youcanfireupanotherWordPresscontainerusingthesameMySQLlinkandthesamedatavolumecontainer.Whatdoyouthinkwillhappen?

ThenewWordPresscontainerwillbeanotherinstanceofthesameWordPresssite,withthesamefilesandthesamedatabase.

Whenyoulinkcontainers,Dockerwillsetsomeenvironmentvariablesinthetargetcontainerinordertoenableyoutogetinformationaboutthelinkedsourcecontainer.Inourcase,theseenvironmentvariableswillbesetwhenwelinktheMySQLcontainer,asshowninthefollowingcommand:

MYSQL_NAME=/wordpress-one/mysql-one

MYSQL_PORT=tcp://ip:3306

MYSQL_3306_TCP=tcp://ip:3306

MYSQL_3306_TCP_PROTO=tcp

MYSQL_3306_TCP_PORT=3306

MYSQL_3306_TCP_ADDR=ip

ExploringthecontentsofadatavolumecontainerIsthedatabeingwrittentothedatavolumecontainer?Or,isthedatastoredinsidetheMySQLandWordPresscontainerswhenconnected?Howcanyoutell?

Onewaytodeterminethisistoenteracontainerviaashellsothatyoucannavigatearounditsfilesystem.Sinceversion1.3,Dockerhastheabilitytostartanewinstanceofacontainer’sshell.Runningtheolddockerattachcommandjustgetsyouinthecurrentshellinstance,whichinourcasehastail–f/dev/nullrunning.Ifweexitthistailcommand,thecontainerwillexitandshutdown.Therefore,weneedanewshellinstanceinarunningcontainersothatwecaninvokeanycommandswewantinsidethecontainerwithouttheriskofthecontainerexiting.Thefollowingcommandcanbeusedtodothis:

dockerexec-i-tdata-one/bin/sh

The–iand–tflagsmeanthatwewanttokeepthesessioninteractiveandallocateapseudo-TTY.data-oneisthenameofthecontainer,butyoucanusethecontainerIDifyoulike.Iwouldchoose/bin/bashover/bin/sh,butthecontainerrunsBusyBoxand/bin/bashisn’tavailablethere.Forthekindsoftasksthatweareabouttoperform,itdoesn’tmatterwhichshellweuse.

WhatwewanttodoistotakealookinthedirectoriesweexposedasVOLUMESinthisdatavolumecontainer.Thedirectoriesare/var/www/htmland/var/lib/mysql.

Let’sexploreinthefollowingcommand:

ls-la/var/www/html

ls-la/var/lib/mysql

Thefollowingoutputisdisplayed:

Weseefilesonboththosedirectories,whichindicatesthatthetwoothercontainersarewritingtothisone.Itseparatestheserviceswiththedata.Ifyouwantfurtherproof,launchviintheshell,editafile,andreloadthesiteinyourbrowser.

Thisworkedoutreallysmoothandeasy,didn’tit?Thecontainersinteractwitheachotherandallwehavetodoistolinkthemtogetherwithjustonecommand.

ConnectingcontainersusingDockerComposeDockerComposewaspreviouslycalledFig,butDockeracquiredFigandthenamewaschanged.ThisishowDockerdescribesDockerCompose:

“ComposeisatoolfordefiningandrunningcomplexapplicationswithDocker.WithCompose,youdefineamulti-containerapplicationinasinglefile,thenspinyourapplicationupinasinglecommandwhichdoeseverythingthatneedstobedonetogetitrunning.”

DockerComposebasicallygivesusawaytodefinesettingsinaconfigurationfile,sowedon’thavetorememberallthenamesforallthecontainerswhenlinkingthemtogether,theportstoexpose,thedatavolumecontainertouse,andsoon.

InstallingDockerComposeDockerComposehasregularreleasesonGitHub,andatthetimeofwritingthisbook,thelatestreleaseis1.0.1.

WewillinstallDockerComposewiththePythonpackagemanager,pip.OurEC2instancedoesnotcomewithpipinstalled,sowehavetostartwiththeinstallation,asshownhere:

sudosu

wgethttps://bootstrap.pypa.io/get-pip.py&&python./get-pip.py

Thefollowingoutputisdisplayed:

Afterpipisinstalled,youcangoaheadandinstallDockerCompose:

sudopipinstall-Udocker-compose

Now,you’llseeDockerComposeinstalledalongwithallofitsdependencies.Invokedocker-compose--versiontoverifythatitworksasexpected.

BasicDockerComposecommandsThefollowingarethebasicDockerComposecommandsthatyoushouldbefamiliarwith:

build:Thisisusedtobuildorrebuildserviceskill:Thisforcestheservicecontainerstostoplogs:Thisviewstheoutputfromtheservicesport:Thisisusedtoprintthepublicportforaportbindingps:Thisisusedtolistcontainerspull:Thisisusedtopullserviceimagesrm:Thisisusedtoremovestoppedservicecontainersrun:Thisisusedtorunaone-offcommandonaservicescale:Thissetsthenumberofcontainerstoberunforaservicestart:Thisisusedtostartexistingcontainersforaservicestop:Thisstopsrunningcontainerswithoutremovingthemup:Thisbuilds,recreates,starts,andattachestocontainersforaservice;linkedcontainerswillbestarted,unlesstheyarealreadyrunning

Asyoucansee,thecommandsareverysimilartotheDockerclientcommandsandmostofthemdotheexactsamethingbyforwardingthecommandstotheDockerdaemon.Wewillgothroughsomeofthemalittlemoreindetail.

ServiceWhenthewordserviceisusedwithDockerCompose,itreferstoanamedcontainerinadocker-compose.ymlconfigurationfile.

UsingtheruncommandWeareusedtostartingcontainerswiththeruncommandfortheDockerclient.Withdocker-compose,theruncommandisverydifferent.Whenyourunacommandwithdocker-compose,it’saone-offcommandonaservice.ThismeansthatifwenameacontainerconfigurationUbuntuandinvokedocker-composerunubuntu/bin/bashechohello,thecontainerwillstartandexecute/bin/bashechohelloandthenshutdown.ThedifferencewiththisandrunningthecommanddirectlywithDockeristhatallthelinkedcontainersandVOLUMEcontainerswillbestartedandconnectedwhenyouusedocker-compose.

UsingthescalecommandThescalecommandisveryinteresting.Whenweinvokedocker-composescaleweb=3,weactuallystartthreecontainersoftheservicethatwenamedweb.

SettingupourPaaSwithDockerComposeEveryDockerComposeinstancelivesinitsowndirectoryandhasaconfigurationfilenameddocker-compose.ymlinsideit:

mkdirdocker-compose-wp&&cd$_

touchdocker-compose.yml

Thisishowthecontentsofourdocker-compose.ymlfilewilllook:

wp:

image:oskarhane/wordpress

links:

-mysql:mysql

ports:

-"80"

volumes_from:

-paasdata

mysql:

image:mysql

volumes_from:

-paasdata

environment:

-MYSQL_ROOT_PASSWORD=myrootpass

paasdata:

image:oskarhane/data

command:tail-f/dev/null

Youcanseethatwehavedefinedthreeserviceshere,namelywp,mysql,andpaasdata.

Letstrytheseservicesandthefollowingoutputisdisplayed:

Invokedocker-composeup–dtorundocker-composeandthecontainersindaemonmode.

That’showeasyitis.OpenyourwebbrowserandheadtoyourDockerhostandtheportstatedinthetable(inmycase,port49155);youshouldseetheveryfamiliarWordPressinstallationpage.

ConnectingcontainersusingCraneCraneismuchlikeDockerCompose,butithasmoreconfigurationpossibilities.ThisishowitscreatordescribesCrane:

“CraneisatooltoorchestrateDockercontainers.Itworksbyreadinginsomeconfiguration(JSONorYAML)whichdescribeshowtoobtainimagesandhowtoruncontainers.Thissimplifiessettingupadevelopmentenvironmentalotasyoudon’thavetobringupeverycontainermanually,rememberingalltheargumentsyouneedtopass.Bystoringtheconfigurationnexttothedataandtheapp(s)inarepository,youcaneasilysharethewholeenvironment.”

ThisparagraphcanbeaboutDockerComposeaswell,asyoucansee.

InstallingCraneCraneiseasytoinstallbutnoteasytokeepupdated.Thesamecommandisusedtoinstallaswellasupdate,sowehavetoinvokethisonceinawhileinordertohavethelatestversion.

InvokethefollowingcommandonasinglelinetoinstallCrane:

bash-c"`curl-sL

https://raw.githubusercontent.com/michaelsauter/crane/master/download.sh`"

&&sudomvcrane/usr/local/bin/crane

Craneisnowinstalledin/usr/local/bin.

UsageIwon’tgothroughallthecommandsheresincethey’resimilartoDockerCompose’scommands,butI’llcommentonafewhere:

lift:Thiscommand,likeDockerCompose’supcommand,buildsandrunscontainersfromyourconfigurationfilegraph:Thisprintsyourcontainers’relationsfromtheconfigurationfilelogs:ThismapstotheDockersCompose’scommand,buthereyoucangetthelogsforawholegroupstatus:ThisalsomapstotheDockersCompose’scommandbutletsyougetthelogsforagroup

ConfigurationThisiswhereCranereallyleavesDockerComposebehind.YouhavemanymoreconfigurationoptionsforCraneapps.Theconfigurationfilemustbenamedcrane.jsonorcrane.yaml.Foreverycontainer,thisiswhatyoucanconfigure:

image(string,required):Thisisthenameoftheimagetobuild/pulldockerfile(string,optional):ThisgivestherelativepathtotheDockerfilerun(object,optional):TheseparametersaremappedtoDocker’srunandcreatecommands:

add-host(array):Thisaddscustomhost-to-IPmappingscpuset(integer)cpu-shares(integer)detach(boolean)sudodockerattach<containername>willworkasnormaldevice(array):Thisaddshostdevicesdns(array)entrypoint(string)env(array)expose(array):Thisdenotestheportstobeexposedtolinkedcontainershostname(string)interactive(boolean)link(array):Thislinkscontainersmemory(string)privileged(boolean)publish(array):Thismapsnetworkportstothecontainerpublish-all(boolean)restart(string)Restartpolicyrm(boolean)tty(boolean)volume(array):IncontrasttoplainDocker,thehostpathcanberelativevolumes-from(array):Thisisusedtomountvolumesfromothercontainersworkdir(string)cmd(array/string):Thiscommandisusedtoappendtodockerrun(overwritingCMD)

rm(object,optional):TheseparametersaremappedtoDocker’srmcommand:

volumes(boolean)

start(object,optional):TheseparametersaremappedtoDocker’sstartcommand:

attach(boolean)interactive(boolean)

SetupthesameconfigurationthatyoudidinDockerCompose;itwilllooksomethinglikethefollowingcode.Asyoumightunderstand,youcanwritethisintheJSONformatas

well,butforthecomparisontoDockerCompose’sversiontobeaseasyaspossible,I’llkeepitintheyamlformat:

containers:

wp:

image:oskarhane/wordpress

run:

volumes-from:["mydata"]

link:

-mymysql:mysql

publish:["80"]

detach:true

mymysql:

image:mysql

run:

volumes-from:["mydata"]

detach:true

env:["MYSQL_ROOT_PASSWORD=rootpass"]

mydata:

image:oskarhane/data

run:

detach:true

cmd:"tail-f/dev/null"

Here,wespecifythreecontainers,wherethedatacontainerisaddedasadatavolumecontainertotheothersandtheMySQLcontainerislinkedtotheWordPresscontainer.

Savethisfileascrane.yamlandtypecranelifttorunyourapp.

Thefollowingoutputisdisplayed:

Toseethecontainers’currentstatuses,wecantypecranestatus.Takealookatthelastcolumninourwpcontainer.Itsaysit’snotrunning.Typecranelogswpandseewhatitsaysinfollowingcommand:

wp*WordPressnotfoundin/var/www/html-copyingnow…

wp*Complete!WordPresshasbeensuccessfullycopiedto/var/www/html

wp|

wp|Warning:mysqli::mysqli():(HY000/2002):Connectionrefusedin-on

line5

wp*MySQLConnectionError:(2002)Connectionrefused

ItseemsthatourWordPresscontainerstartsfasterthanourMySQLcontainer,sotheWordPresscontainercan’tfinditwhenitstarts.

ThiscanhappeninDockerComposeaswellbecausethere’snocheckif--link:edcontainersareup,atleastnotatthetimewhenthisisbeingwritten.

ThiscannotbesolvedinDockerCompose;wehavetorelyonpureluckthattheMySQLcontainerwillgetreadybeforetheWordPresscontainertriestousethelinkedMySQLcontainer.

WithCrane,youcangroupcontainersinsidetheconfigurationfileindifferentgroupsandthenruncommandsonthatgroupinsteadofthewholeconfiguration.

Thisisveryeasy;wejustaddtheselinesattheendofourcrane.yamlfile:

groups:

default:['mydata','mymysql','wp']

data_db:['mydata','mymysql']

web:['wp']

Here,wehaveseparatedtheWordPresscontainerfromtheothertwocontainerswehavesothatwecanruncommandsonthemseparately.

Let’sstartourdata_dbgroupfirstbyinvokingthecraneliftdata_db--recreatecommand.Iaddedtheflag--recreateandtomakesurethatwe’recreatingnewcontainersandnotreusingtheoldones.Runcranestatusdata_dbtomakesurethey’rerunning.

NowthatweknowthattheMySQLcontainerisrunning,wecanstarttheWordPresscontainerbyinvokingthecraneliftweb--recreatecommand.

Thefollowingoutputisdisplayed:

SummaryNow,wecanconnectcontainersindifferentwaystokeepdifferentservicesseparateondifferentcontainers.Welearnedhowtodothismanually,whichcanbequitehardwhenyouhavelotsofdependenciesbetweencontainers.

Wehadabrieflookattwoorchestrationtools:DockerComposeandCrane.Craneisanindependentandmoreadvancedtoolfortheadministratorswhowantmorecontrolovercontainers.TheabilitytogroupcontainersinCranemakesitmorereliablewhentherecanbetimingissuesindependencies.

Inthenextchapter,wewillruntwoinstancesofourappusingCranetoseewhatproblemsandpossibilitiescropupwhenwewanttomakebothourblogspubliclyaccessibleontheregularHTTPport(80).

Chapter6.ReverseProxyRequestsOnebigprobleminhavingmanycontainerswithpublicportsonthesameserveristhattheycan’talllistentothestandardportsfortheirkindsofservices.IfwehaveaMySQLbackendserviceandhave10MySQLcontainersrunning,onlyoneofthemcanlistentotheMySQLstandardport3306.Forthosewhoexposeawebserver,thestandardport80canonlybeusedbyoneoftheirWordPresscontainers.Inthischapter,we’llcoverthefollowingtopics:

ExplainingtheproblemComingupwithasolutiontotheproblemImplementingthesolutionwithNginxandHAProxyAutomatingtheprocessofmappingdomains

ExplainingtheproblemTheprobleminhavingmanycontainerswiththesameservicesonthesamehostisthattherearestandardportsusedbyuserapplications.UsingawebbrowserandenteringtheIPtoaDockerhostrunningaWordPresscontainerwillaskforresourcesonport80bydefault.Youcan’texpectyouruserstorememberanonstandardportinordertoenteryourwebsite.

Theonlywaytoreacheachofthethreecontainersistomanuallyenterthecontainers’exposedportnumber.

FindingasolutionBeforeweheadtothesolution,letmeexplainwhataregularproxyserveris,incaseyou’renotfamiliarwithit.

Aproxyserverisaserverthatconnectstoservicesonyourbehalfandforwardsalltheresultstoyou.Afteryou’vesetuptorouteallyourtrafficthroughtheproxyserver,you—asauser—won’tnoticeit’sthere.Everythingwillworkasusual.

However,serviceownersonlyseethatacertainmachine(theproxyserver)isconnectedtothem.Ifanotheruserusesthesameproxyserverandthesameserviceasyoudo,theserviceownercan’ttellthedifferenceandwillperceiveyouasonesingleuser.

Differentusersconnectingthroughaproxyserverappearasoneuser.

Asyoucanseeintheprecedingdiagram,theserviceownersjustseethatsomeonewithanIPof213.12.12.3hasconnectedtothem.

So,whatifweusethisontheDockerhost?Whatifweputsomethinginfrontofallthecontainers?Dependingonwhichdomainnameisbeingrequested,thisthingwillforwardtherequesttotherightcontainerandportandthenjustforwardtherequest’sresponsetotherequestinguser.

Therearethingsespeciallymadetosolvethiskindofproblem.They’recalledreverseproxies(reversebecausetheproxyisattheotherend,makingtheuseronlyseeoneIPand

forwardingtherequest).

IfweinstallandconfigureareverseproxyonourDockerhostserver,thenthisishowthediagramwilllook:

AreverseproxyletsallDockercontainersappearasone.

Thereverseproxylistenstoport80—thestandardwebport—andwhenarequestfordomain1.comcomesin,theproxylooksatitsconfigurationtoseewhetherthereisaspecifiedforwardingendpointforthisdomain.Ifthereis,thereverseproxyforwardstherequesttotherightDockercontainer,waitsforitsresponse,andforwardsthecontainer’sresponsetotherequestinguserswhenitcomes.

Thisisthesolutionwe’reafter.Theonlyquestionnowiswhichreverseproxywearegoingtouse.Therearequiteabunchofthemoutthere;somereverseproxieshavemorespecificpurposes,suchasloadbalancing,andsomeareservicesthatdoalotofotherstuffandhavethisfeatureaswell,suchasawebserver.

ImplementingthesolutionYouwillalwayshavepreferenceswhenselectingatooltosolveaproblem.Sometimes,youselectatoolbecauseyou’recomfortableusingitandit’sgoodenough;sometimes,youselectitbecauseithasgreatperformanceorbecauseyoujustwanttotrysomethingnew.

That’swhywewillgothroughthisproblemandsolveitwithtwodifferenttools.Theendresultwillbethesame,butthetoolshaveaslightlydifferentsetup.

Beforewestartimplementingthesolutions,weuseCranetostartaninstanceofourthree-containerapplicationandverifythatit’sworkingbyconnectingittothesite.HaveDockerdecidethepublicportforyou,soit’s491XX.Rememberthisportsincewewilluseitwhenimplementingthesolutions.

WeneedtopointoutthedomainnameswewanttousetoourDockerhost’sIPaddress.WecandothiseitherbysettingthedomainnamesA-recordtoourserver’sIPaddressorbyaddingalineinourlocal/etc/hostsfile,whichdirectsrequeststothedomainnamestoourserver’sIPaddress.

I’llgowiththelatterandenterthisinmyMac’s/etc/hostsfile:

54.148.253.187domain1.com

54.148.253.187domain2.com

54.148.253.187domain3.com

NoteMakesureyoureplacetheaboveIPaddresswithyourserver’sIPaddress.

ImplementationwithHAProxyHAProxy(http://www.haproxy.org)isaloadbalancer,whichhastheroleofforwardingtraffictodifferentservicesbehindit.

ThisishowHAProxydescribethemselves:

“HAProxyisafree,veryfastandreliablesolutionofferinghighavailability,loadbalancing,andproxyingforTCPandHTTP-basedapplications.Itisparticularlysuitedforveryhightrafficwebsitesandpowersquiteanumberoftheworld’smostvisitedones.Overtheyearsithasbecomethede-factostandardopensourceloadbalancer,isnowshippedwithmostmainstreamLinuxdistributions,andisoftendeployedbydefaultincloudplatforms.”

Thissoundslikesomethingthatfitsourneeds.

InstallingHAProxyAsnotedinthequote,manysystemsareinstalledalreadyandshippedwithit.Ifyoucan’tfindit,itshouldbeavailableinyoupackagemanagerifyouuseUbuntuorDebian(apt-getinstallhaproxy)orinsomeotherdistrowithapackagemanager.

OnmyAmazonEC2instancethatrunsAmazonLinux,HAProxycanbeinstalledusingyuminstallhaproxy.

Thefollowingoutputwillbeobtainedasfollows:

It’snotthemostrecentversion,butthat’sOKforthethingsweareabouttodo.

ConfiguringHAProxyWe’llwriteanHAProxyconfigurationinthefile/etc/haproxy/docker.cfgsothatwedon’thavetoremoveeverythinginthedefaultconfigurationfile,asitmaybegoodforreferenceinthefuture.

HAProxydividesitsconfigurationintofourparts:global,defaults,frontend,andbackend.Don’tconfusefrontendandbackendwithfrontendandbackenddevelopment.Here,frontendmeanstheserverpartthat’sfacingtheInternet,andbackendistheserverpartthat’sbehindHAProxy,whichinourcasearetheDockercontainers.

Opentheconfigurationfileandstartbytypinginthegenericstuff,asshownhere:

global

daemon

maxconn4096

pidfile/var/run/haproxy.pid

defaults

modehttp

timeoutconnect5000ms

timeoutclient50000ms

timeoutserver50000ms

Now,weentertheporttolistenonandthebackendconfigurationstouseforwhichdomain:

frontendhttp-in

bind*:80

aclis_site1hdr_end(host)-idomain1.com

use_backendsite1ifis_site1

WedefinethatregularincomingHTTPtrafficonport80shouldbecaptured.Theaclheremeansaccesscontrollistandisaflexiblesolutiontotakedecisionsbasedoncontentextractedfromtherequests.Thehdr_end(host)-idomain1.comfunctioncallmeansthattheendoftheheaderhostiscase-insensitive,matchedagainstthestringdomain1.com.Theresult(Boolean)ofthismatchissavedintheis_site1variable.

Notethatthismeansthatallthesubdomainsfordomain1.comwillbematchedwiththissetup.Ifyoujustwanttomatchwww.domain1.com,youcanusehdr(host)-iwww.domain1.cominstead.

Nowthatwehavethematchresultintheis_site1variable,wecansendtherequesttoabackendconfiguration,namedsite1.

Weappendthistoourconfigurationfile:

backendsite1

balanceroundrobin

optionhttpclose

optionforwardfor

servers1127.0.0.1:49187maxconn450

Wedefineourbackendnameassite1,setafewoptions,andaddtheserverandtheporttoourWordPresscontainer.

NoteMakesureyouenteryourWordPresscontainer’sexposedportinsteadof49187intheprecedingcode.

It’stimetotrythisconfiguration.Savetheconfigurationfileandtestitinashellwiththiscommand:

haproxy-f/etc/haproxy/docker.cfg–c

TheoutputshouldsayConfigurationfileisvalid.

Makesureyoudon’thavesomethingalreadylisteningtoport80onyourmachine.Youcanusesomethingsuchasnetstat–atoverifythat80orHTTPisn’tlisted.Iftheyare,findtheappthat’slisteningandshutitdown.

StartHAProxywiththiscommand:

haproxy-f/etc/haproxy/docker.cfg–D

The-Doptionmeansthatwewanttorunitasadaemoninthebackground.Youshouldn’tseeanyoutputwhenyouinvokethiscommand.

Let’scheckwhetherHAProxyisrunningbyinvokingpsaux|grephaproxy.Youshouldseeitlistedthere.Finally,let’sverifythatitislisteningtoport80byinvokingnetstat–a|grephttp.Now,youshouldhavesomethinginthatlist.

Theoutputobtainedisdisplayedhere:

Italllooksgood!

Justtorecapwhatwehavedonehere:wesetupaservicethatlistensforincomingrequestsonport80onourserver.Whenarequestonthisportcomesin,acheckontherequestheader’shostisperformedtoseewhetheritmatchesdomain1.com.Ifwehaveamatch,therequestisforwardedtotheIPaddress127.0.0.1andtotheport49187.TheresponsefromthisIPandportaresentbacktotherequester.

Nowtothemomentoftruth.OpenyourwebbrowserandentertheURLdomain1.com.

Makesurethatyouhaveentriesfordomain1.cominyourhost’sfile,pointingittoyourserver.

Afteryouperformtheprecedinginstructions,youwillseethefollowingwebsitescreen:

Youcanseethatinthelocationbar,noportisspecified.Wonderful!

AddingmoredomainstoHAProxyWedidnotgothroughallthisjusttoserveasinglewebapplicationonport80,whichcanbedonewithoutareverseproxy.StartanotherWordPressapplicationwithCranebycopyingtheoldconfigurationtoanewdirectoryandchangetheservice’snames,asshownhere:

cd..

cp–rcrane-wpcrane-wp2

cdcrane-wp2

sed-i"s/wp/wp2/g"crane.yaml

sed-i"s/mydata/mydata2/g"crane.yaml

sed-i"s/mymysql/mymysql2/g"crane.yaml

craneliftdata_db

craneliftwp2

#checkoutportfornewcontainernamedwp2

dockerps

OpentheHAProxyconfigurationfileagainandaddtwolinesinthefrontend:

aclis_site2hdr_end(host)-idomain2.com

use_backendsite2ifis_site2

Afterthat,addanewbackendconfigurationnamedsite2:

backendsite2

balanceroundrobin

optionhttpclose

optionforwardfor

servers2127.0.0.1:49188maxconn450

Makesurethatyoureplacetheportwiththeoneyougot.RestartHAProxyanddothecheckswedidthelasttimewestartedit.

TorestartHAProxy,run/etc/init.d/haproxyrestart.

NoteHAProxycanreloadanewconfigurationwithoutdroppingactivesessionswiththiscommand:

haproxy-f/etc/haproxy/docker.cfg-p/var/run/haproxy.pid-sf$(cat

/var/run/haproxy.pid)

Openyourbrowserandgotodomain1.cominordertomakesurethattheoldoneisworking.Ifitdoes,gotodomain2.com.YoushouldseeanotherWordPressinstallationsite.Justtobesurethatit’snotthesame,goaheadandinstalloneofthem.Or,gotodomain3.comandseewhathappenswhenadomainpointstotheserverwithouthavingitmatchinHAProxy.

ImplementationwithNginxNow,wearegoingtodothesamethingaswedidwithHAProxy,butwewillusetheexcellentwebserverNginx(http://nginx.org/en/)asourreverseproxyinstead.Nginxisafullfeaturedandreallyfastwebserverthatleavesasmallfootprintinthememory.

ThisishowNginxisdescribed:

“nginx[enginex]isanHTTPandreverseproxyserver,aswellasamailproxyserver,writtenbyIgorSysoev.Foralongtime,ithasbeenrunningonmanyheavilyloadedRussiansitesincludingYandex,Mail.Ru,VK,andRambler.AccordingtoNetcraft,nginxservedorproxied20.41%busiestsitesinNovember2014.Herearesomeofthesuccessstories:Netflix,Wordpress.com,FastMail.FM.”

Thisalsosoundslikewhatweneed,justlikeitdidwithHAProxy.

InstallingNginxNginxisavailableinallLinuxpackagemanagers,suchasaptitude/apt,yum,andothers,soaninstallcanbesimplydonewithapt-getinstallnginxoryuminstallnginx.Sinceit’sopensource,youcan,ofcourse,installitfromthesourceaswell.

ConfiguringNginxWearegoingtoaddtheconfigurationtoafilenamed/etc/nginx/conf.d/wp1.conf.

Createandopenthisfileinyourfavoritetexteditor:

server{

listen80;

server_namedomain1.com;

charsetUTF-8;

if($host!~^(domain1.com)$){

return444;

}

}

Thisblock,asyoucansee,makestheserverlistentoport80andtomatchthedomaindomain1.comforthisconfigurationtoapply.It’salwaysgoodtospecifytheservercharsetsothatthewebsitetextdoesnotgetthewrongencodingduringtheforwardingprocess;so,weaddthatlineaswell.Tojustlistentodomain1.comandnothingelse(Nginxusesthefirstconfigurationfoundasadefaultconfigurationifthere’snomatchintheservernamepart),wereturntheHTTPstatuscode444(noresponse)ontheotherrequeststhatgetinthere.

Whatarewegoingtodowiththerequestsonport80fordomain1.comthen?

Addthisinsidetheserver’sscope(curlybrackets):

location/{

proxy_passhttp://wp1;

proxy_set_headerX-Real-IP$remote_addr;

proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;

proxy_set_headerX-NginX-Proxytrue;

proxy_set_headerHost$host;

proxy_set_headerX-Forwarded-Proto$scheme;

proxy_redirectoff;

}

Thelocationblockwillmatchalltherequestssinceitmatches/.Wewillgetbacktotheproxy_passpartinawhile.Otherthanthis,you’llseethatwesetalotofheaders,mostofthemtellingourDockercontainertherequesters’realIPaddressandsoon.

Backtotheproxy_passpart.Thisisthepartthatactuallyforwardstherequest,tosomethingnamedwp1.Thisiscalledanupstream,whichwehavetodefine.

Addthisoutsidetheserver’sscope:

upstreamwp1{

server127.0.0.1:49187;

}

Thecompleteconfigurationfilenamed/etc/nginx/conf.d/wp1.confshouldlooklikethisnow:

upstreamwp1{

server127.0.0.1:49187;

}

server{

listen80;

server_namedomain1.com;

charsetUTF-8;

if($host!~^(domain1.com)$){

return444;

}

location/{

proxy_passhttp://wp1;

proxy_set_headerX-Real-IP$remote_addr;

proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;

proxy_set_headerX-NginX-Proxytrue;

proxy_set_headerHost$host;

proxy_set_headerX-Forwarded-Proto$scheme;

proxy_redirectoff;

}

}

SavethefileandonmostLinuxsystems,youcantestitforsyntaxerrorsusingthecommandsudo/etc/init.d/nginxconfigtestorsudoservicenginxconfigtest.

NoteMakesurethatyouhaveshutdownHAProxybeforeyoustartNginx,oryouwillgetanerrorsayingthatNginxcan’tbindtoport80.Youcandothiswiththefollowingcommand:

/etc/init.d/haproxystop

Ifthetestwassuccessful,wecannowrestart(orstart)theNginxserver.Again,usesudo/etc/init.d/nginxrestartorsudoservicenginxrestartonmostsystems.

HeadovertoyourwebbrowserandentertheURLdomain1.comtotakealookatourWordPressinstallationsite.Tomakesurenothingbutdomain1.comworks,trytogotodomain2.comandexpectnoresponse.

AddingmoredomainstoNginxToaddanotherdomaintomatchinNginx,youcancreateanewfileinthe/etc/nginx/conf.d/directoryandreloadtheNginxconfiguration,asshowninthefollowingcode:

cp/etc/nginx/conf.d/wp1.conf/etc/nginx/conf.d/wp2.conf

sed-i"s/wp1/wp2/g"/etc/nginx/conf.d/wp2.conf

sed-i"s/domain1/domain2/g"/etc/nginx/conf.d/wp2.conf

sed-i"s/49187/49188/g"/etc/nginx/conf.d/wp2.conf

#testconfig

/etc/init.d/nginxconfigtest

#reloadconfig

/etc/init.d/nginxreload

Copytheconfigurationfile,replaceafewnames,runconfigtest,andreloadNginx.

Trydomain1.cominyourbrowsertomakesureitstillworks.YoushouldstillseetheWordPressinstallationpage(unlessyouinstalledWordPress,ofcourse);headovertodomain2.comafterthattoseewhetherournewconfigurationisused.

Ifyouwanttotakeasitedown,justchangethefile’sextensionfrom.conftosomethingelseandreloadNginx.

AutomatingtheprocessofmappingdomainsThelimitationsinthissetuparethatit’smanualandhands-oneverytimeanewdomainisadded.Onmywebsite(http://oskarhane.com),I’vewrittensomeblogpostsabouthowthisprocesscouldbeautomatedandthosepostsaremymost-readpostsofalltime.

IwasverygladwhenIfoundnginx-proxybyJasonWilder.nginx-proxysolvesthisprobleminamorecleverwaythanmebymonitoringDockereventsviatheDockerRemoteAPI.

NoteYoucanreadmoreaboutnginx-proxyonitsGitHubpage(https://github.com/jwilder/nginx-proxy).

nginx-proxycomesasacontainerandwecanrunitbyexecutingthefollowingcommand:

dockerrun-d-p80:80-v/var/run/docker.sock:/tmp/docker.sock

jwilder/nginx-proxy

WearegivingthecontainerourDockersocket,soitcanlistenfortheeventsweareinterestedin,whicharecontainerstartsandstops.WealsobindtheDockerhosts’port80tothisnewcontainer,makingittheentrancecontainerforallincomingwebrequests.MakesureyoustopNginxontheDockerhostbeforestartingthenginx-proxycontainer.Youcandothiswiththefollowingcommand:

/etc/init.d/nginxstop

Whenacontainerstarts,nginx-proxycreatesannginxreverseproxyconfigfileandreloadsNginx—justlikewedid,butfullyautomatedwithnginx-proxy.

Totellnginx-proxywhichdomainwewantmappedtowhichcontainer,wemustrunourcontainerswithanenvironmentvariablenamedVIRTUAL_HOST.

Inourcrane.yamlfile,weaddanenvironmentvariableinthewprunsection:

containers:

wp:

image:oskarhane/wordpress

run:

volumes-from:["mydata"]

link:

-mymysql:mysql

publish:["80"]

detach:true

env:["VIRTUAL_HOST=domain1.com"]

Now,wejusthavetoliftthiswithcraneagaintohavethiscontainermappedtothedomaindomain1.comonport80:

craneliftweb--recreate

SummaryInthischapter,wesawhowyoucansolvetheproblemofhavingmultiplecontainersthatwanttoservedataonthesamepublicport.Welearnedwhataproxyserverandreverseproxyserverisandhowareverseproxyisusedinloadbalancing.

Weinstalledandconfiguredtwodifferentreverseproxies:HAProxyandNginx.Inmyworkflow,theNginxsetupfitsbetter,justcopyingafile,replacingafewwords,andthenreloadingNginxtohaveitworking.HAProxymightworkbetterinyoursetup;thechoiceisyoursandonecannotbesaidtobebetterthantheother.

nginx-proxyautomatestheprocessofcreatingareverseproxyforcontainersthatarestartedandisanOKsolutionforaPaaS,exceptforonething:easyandstraightforwarddeployment.That’swhatthenextchapterisallabout.

Chapter7.DeploymentonOurPaaSInthepreviouschapters,wewentfromsettingupourPaaSinaveryhands-onmannertoa“hacked-together-automated”waybycombiningtoolssuchasCraneandnginx-proxy.Onepartisstillmissing—howtodeployyourcode.

Inthischapterwewillgothroughthefollowingtopics:

TheproblemwithourcurrentsetupThetools/servicesavailableDokku—mini-HerokuSettingupaWordPressappwithDokku

TheproblemwithourcurrentsetupOurcurrentsetupconsistsofthreecontainers:aWordPresscontainer,aMySQLcontainerandadatavolumecontainer,tiedtogetherwithCrane.

ThemainproblemwithourcurrentsetupusingaVOLUMEcontainerasfilestorageisthatweneedawayintothevolumetoeditfiles.Asofnow,theonlywaytogetintoitisbymountingitonanothercontainer.

Anotherproblemisthatwedon’tversioncontroloursourcecode.WehavejustdownloadedWordPressandsomepluginsandleftitthere.WhatifweupdateWordPressormakesomeotherchanges?Wesurelywanttohavethatunderversioncontrol.

Ifwewanttokeeptheapplicationarchitectureasitis,therearetwooptions:

Createanewcontainerthatmountsourdatavolumecontainer,installit,andgetaccesstoitwithSSHInstallandopenaccesstoSSHinourWordPresscontainer

WithSSHinstalled,wecanaccessthecontainersshellfromaremotemachine,andso,wecaninstallGittoversioncontroltoourfiles.Inthisway,wecanconnectandpushnewcodeintothedatavolumecontainerwhenweneedto.

WhenconnectingwithSSH,youcangostraightintothecontainerwithoutneedingtoconnecttotheDockerhostsshell.

IfyouareokaywithconnectingtotheDockerhost,andfromthere,ifyouopenanewshelltogetintoyourdatavolumecontainer,athirdoptionwouldbetoSSHintoyourDockerhostsandthenaccessthecontainerwithdockerexec–itcontainer_name/bin/sh.

Whilethiscertainlyworks,thereareeasierwaystodoit.

Thetools/servicesavailableWhenwelookathostedPaaSprovidersavailabletoday,twoofthemcometomind—OpenShiftandHeroku.ManydevelopersloveHerokubecauseofitseaseofuse.Theirphilosophygivesahintwhy:

“DeveloperProductivity:

Developerproductivityisourbattlecry,atthecoreofeverythingwedo.Whyrequirethreestepswhenonewilldo?Whyrequireanyactionatallwhenzerostepswilldo?”

Developersusuallywanttospendtimeontheircode,notmanagingservers,deployment,andsoon.

OnHeroku,yougetaremoteGitrepositoryintowhichyoucanpushcode.Yourapp’slanguageanddependenciesareidentifiedbyspecialfiles,dependingonthelanguageyouuse.Environmentvariablesareusedforconfiguration,andyouinstructHerokuwhattoexecutebyspecifyingcommandsinaspecialfile,calledProcfile,thatyouincludeinyoursourcecode.

WheneveryourpushcodeintoyourremoteHerokuGitrepository,theapprebuildsandyouhaveitonlinerightaway.Ifyouhavespecialbuildrequirements,Herokuletsyoucreateyourownbuildpackswhereyoucanspecifyexactlywhat’stobedone.

Basically,ifyouwanttosetupaWordPressblogonHeroku,youneedtogothroughthesesteps:

1. LocallydownloadthelatestversionofWordPress.2. CreateaProcfileanddefinewhattoexecute(abuildpackthatrunsPHPandApache2

inthiscase).3. Createacomposer.jsonfilethatspecifiesthatPHPisadependency.4. MakesomechangestotheWordPressconfigfiles.5. CreatetheHerokuapp,addadd-ons(suchasadatabase),anddefineenvironment

variablesonHeroku.6. PushyourlocalcodeintoHeroku.

Whenyoumakeachangetothecode,youjustGitpushtoHerokutodeploythenewcode.YoucannoteditcodedirectlyonHeroku’sservers,norcanyouinstallthemesorplugins(youhavetodothatlocallyandpushthenewcode).

IfyouchoseaprovidersuchasOpenShiftinstead,youwillhaveabitmorecontroloveryourPaaS,YoucanconnecttoitwithSSHandalsostorestaticfilesdownloadedbyapps.

Itissomethinglikethiswearelookingfor;it’sjustthatwewanttohostourownplatformandhaveDockercontainersusedinthebackground.

Dokku–Docker-poweredmini-HerokuDokkucanbefoundathttps://github.com/progrium/dokku.Itisaprojectthatisdescribedbyitsauthorsasfollows:

“Dockerpoweredmini-Herokuinaround100linesofBash.”

Featurewise,DokkucarriesoutdeploymentinthesamewayasHerokudoes.Let’sinstallDokkuandseewhatitcandoforourPaaS.

InstallationDokkurequiresUbuntu14.04torun,andwestartbycreatinganewEC2instancerunningthat.

Hereisascreenshotofwhatwesee:

Whenwehavecreatedaninstanceandhaveitupandrunning,wecanstartbyinstallingDockeritself:

sudoapt-getinstalldocker.io

Whenthatisdone,wegoaheadandinstallDokku.

Therecommendedbootstrapbashinstallationdidn’tworkforme,soIclonedtherepoinstead:

cd/tmp

gitclonehttps://github.com/progrium/dokku.git

cddokku

sudomakeinstall

dokkuversion

NoteYoucanreadabouttheinstallationprocessontheofficialinstallationpageathttp://progrium.viewdocs.io/dokku/installation.

Theinstallationpartwilltakeawhile,butitshouldsucceed.

Accordingtothedocumentthroughtheprecedinglink,weshouldeditthe/home/dokku/VHOSTfiletoholdthecontentofadomainnameweplantouse.WeskipthisfornowbecauseitincludessettingsomeDNSrecords.Whenweleavethatfileempty,wewillbereachingourPaaSintheformofhttp://ip:port.Wewillcomebacktothisstepatalaterpoint.

TheonlystepleftnowistocreateansshkeypaironourlocalmachineandaddthepublicpartintheserveruserDokku’sauthorized_keysfilesothatwecanconnectwithGitinaverysecurewaywithoutusingapassword.

Onyourlocalmachine,usethesecommands:

cd~/.ssh

ssh-keygen–trsa

#Inamedmykeypairid_rsa

catid_rsa.pub

#copytheoutputsoyouhaveitinyourclipboard

Ontheserver,usethefollowing:

#Asyourubuntuuser

#Replace<publickey>withthekeyyoujustcopied

#<remoteuser>canbereplacedwithanything,like"remoteuser".

echo"<publickey>"|sudosshcommandacl-adddokku<remoteuser>

Ifyounameyourssh-keysomethingotherthanid_rsa,youwillhavetoedityourlocal.ssh/configfiletogetittowork.

NowtheDokkuconfigurationisdoneandweshouldbeabletostartusingit.

CreatingasampleDokkuappItistimeforustosetupademoappjustsothatyoucanlearntheprocess.Inthiscase,let’stakeHeroku’sNode.jssampleapp.

WestartoffbycloningHeroku’snode-js-sampleGitHubrepositorytogettheapp’scontent.Thefollowingtasksareallsupposedtobedoneonyourlocalmachine,andwhenIenterserver.com,youshouldentertheURLortheIPaddressofyourserver.Ifyouuseadomain,makesurethatyou’vesetupDNSrecordsforitorenteredarecordinyourlocal/etc/hostsfile:

#Clonetherepo

gitclonegit@github.com:heroku/node-js-sample.git

cdnode-js-sample

#AddaDokkugitremote

gitremoteadddokkudokku@server.com:first-app

#PushtoDokku

gitpushdokkumaster

Whenwepushtoanon-existingbranchorappnameinDokku,Dokkuwillcreateanewappanddeployit.Whenthepushisdone,youshouldseesomethinglikethisatthebottomoftheoutput:

=====>Applicationdeployed:

http://54.191.69.5:49154

Ofcourse,theIPaddressandportwillnotbethesameforyou.

Theoutputisdisplayed,asfollows:

Entertheip:portinyourwebbrowsertofindyourselfapagesayingHelloWorld.We’vejustdeployedourfirstapponDokku!

Tomodifyandredeploythesite,wecancreateafilenamedindex.htmlinsidepublic/folderinournode-js-sampleproject.Thisnodeappwillalwayslookforfilesinthepublicfolder.Iftherequestedfileisn’tfound,theappfallsbacktojustprintingHelloWorld.So,ifwecreateafileandrequestit,thenodeserverwillserveittous.

Pastethisasthecontentoftheindex.htmlfile:

<!DOCTYPEhtml>

<htmllang="en">

<head>

<metacharset="utf-8">

<title>Hello</title></head>

<body>

<h1>Firstedit!</h1>

</body>

</html>

It’sasimpleHTMLpage.

Let’sgoaheadandcreatethefileandpushit,asshowninthefollowingcode:

nanopublic/index.html

#pastetheHTML

#savethefile

#commityourchanges

gitaddpublic/index.html

gitcommit–m"AddedfirstHTMLpage."

#pushtodokku

gitpushdokkumaster

NoteNotefromtheoutputthattheportwillchangeeverytimeyoudeploy,sinceanewcontaineriscreatedandyouroldcontainerisshutdown.

Later,whenweaddadomainnametodeployon,theURLwill,ofcourse,bethesame.TheNginxconfigfileisupdatedupondeployment.Pointyourbrowsertothenewip:port,andyoushouldseeahugeheadlinesayingFirstedit!.

Wheneveryoumakeedits,justpushthem.Dokkuwilltakecareoftherest.

HowDokkuworksAsIdescribedthebasicstepofHerokuearlier,youmightrecognizethestepswhendeployingonDokku,andthatisalsoDokku’sgoal.Theywantpeoplelikeustofeelcomfortablewiththedeploymentprocess.

Dokkucanbeseenasthegluebetweenthefollowingtools:Docker,Buildstep,ssh-command,pluginhook,ssh,git,andnginx.Thesourcecodeisjustabout100lineslong,anditshipswithafewpluginsthattogethercontainabout500linesofcode.ThisisthepowerofDokku—anyonecanwritepluginstoextendthefunctionalityofDokku.

Wehavenotyetinstalledanyplugins,andacleaninstallationlikeourscandoonlybasicstuffsuchasdeploy,seeanapp’slogs,deleteanapp,andrunacommandintheapp’scontainer.Therearequitealotofplugins;theyarealllistedathttp://progrium.viewdocs.io/dokku/plugins.

ThereceiveprocessIfwetakealookatthemainDokkufile(nameddokkuintheprojectsroot),wenoticethatwheneverareceiveactionistriggered(whichhappenswhenwepushtothemasterbranch),weseethiscode:

case"$1"in

receive)

APP="$2";IMAGE="dokku/$APP"

echo"----->Cleaningup…"

dokkucleanup

echo"----->Building$APP…"

cat|dokkubuild$APP

echo"----->Releasing$APP…"

dokkurelease$APP

echo"----->Deploying$APP…"

dokkudeploy$APP

echo"=====>Applicationdeployed:"

dokkuurls$APP|sed"s/^//"

echo

;;

Throughthisoutputwecanrecognizewhenwehavepushedtothemaster.

Ifwefollowthepluginchainwhendeployiscalled,weendupwithapluginhooknamedpost-deploybeingcalled.Astandardplugin,namednginx-vhosts,istriggered,andthisinturncallsafunctioninsidethatpluginnamednginx:build-config.

Acodesnippetfromthatprecedingfilelookslikethis:

case"$1"in

nginx:build-config)

APP="$2";DOKKU_APP_LISTEN_PORT="$3";DOKKU_APP_LISTEN_IP="${4}"

VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"

WILDCARD_SSL="$DOKKU_ROOT/tls"

SSL="$DOKKU_ROOT/$APP/tls"

if[[-z"$DOKKU_APP_LISTEN_PORT"]]&&[[-f"$DOKKU_ROOT/$APP/PORT"

]];then

DOKKU_APP_LISTEN_PORT=$(<"$DOKKU_ROOT/$APP/PORT")

fi

if[[-z"$DOKKU_APP_LISTEN_IP"]]&&[[-f"$DOKKU_ROOT/$APP/IP"]];

then

DOKKU_APP_LISTEN_IP=$(<"$DOKKU_ROOT/$APP/IP")

fi

[[-f"$DOKKU_ROOT/$APP/ENV"]]&&source$DOKKU_ROOT/$APP/ENV

if[[!-n"$NO_VHOST"]]&&[[-f"$DOKKU_ROOT/$APP/VHOST"]];then

...

NGINX_CONF="$PLUGIN_PATH/nginx-vhosts/templates/nginx.conf"

SCHEME="http"

...

APP_NGINX_TEMPLATE="$DOKKU_ROOT/$APP/nginx.conf.template"

if[[-f$APP_NGINX_TEMPLATE]];then

echo"----->Overridingdefaultnginx.confwithdetected

nginx.conf.template"

NGINX_CONF=$APP_NGINX_TEMPLATE

fi

xargs-iecho"----->Configuring{}..."<$VHOST_PATH

#IncludeSSL_VHOSTSsowecanredirecthttptohttpsonthat

hostnameaswell

NOSSL_SERVER_NAME=$(echo$NONSSL_VHOSTS$SSL_VHOSTS|tr'\n''')

if[[-n"$DOKKU_APP_LISTEN_PORT"]]&&[[-n"$DOKKU_APP_LISTEN_IP"

]];then

echo"----->Creating$SCHEMEnginx.conf"

echo"upstream$APP{server

$DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT;}">

$DOKKU_ROOT/$APP/nginx.conf

eval"cat<<<\"$(<$NGINX_CONF)\">>$DOKKU_ROOT/$APP/nginx.conf"

echo"----->Runningnginx-pre-reload"

pluginhooknginx-pre-reload$APP$DOKKU_APP_LISTEN_PORT

$DOKKU_APP_LISTEN_IP

echo"Reloadingnginx"

restart_nginx

fi

else

if[[-f"$DOKKU_ROOT/$APP/VHOST"]];then

echo"----->VHOSTsupportdisabled,deleting$APP/VHOST"

rm"$DOKKU_ROOT/$APP/VHOST"

fi

if[[-f"$DOKKU_ROOT/$APP/nginx.conf"]];then

echo"----->VHOSTsupportdisabled,deletingnginx.conf"

rm"$DOKKU_ROOT/$APP/nginx.conf"

echo"----->VHOSTsupportdisabled,reloadingnginxafter

nginx.confdeletion"

restart_nginx

fi

fi

;;

Ifwelookthroughthatcode,wecanseethatitlooksforadomainnameinthe$DOKKU_ROOT/$APP/VHOSTfile,andifthatisfound,setssomeconfigvariablesandinsertsthemintoacopyofthetemplates/nginx.conffile.

Thatfilehasthesecontents:

server{

listen[::]:80;

listen80;

server_name$NOSSL_SERVER_NAME;

location/{

proxy_passhttp://$APP;

proxy_http_version1.1;

proxy_set_headerUpgrade\$http_upgrade;

proxy_set_headerConnection"upgrade";

proxy_set_headerHost\$http_host;

proxy_set_headerX-Forwarded-Proto\$scheme;

proxy_set_headerX-Forwarded-For\$remote_addr;

proxy_set_headerX-Forwarded-Port\$server_port;

proxy_set_headerX-Request-Start\$msec;

}

include$DOKKU_ROOT/$APP/nginx.conf.d/*.conf;

}

Nowthatlooksverymuchlikethenginxconfigwecreatedinthelastchapter,right?Thepost-deploypartofDokkuisbasicallyJasonWilder’snginx-proxy.Theyaccomplishthesameresult,buttheygetthereinverydifferentways.

DokkupluginsAdd-onsinHerokuarecalledpluginsinDokku.SincewecannotspecifydockerruncommandparametersdirectlyfromDokku,weneedpluginstoconnectcontainersandadddatavolumecontainers.

Here’salistofafewusableDokkupluginsthatwe’llsoonuse.

DokkudomainspluginDokkudomainpluginenablesyoutospecifymultipledomainsinoneapp.Bydefault,onlyoneURLcanbemappedtoanapp:

dokkudomains:setmyawesomeapp.comwww.myawesomeapp.com

URL:https://github.com/wmluke/dokku-domains-plugin

Dokku-docker-optionsWiththisplugin,youcanpassanyoptionstotheDockerdaemonwhendockerruncommandisexecuted.Itcanbeusedtomountvolumes,linkcontainers,andsoon:

dokkudocker-options:addmyapp"-v/host/path:/container/path"

dokkudocker-options:addmyapp"-linkcontainer_name:alias"

URL:https://github.com/dyson/dokku-docker-options

VolumepluginforDokkuHere’sapluginthatenablesyoutomountvolumesonyourservicecontainers.Italsohascommandstodump(export)andrestorethedata:

dokkuvolume:addfoo/path/in/container

dokkuvolume:dumpfoo/path/in/container>foo.tar.gz

URL:https://github.com/ohardy/dokku-volume

Dokku-linkYoucanlinkcontainerswiththisplugin:

dokkulink:create<app>NAME[ALIAS]

dokkulink:delete<app>NAME[ALIAS]

URL:https://github.com/rlaneve/dokku-link

MariaDBpluginforDokkuThispluginenablesyoutocreateanduseMariaDBcontainers.MariaDBcanbeusedasareplacementforMySQLandisgenerallyfaster:

dokkumariadb:create<app>

dokkumariadb:link<app><db>

dokkumariadb:dumpraw<app>

URL:https://github.com/Kloadut/dokku-md-plugin

MySQLplugin:https://github.com/hughfletcher/dokku-mysql-plugin

SettingupaWordPressappwithDokkuNowthatwehaveplayedaroundwithDokkuforawhile,exploringhowitworksandwhatpluginsareavailable,it’stimetosetupaWordPresssite.Afterall,that’swhywewereexploringitinthefirstplace.

Thisiswhatwearegoingtodo:

1. CreateanewlocalGitrepositoryanddownloadWordPressonit.2. InstalltheMariaDBplugin,createadatabase,andlinkittoourapp.3. ConfigureWordPresstoconnecttoourlinkeddatabase.

Onyourlocalcomputer,downloadandunpackthelatestversionofWordPressandcreateanewGitrepository.Createacomposer.jsonfiletotellDokkuthatthisisaPHPappwearecreating.

NoteYoucanreadmoreabouthowtohintDokkuonwhattypeofappyouarecreatingathttps://devcenter.heroku.com/articles/buildpacks(yes,DokkuusesHerokubuildpacks)andlookstodetectfunctions.DokkuusesalibrarycalledBuildsteptomakeapplicationbuildsusingDockerandBuildpacks.

Let’sgoaheadandgetstartednow.

Iusedaserveronmydomain,ohdokku.com,forthisapp:

#DownloadWordpress

curl-Ohttps://wordpress.org/latest.zip

unziplatest.zip

mvwordpresswp1

cdwp1

#CreateanewGitrepo

gitinit

gitadd.

gitcommit–m"Initialcommit."

#Createacomposer.jsonfiletotellDokkuweareusingphp

echo'{}'>composer.json

gitadd.

gitcommit-am"Addcomposer.jsonforPHPappdetection."

#AddaremotesowecanpushtoDokku

gitremoteadddokkudokku@ohdokku.com:wp1

OntheserverwehavetoinstalltheMariaDBorMySQLplugin:

cd/var/lib/dokku/plugins

sudogitclone--recursivehttps://github.com/Kloadut/dokku-md-plugin

mariadb

cdmariadb/dockerfiles/

gitcheckoutmaster

cd../../

sudodokkuplugins-install

Backtotheclientside(youcandothisontheserveraswell,butthewholepointofthistypeofPaaSisbeingabletodoallofthisrepetitivestuffontheclient).

Theresultisasfollows:

Asyoucansee,theoutputfromthecreatecommandwillshowourdatabasecredentials.

Nowthatthedatabaseissetup,wecangoaheadandpushourappforthefirsttime:

gitpushdokkumaster

YoushouldnoticethatDokkudetectsthatyouarepushingaPHPapp.Sincewehaven’tspecifiedanythingatallinourcomposer.jsonfile,adefaultpackageofPHPandApache2willfireup.

CreateaMariaDBdatabasecalledwp1_db:

sshdokku@ohdokku.commariadb:createwp1_db

sshdokku@ohdokku.commariadb:linkwp1wp1_db

Ifweenterip:portinabrowser,aknownpagewelcomesus—theWordPressinstallationpage.WhenweclickontheContinuebutton,weseethatwecan’tcontinuebeforewecreateawp-config.phpfile.

WehavejustcreatedthelinkbetweentheMariaDBcontainerandtheWPcontainer,butwehaven’tmadethelinkincodeyet.WordPresshasnoideahowtoconnecttothedatabase.

Westartoffbyrenamingthewp-config-sample.phpfiletowp-config.phpandopeningthefileinaneditor:

//**MySQLsettings-Youcangetthisinfofromyourwebhost**//

/**ThenameofthedatabaseforWordpress*/

define('DB_NAME',getenv('DB_NAME'));

/**MySQLdatabaseusername*/

define('DB_USER','root');

/**MySQLdatabasepassword*/

define('DB_PASSWORD',getenv('DB_PASSWORD'));

/**MySQLhostname*/

define('DB_HOST',getenv('DB_HOST').":".getenv('DB_PORT'));

EditthecredentialsasyoujustsawtomakeWordPresslookforenvironmentvariablesthatourlinkedMariaDBgivesus:

gitadd–A.

gitcommit–m"Addwp-config.phpandaddcredentials."

gitpushdokkumaster

Waituntilyougetanewip:portthatourappisdeployedto,andthenentertheinfoinyourwebbrowser.

NowyoushouldbeabletoinstallWordPress.

Theoutputisasfollows:

StartingmultipleappsTostartmultipleappswithDokku,justrepeatthesimpleprocess,asfollows:

1. CreatealocalGitrepositorywithWordPressinit,andcreatearemoteGitrepository.2. CreateandlinkadatabasewiththeMariaDBplugin.

Edityourwp-config.phpfile.

3. Pushtodeploy.

ThenameyousetonyourappwhenaddingtheremotefromGitcommand:

gitremoteadddokkudokku@ohdokku.com:wp1

ThiscommandwillcreatetheURLtotheWordPresssite(wp1.ohdokku.com).Youcansetacompletecustomdomainasthenamelike:gitremoteadddokkudokku@ohdokku.com:wp1.oskarhane.comthatwillworkifIpointwp1.oskarhane.comtomyserver.

AddingadomaintoDokkuIwaitedwithsettingupdomainstoDokku,sinceitinvolvesloggingintoaDNSproviderandsettingupDNSrecordstopointthedomaintoourserver.WesetupDNSrecordstopointourdomainnametoourserver’sIPaddresssothatourservercanbereachedbyenteringourdomainnameinthewebbrowser’slocationbar.

IusuallyuseAmazonRoute53tohandleDNSfordomains,sincethey’reverystableandeasytouse.Itcostsaboutadollaramonthforlow-trafficsites.ThesetupisthesameforanyDNSprovider.Youhavetoaddtworecords,oneforyourdomain.comandonefor*.yourdomain.com.

TherecordswearegoingtoenterareA-records,whichmeansthatwepointthedomainnamestoaspecificIPv4address.TheTimeToLive(TTL)valueisnotimportantrightnow,butitmeansTTLandtellsallotherDNSserversthatgetrequestsforthisdomainhowlongtheycancachethecurrentvalue.

Theoutputisasfollows:

Youshould,ofcourse,changetheIPtothepublicIPyourserverhas.WhensettingtheA-recordforthewildcardsubdomains,justenter*intheinputfieldatthetop.

ToseewhetheryourDNSprovidercanresolveyourdomainname,executepingyourdomain.cominaterminal.You’llseetheresolvedIPrightthere.Ifyou’vejustboughtthedomain,youshouldbeabletoseetheresultrightaway,butifyou’veusedthedomainforawhile,theoldTTLvaluemightdelaytheeffectabit.

IfyouwanttowaitforthesettingofDNSrecords(whichiscommonduringdevelopment),youcansetlocalrecordsonyourcomputerbyeditingthe/etc/hostsfile,asshowninthefollowingcommandsnippet:

sudonano/etc/hosts

#Addthislinetothefile

54.191.69.5ohdokku.com

#Saveandexit

Onethingtorememberhereisthatyoucan’tenterrecordsforwildcardsubdomains.Ifyouplantodevelopmultipleappsonsubdomains,youhavetoenteronerecordforeachofthem.Also,don’tforgettoremovetheserecordswhenyou’redone;itcangetquiteconfusing(andinteresting)whenyouforgetyouhaverecordsforthedomainsyouused.

OntheDokkuserver,createafilenamed/home/dokku/VHOSTandenteryourdomain.cominit.

Allappsbeingcreatedfromnowonwillbesubdomainsofthisdomain,unlessyougivetheappscompletedomainnames.

MorenotesonDokkuJustlikeHeroku,Dokkumakesiteasyfordeveloperstodeployandpushcode.IfyoudownloadaWordPresspluginstraightfromyourDokkuapp,itwillbegonewhenyourestartyourDokkuapp.Itisadvisabletokeepalocalcopythatcaneasilybestartedoradev,test,andstagingserverthatyoucandownloadnewpluginsonandpushtoyourDokkuappfromtoensuretheyarepersistent.

TipImagesandvideosshouldbeuploadedtosomethingsuchasAmazonviaapluginwhenusingthiskindofinfrastructure.

YoumustalsohaveyourWordPresssitesende-mailsfromanexternale-mailprovider,suchasMandrill.ApluginlikeWPMailSMTPwillsolvethatforyou.

Westillhaveafewmanualsteps(forexample,downloadingWordPressandeditingwp-config.php)todowhendeployingaWordPressapponDokku,butthetaskofcreatingacustomBuildsteptoremovethemanualpartsisbeyondthescopeofthisbook.

AnotheroptionistohaveComposerhandletheinstallationofWordPresswiththecomposer.jsonfile,butWordPressdoesnotofficiallysupportthisanditrequiresafewhacks,soI’llleavethatuptoyou.

NoteIfyouwanttolearnmoreaboutcomposer,youcangototheprovidedlinkhttp://wpackagist.org.

SummaryInthischapter,wewentallthewaytocreateourownPaaSbyaddingdeploymenttotheprocess.Whatwelookedintouptothischapterwasallaboutorganizingcontainersanddirectincomingtrafficsothatvisitorscanreachthecorrectcontainer.

WithDokku,wedon’thavetoworryaboutthat;allwehavetocareaboutisourcode.Assoonaswepushourcode,Dokkutakesoveranddoestherightthings.Dokkumakesitlookreallyeasyandthatiswhy,Istartedfrommanuallycreatingandlinkingcontainersandconfiguringreverseproxies—sothatyouwouldunderstandwhatDokkudoes.

Thenextchaptertakesustothebleedingedge:what’sbeingdevelopedrightnowthatcantakeprivatePaaSwithDockeronestepfurther?

Chapter8.What’sNext?Sofar,wehaverunourPaaSonasinglehost,whichcanbeaproblemifweneedtoscaleout.Thereisalothappeninginthisspace,andIhaveselectedafewprojectsthatIwillintroduceinthischapter.Theseprojectsvaryalotinhowmaturetheyare,oneisreadyforuseinproductionwhiletheotherisinaprototypestate.Inthischapter,wewillcoverthefollowingtopics:

WhatisaTwelve-Factorapp?FlynnDeisRocketOrchestrationtools

WhatisaTwelve-Factorapp?Manyoftoday’sappsare,infact,webappsthatyouruninyourwebbrowser.Gmail,Slack,Wunderlist,Trello,andsoonareallwebappsorsoftware-as-a-service.

ItisthesekindofappsthataresuitabletoberunonaPaaS.

TheTwelve-Factorappisamethodologyforbuildingsoftware-as-a-serviceappsthatfulfillthefollowingcriteria:

UsedeclarativeformatstosetupautomationaswellastominimizethetimeandcostfornewdeveloperswhojointheprojectHaveacleancontractwiththeunderlyingoperatingsystem,offeringmaximumportabilitybetweenexecutionenvironmentsSuitablefordeploymentonmoderncloudplatforms,obviatingtheneedforserversandsystemsadministrationMinimizedivergencebetweendevelopmentandproduction,enablingcontinuousdeploymentformaximumagilityScaleupwithoutsignificantchangestotooling,architecture,ordevelopmentpractices

TheTwelveFactorsaredefinedasfollows:

Codebase(Onecodebasetrackedinrevisioncontrol,manydeploys):ThisputsyourcodeinaversioncontrolsystemsuchasGit.Dependencies(Explicitlydeclareandisolatedependencies):Thislistsalltheversionsofallthelibrariesthatyourappdependsoninasingleplace.Config(Storeconfigintheenvironment):Sinceconfigwillvarybetweenenvironmentssuchastheusernameorpasstoadatabase,itshouldnotbepartofthecode.Youcansettheconfigfileinenvironmentvariablesandhaveyourappreadtheminatruntime.BackingServices(Treatbackingservicesasattachedresources):Thesehaveallthebackingservices,suchasmailserver,database,andcachesystem,amongothers.ThesewillbereferencedbyaURLendpoint.Thiswayyourcodedoesn’thavetocarewhetherthebackingserviceisrunningonthesamemachineoracrosstheworld.Build,release,run(Strictlyseparatebuildandrunstages):Thebuildstagecreatesbundles,assets,andbinaries.Thisisthedeveloper’sjob.Whenyou’veplacedapackageonaserver,youarereadytoentertherunstagebystartingyourapplicationandmakingitavailableontheserver.Thisstageshouldbeaseasyaspossiblesothatanyonecandoit.Processes(Executetheappasoneormorestatelessprocesses):Asstatedearlierinthisbook,youshouldseparateyourapplicationdatafromyourapplicationservice,thatis,itmakestheservicestateless.Allthestatesshouldbeinthesharedstoragesanddatabases.Portbinding(Exportservicesviaportbinding):Anexampleisbackingservices;yourserviceshouldbereachableviaaURLendpoint.Concurrency(Scaleoutviatheprocessmodel):Thiskeepseveryprocessasan

independentservice.Thiswayyoucanscalejustthepartsofyourappthatreallyneedtobescaled.Disposability(Maximizerobustnesswithafaststartupandgracefulshutdown):Thisisforappstartup,whichshouldbefast,andyourappshouldbeabletorecoverfromacrashbyitself.Dev/prodparity(Keepdevelopment,staging,andproductionassimilaraspossible):Thiskeepsyourdevelopmentenvironmentandsetupasequalaspossibletoyourproductionenvironmentandsetup.Dockerreallyexcelshere.Logs(Treatlogsaseventstreams):Placeyourapp’serrorlogsintoacentralplacewhereyougetnotifiedwhenanewerrorhasoccurred.Adminprocesses(Runadmin/managementtasksasone-offprocesses):Ifyouaredoingadministrativetasks,runthemonamachineintheproductionenvironmentwiththelatestcodebase.Youshouldrunqueriesdirectlyagainstthedatabase.

Iencourageyoutogotohttp://12factor.netinordertoreadmoreabouteachoneoftheTwelveFactors.It’sagoodread;youwillgetanunderstandingofwhysomedesigndecisionsweremadeonthefollowingprojects.

Flynn

TheguywhocreatedDokku,JeffLindsay,hasalsoco-createdFlynn.Flynnislikeasuper-Dokkuthat,amongotherthings,letsyourunyourPaaSonmultiplehosts.

“Flynnistwothings:

Adistributionofcomponentsthatout-of-the-boxgivescompaniesareasonablestartingpointforaninternalplatformforrunningtheirapplicationsandservices.

Thebannerforacollectionofindependentprojectsthattogethermakeupatoolkitorlooseframeworkforbuildingdistributedsystems.

Flynnisbothawholeandmanyparts,dependingonwhatismostusefulforyou.Thecommongoalistodemocratizeyearsofexperienceandbestpracticesinbuildingdistributedsystems.Itisthesoftwarelayerbetweenoperatorsanddevelopersthatmakesboththeirliveseasier.”

IhavetriedusingFlynnafewtimes,butIhavealwaysgonebacktousingDokkuagainbecauseIfindDokkueasiertouse,andmyclientsdon’tneedtheextrafeaturessuchasmultihostPaaS.

URL:http://flynn.io

Status:Thisisnotsuitableforuseintheproductionenvironmentbecauseit’sinabetastage.

Deis

DeisisbuiltonalightweightLinuxdistributionthatisbuilttoruncontainers,calledCoreOS,andonDockertotakeadvantageofthedistributedservices,suchasetcd,availablethere.

“DeisisalightweightapplicationplatformthatdeploysandscalesTwelve-FactorappsasDockercontainersacrossaclusterofCoreOSmachines.”

IfoundDeistobeaverypromisingprojectandwouldliketoworkwithitmore.IhavebarelytoucheditbutwhatIhaveseensofarlooksgood.

DeiscandeployanylanguageorframeworkrunningonLinuxusingDocker,anditalsoincludesHerokubuildpacksforRuby,Python,Node.js,Java,Clojure,Scala,Play,PHP,Perl,Dart,andGo.

TheworkflowisHeroku-likeandyoujustneedtodeploytwelve-factorapps,thatis,savetheapplicationstateinabackingservice.

Funfact:Deisfinanciallybacks/supportsDokku.

URL:http://deis.io

State:Deisisreadyforproductionfromversion1.0.

Rocket

CoreOShasbeenoneofthemostpopularwaystorunamultihostDockerPaaS.TheyhavedoneexcellentworkandhavebuiltsomemultihostPaaStools,suchasDeis,thatuseCoreOStoolsandservicestodelivertheirversionofPaaS.

InDecember2014,theCoreOSteamdecidedtoannouncetheirowncontainerruntime:Rocket.RocketisadirectcompetitortotheoriginalDocker.ThereasonwhytheyarelaunchingRocketisbecausetheybelieveDockerhaslostitsinitialidea:runningreusablestandardcontainers.TheCoreOSteambelievesthatDockerissteppingawayfromtheinitialideabyaddingmoreandmorefeaturesandservicesaroundtheDockerenvironment.

“Rocketisanewcontainerruntime,designedforcomposability,security,andspeed.TodaywearereleasingaprototypeversiononGitHubtobegingatheringfeedbackfromourcommunityandexplainwhywearebuildingRocket.”

AccordingtotheCoreOSteam,theywillcontinuetohaveCoreOStobetheperfectthingtorunDocker.Iguesswewillseewhathappensinthefuture,butIhopetheystandbytheirwords.

URL:https://github.com/coreos/rocket

State:Rocketisinitsveryearlystateandnotreadyforproduction.

OrchestrationtoolsThetoolsIhaveintroducednowaretoolsthatwillhelpyoukeepyourmindonthecodeandgiveyouaneasywaytodeployyourappstoproduction.Ifyouaremoreinterestedinanorchestrationtool—atoolthathelpsyoumanagecontainerclusters—thereareafewofthemoutthereaswell.ThetoolsthatcurrentlycometomindareGoogle’sKubernetes,ApacheMesos/Marathon,CoreOSFleet,andthesoontobereleasedSwarmfromDocker.

SummaryWhenyoufeelit’stimetomoveyourPaaSfromasinglehosttoscaleacrossmultiplehosts,thesetoolsarewhatyoushouldbelookingfor.I’msuresomeworthycompetitorswillpopupinthefuturesincethisisahotarearightnow.

IndexA

AmazonURL/DockeronAmazonEC2

AmazonEC2using/DockeronAmazonEC2Docker,installing/InstallationDocker,upgrading/UpgradingDockeronAmazonEC2

Apachepreparing,forcaching/Preparingforcaching

Bbaseimage

about/TheDockerimageBuildpacks

referencelink/SettingupaWordPressappwithDokkuBuildstep

about/SettingupaWordPressappwithDokkuBusyBox

about/Datavolumeimage

Ccommand-lineinterface

about/TheDockercommand-lineinterfacecommands,Docker

about/DisplayingHelloWorlddockerps/DisplayingHelloWorlddockerps-a/DisplayingHelloWorlddockerimages/DisplayingHelloWorlddockerrun/DisplayingHelloWorlddockerstop/DisplayingHelloWorld

composerreferencelink/MorenotesonDokku

containerabout/TheDockercontainer

containerIDabout/TheDockercontainer

containersabout/WhatisDocker?parameters,passing/Passingparameterstocontainersconnecting,manually/Manuallyconnectingcontainersconnecting,DockerComposeused/ConnectingcontainersusingDockerComposeconnecting,Craneused/ConnectingcontainersusingCranesetupissue/Theproblemwithourcurrentsetup

Craneused,forconnectingcontainers/ConnectingcontainersusingCraneabout/ConnectingcontainersusingCraneinstalling/InstallingCraneusage/Usageliftcommand/Usagegraphcommand/Usagelogscommand/Usagestatuscommand/Usageconfiguring/Configuration

Ddatavolumecontainer

mounting/Mountingadatavolumecontainerexecuting/Runningadatavolumecontainercontents,exploring/Exploringthecontentsofadatavolumecontainer

datavolumeimagecreating/CreatingadatavolumeimagesBusyBox/Datavolumeimagemountpoints,exposing/ExposingmountpointsDockerfile/TheDockerfile

datavolumesabout/Datavolumeshostdirectory,mounting/Mountingahostdirectoryasadatavolumedatavolumecontainer,mounting/Mountingadatavolumecontainerbackup/Backingupandrestoringdatavolumesrestoring/Backingupandrestoringdatavolumes

Deisabout/DeisURL/Deis

Dockerabout/WhatisDocker?URL/WhatisDocker?URL,forinstallation/Userpermissions

DockerComposeused,forconnectingcontainers/ConnectingcontainersusingDockerComposeabout/ConnectingcontainersusingDockerComposeinstalling/InstallingDockerComposebuildcommand/BasicDockerComposecommandskillcommand/BasicDockerComposecommandslogscommand/BasicDockerComposecommandsportcommand/BasicDockerComposecommandspscommand/BasicDockerComposecommandspullcommand/BasicDockerComposecommandsrmcommand/BasicDockerComposecommandsruncommand/BasicDockerComposecommandsscalecommand/BasicDockerComposecommandsstartcommand/BasicDockerComposecommandsstopcommand/BasicDockerComposecommandsupcommand/BasicDockerComposecommandsservice/Serviceruncommand,using/Usingtheruncommandscalecommand,using/UsingthescalecommandPaaS,settingup/SettingupourPaaSwithDockerCompose

Dockerfileabout/Browsingrepositoriescreating,onWordPressimage/Makingourchangespersist

Dockerfile,forPHP5.6URL/Raisingtheuploadlimit

DockerHubregistryabout/TheDockerRegistryHubURL/TheDockerRegistryHubrepositories,browsing/Browsingrepositoriespublishedimages,exploring/Exploringpublishedimagesimage,publishing/PublishinganimageontheDockerRegistryHubimage,publishingwithautomatedbuildoption/Automatedbuilds

Dockerimageabout/TheDockerimagebaseimage/TheDockerimageparentimages/TheDockerimagehosting,onGitHub/HostingonGitHubpublishing,onDockerregistryhub/PublishingontheDockerRegistryHub

dockerimagescommandabout/DisplayingHelloWorld

DockeronAmazonEC2installing/Installationopenports/Openportsupgrading/UpgradingDockeronAmazonEC2userpermissions/Userpermissions

DockeronMacOSXinstalling/DockeronMacOSX,Installationupgrading/UpgradingDockeronMacOSX

DockeronUbuntuTrusty14.04LTSinstalling/DockeronUbuntuTrusty14.04LTSupgrading/UpgradingDockeronUbuntuTrusty14.04LTSuserpermissions/Userpermissions

DockeronWindowsinstalling/DockeronWindows,Installationupgrading/UpgradingDockeronWindows

dockerps-acommandabout/DisplayingHelloWorld

dockerpscommandabout/DisplayingHelloWorld

DockerregistryhubDockerimage,publishing/PublishingontheDockerRegistryHub

dockerruncommandabout/DisplayingHelloWorld

dockerstopcommand

about/DisplayingHelloWorldDokku

about/Dokku–Docker-poweredmini-HerokuURL/Dokku–Docker-poweredmini-Herokuinstalling/InstallationURL,forinstallation/Installationsampleapp,creating/CreatingasampleDokkuappdeploying/HowDokkuworksreceiveprocess/Thereceiveprocessplugins/DokkupluginsWordPressapp,settingup/SettingupaWordPressappwithDokkumultipleapps,starting/Startingmultipleappsdomains,adding/AddingadomaintoDokkuWordPressapp,deploying/MorenotesonDokku

Dokku-docker-optionsabout/Dokku-docker-optionsURL/Dokku-docker-options

Dokku-linkpluginabout/Dokku-linkURL/Dokku-link

Dokkudomainspluginabout/DokkudomainspluginURL/Dokkudomainsplugin

domainsmapping,nginx-proxyused/Automatingtheprocessofmappingdomainsadding,toDokku/AddingadomaintoDokku

FFlynn

about/FlynnURL/Flynn

GGitHub

imagesources,hosting/HostingimagesourcesonGitHubURL/HostingimagesourcesonGitHubDockerimage,hosting/HostingonGitHub

HHAProxy

about/ImplementationwithHAProxyURL/ImplementationwithHAProxyinstalling/InstallingHAProxyconfiguring/ConfiguringHAProxymultipledomains,adding/AddingmoredomainstoHAProxy

Herokuabout/Thetools/servicesavailable

hostdirectorymounting,asdatavolume/Mountingahostdirectoryasadatavolume

Iimagesources

hosting,onGitHub/HostingimagesourcesonGitHubinstallation,Crane

about/InstallingCraneinstallation,Docker

onUbuntuTrusty14.04LTS/DockeronUbuntuTrusty14.04LTSonMacOSX/DockeronMacOSX,InstallationonWindows/DockeronWindows,InstallationonAmazonEC2/Installation

installation,DockerComposeabout/InstallingDockerCompose

installation,Dokkuabout/Installation

installation,HAProxyabout/InstallingHAProxy

installation,Nginxabout/InstallingNginx

installation,WPMailSMTPabout/Plugininstallation

installation,WPSuperCacheabout/Plugininstallation

MMacOSX

Docker,installing/DockeronMacOSX,InstallationDocker,upgrading/UpgradingDockeronMacOSX

MariaDBpluginabout/MariaDBpluginforDokkuURL/MariaDBpluginforDokku

multiplecontainers,withsameservicesproblem/Explainingtheproblemsolution,finding/Findingasolutionsolution,implementing/Implementingthesolution

MySQLdockerrepositoryURL/Exploringpublishedimages

NNginx

about/ImplementationwithNginxURL/ImplementationwithNginxinstalling/InstallingNginxconfiguring/ConfiguringNginxmultipledomains,adding/AddingmoredomainstoNginx

nginx-proxyused,formappingdomains/AutomatingtheprocessofmappingdomainsURL/Automatingtheprocessofmappingdomains

OOpenShift

about/Thetools/servicesavailableorchestrationtools

about/OrchestrationtoolsOSXinstaller

URL/Installation

PPaaS

settingup,withDockerCompose/SettingupourPaaSwithDockerComposeparameterizedimage

creating/Creatingaparameterizedimageparentimages

about/TheDockerimageplugins,Dokku

about/DokkupluginsDokkudomainplugin/DokkudomainspluginDokku-docker-options/Dokku-docker-optionsvolumeplugin/VolumepluginforDokkuDokku-linkplugin/Dokku-linkMariaDBplugin/MariaDBpluginforDokku

Procfileabout/Thetools/servicesavailable

proxyserverabout/Findingasolution

publishedimagesexploring/Exploringpublishedimages

Rreceiveprocess,Dokku

about/Thereceiveprocessrepositories

browsing/Browsingrepositoriesreverseproxies

about/FindingasolutionRocket

about/RocketURL/Rocket

Ssolution,multiplecontainerswithsameservices

implementing,withHAProxy/ImplementationwithHAProxyimplementing,withNginx/ImplementationwithNginx

Ttags

about/TheDockerimageTimetolive(TTL)

about/AddingadomaintoDokkutools/services

OpenShift/Thetools/servicesavailableHeroku/Thetools/servicesavailable

Twelve-Factorappabout/WhatisaTwelve-Factorapp?URL/WhatisaTwelve-Factorapp?

twelvefactorscodebase/WhatisaTwelve-Factorapp?dependencies/WhatisaTwelve-Factorapp?config/WhatisaTwelve-Factorapp?backingservices/WhatisaTwelve-Factorapp?build/WhatisaTwelve-Factorapp?release/WhatisaTwelve-Factorapp?run/WhatisaTwelve-Factorapp?processes/WhatisaTwelve-Factorapp?portbinding/WhatisaTwelve-Factorapp?concurrency/WhatisaTwelve-Factorapp?disposability/WhatisaTwelve-Factorapp?dev/prodparity/WhatisaTwelve-Factorapp?logs/WhatisaTwelve-Factorapp?adminprocesses/WhatisaTwelve-Factorapp?

UUbuntuTrusty14.04LTS

Docker,installing/DockeronUbuntuTrusty14.04LTSDocker,upgrading/UpgradingDockeronUbuntuTrusty14.04LTS

Vvolumeplugin

about/VolumepluginforDokkuURL/VolumepluginforDokku

WWindows

Docker,installing/DockeronWindows,InstallationDocker,upgrading/UpgradingDockeronWindows

WindowsinstallerURL/Installation

WordPressconfiguring/Movingfromthedefaults

WordPressappsettingup,withDokku/SettingupaWordPressappwithDokkumultipleapps,starting/Startingmultipleappsdomains,addingtoDokku/AddingadomaintoDokkudeploying,onDokku/MorenotesonDokku

WordPressDockerimageURL/Exploringpublishedimages

WordPressimagecreating/TheWordPressimageobjective/Ourobjective

WordPressimage,objectiveApache,preparingforcaching/Preparingforcachinguploadlimit,raising/RaisingtheuploadlimitWPSuperCache,installing/PlugininstallationWPMailSMTP,installing/Plugininstallation

WPMailSMTPinstalling/Plugininstallation

WPSuperCacheinstalling/Plugininstallation