Docker Deep Dive Zero to Docker in a single book 2020 Edition Nigel Poulton @nigelpoulton About this edition This edition was published in May 2020. In producing this edition, I've gone through every page and every example to make sure everything is up-to-date with the latest versions of Docker and the latest trends in the cloud-native ecosystem. Important updates include: -The Compose specification (announced April 2020). -Using TLS to secure client-daemon communications added to chapter 5. -Simplified Installing Docker chapter. Too much space was wasted on this topic in previous editions. Finally, I was able to reduce the cost of the paperback edition by shortening the book from ~400 pages to ~250 pages. I achieved this by reducing the font size to a more professional size that I already use in The Kubernetes Book (previous editions used a very large font). I also removed duplicate content and chapters that related to Docker Enterprise Edition which is no longer a strategic focus. The resulting book is shorter, sharper, and easier to navigate and consume! Enjoy the book! (cc))2020 Nigel Poulton All typos are mine. Or should that be typo's... ;-) Education is about inspiring and creating opportunities. I hope this book, and my video training courses, inspire you and create lots of opportunities! A huge thanks to my wife and daughters for putting up with me. It can't be easy living with a geek who wants to mess about with Docker and Kubernetes every hour of the day. I'm also grateful to my younger brother who manages the operational aspects of everything I do --- he also proof-read the manuscript, so we share the blame for any typos ;-). Thank you, as well, to everyone who watches my training videos at pluralsight.com, acloud.guru, and udemy.com. I love connecting with you and appreciate all the feedback you give --- keep it coming, it's what inspired me to write this book. Finally, I love to connect. You can reach me at nigelpoulton.com, Twitter, LinkedIn, YouTube, and many other places where I spend too much time talking about tech. @nigelpoulton About the author Nigel is a techoholic who spends his life creating books, training videos, and online hands-on training. He's the author of best-selling books on Docker and Kubernetes, as well as the most popular online training videos on the same topics (pluralsight.com. acloud.guru, and udemy.com). He's also a Docker Captain. Prior to all of this, Nigel held various senior infrastructure roles at large enterprises (mainly banks). When he's not playing with technology, he's dreaming about it. When he's not dreaming about it, he's reading and watching scifi. He wishes he lived in the future so he could explore space-time, the universe, and tons of other mind-blowing stuff. He likes cars, football, food, and bees (yes, that's the fuzzy insect and not a typo). He has a fabulous wife and three fabulous children. Feel free to connect via: • Twitter (@nigelpoulton) • LinkedIn (https://www.linkedin.com/in/nigelpoulton/) • nigelpoulton.com • YouTube: Nigel Poulton - KubeTrainer Contents 0:Aboutthebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 WhyshouldIreadthisbookorcareaboutDoer? . . . . . . . . . . . . . . . . . . . . . . . . . . 1 WhatifI’mnotadeveloper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 ShouldIbuythebookifI’vealreadywatedyourvideotrainingcourses? . . . . . . . . . . . . . . 1 Howthebookisorganized . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Editionsofthebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 HavingproblemsgeingthelatestupdatesonyourKindle? . . . . . . . . . . . . . . . . . . . . . 3 epaperbaedition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Leaveareview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Part 1: e big picture stuff . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1:Containersfrom30,000feet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 ebadolddays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 HelloVMware! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 VMwarts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 HelloContainers! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Linuxcontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 HelloDoer! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Windowscontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 WindowscontainersvsLinuxcontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 WhataboutMaccontainers? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 WhataboutKubernetes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2:Doer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Doer-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Doer,Inc. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 eDoertenology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 eOpenContainerInitiative(OCI) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3:InstallingDoer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 DoerDesktop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Windowspre-reqs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 CONTENTS InstallingDoerDesktoponWindows10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 InstallingDoerDesktoponMac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 InstallingDoeronLinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 InstallingDoeronWindowsServer2019 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 PlaywithDoer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 4:ebigpicture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 eOpsPerspective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Aaingtorunningcontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 eDevPerspective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Part 2: e tenical stuff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 5:eDoerEngine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 DoerEngine-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 DoerEngine-eDeepDive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 GeingridofLXC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 GeingridofthemonolithicDoerdaemon . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 einfluenceoftheOpenContainerInitiative(OCI) . . . . . . . . . . . . . . . . . . . . . . . 36 runc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 containerd. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Startinganewcontainer(example) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Onehugebenefitofthismodel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 What’sthisshimallabout? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Howit’simplementedonLinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 What’sthepointofthedaemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Securingclientanddaemoncommunication . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 6:Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Doerimages-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Doerimages-edeepdive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Imagesandcontainers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Imagesareusuallysmall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Pullingimages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Imagenaming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Imageregistries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Imagenamingandtagging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Imageswithmultipletags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Filteringtheoutputofdocker image ls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 SearingDoerHubfromtheCLI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Imagesandlayers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Sharingimagelayers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Pullingimagesbydigest. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Alilebitmoreaboutimagehashes(digests) . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Multi-aritectureimages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 DeletingImages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Images-ecommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 7:Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Doercontainers-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Doercontainers-edeepdive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 ContainersvsVMs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 eVMtax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Runningcontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 CheingthatDoerisrunning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Startingasimplecontainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Containerprocesses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Containerlifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Stoppingcontainersgracefully . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Self-healingcontainerswithrestartpolicies . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Webserverexample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Inspectingcontainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Tidyingup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 Containers-ecommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8:Containerizinganapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Containerizinganapp-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Containerizinganapp-edeepdive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Containerizeasingle-containerapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 MovingtoproductionwithMulti-stageBuilds . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Afewbestpractices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 Containerizinganapp-ecommands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 9:DeployingAppswithDoerCompose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 DeployingappswithCompose-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 DeployingappswithCompose-eDeepDive . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Composebaground . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 InstallingCompose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Composefiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 DeployinganappwithCompose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 ManaginganappwithCompose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 DeployingappswithCompose-ecommands . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 10:DoerSwarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 DoerSwarm-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 CONTENTS DoerSwarm-eDeepDive. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Swarmprimer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 BuildasecureSwarmcluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Swarmmanagerhighavailability(HA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 Swarmservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Viewingandinspectingservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Replicatedvsglobalservices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Scalingaservice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Removingaservice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Rollingupdates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 BaingupSwarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 DoerSwarm-eCommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Chaptersummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 11:DoerNetworking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 DoerNetworking-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 DoerNetworking-eDeepDive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 etheory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Single-hostbridgenetworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 Multi-hostoverlaynetworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Connectingtoexistingnetworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 Servicediscovery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Ingressloadbalancing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 DoerNetworking-eCommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 12:Doeroverlaynetworking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Doeroverlaynetworking-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Doeroverlaynetworking-edeepdive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 BuildandtestaDoeroverlaynetworkinSwarmmode . . . . . . . . . . . . . . . . . . . . . 176 Testtheoverlaynetwork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 etheoryofhowitallworks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Doeroverlaynetworking-ecommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 13:Volumesandpersistentdata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Volumesandpersistentdata-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Volumesandpersistentdata-eDeepDive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Containersandnon-persistentdata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Containersandpersistentdata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Demonstratingvolumeswithcontainersandservices . . . . . . . . . . . . . . . . . . . . . . . 193 Sharingstorageacrossclusternodes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 Volumesandpersistentdata-eCommands . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 14:DeployingappswithDoerStas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 DeployingappswithDoerStas-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 DeployingappswithDoerStas-eDeepDive . . . . . . . . . . . . . . . . . . . . . . . . . 199 Overviewofthesampleapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Lookingcloseratthestafile. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Deployingtheapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Managingtheapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 DeployingappswithDoerStas-eCommands . . . . . . . . . . . . . . . . . . . . . . . . . 216 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 15:SecurityinDoer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 SecurityinDoer-eTLDR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 SecurityinDoer-edeepdive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Linuxsecuritytenologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Doerplatformsecuritytenologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 DoerSecrets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 ChapterSummary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 16:Whatnext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Practicemakesperfect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Videotraining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Getinvolvedwiththecommunity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Kubernetes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Feedbaandconnecting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238