Build Your Own PaaS with Docker - مهندسی داده · 2015-04-21 · Build Your Own PaaS with...
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<[email protected]>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<[email protected]>,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<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.
QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,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:
~/.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:
[email protected]: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<[email protected]>
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<[email protected]>
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
[email protected]:heroku/node-js-sample.git
cdnode-js-sample
#AddaDokkugitremote
[email protected]: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
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:
[email protected]:createwp1_db
[email protected]: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:
ThiscommandwillcreatetheURLtotheWordPresssite(wp1.ohdokku.com).Youcansetacompletecustomdomainasthenamelike:[email protected]: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