You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

557 lines
56 KiB

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  7. <meta name="apple-mobile-web-app-capable" content="yes">
  8. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  9. <meta name="mobile-web-app-capable" content="yes">
  10. <title>
  11. Lab 11: Docker - HackMD
  12. </title>
  13. <link rel="icon" type="image/png" href="https://hackmd.io/favicon.png">
  14. <link rel="apple-touch-icon" href="https://hackmd.io/apple-touch-icon.png">
  15. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
  16. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
  17. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
  18. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
  19. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
  20. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
  21. <style>
  22. @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);.hljs{background:#fff;color:#333;display:block;overflow-x:auto;padding:.5em}.hljs-comment,.hljs-meta{color:#969896}.hljs-emphasis,.hljs-quote,.hljs-string,.hljs-strong,.hljs-template-variable,.hljs-variable{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-attribute,.hljs-bullet,.hljs-literal,.hljs-number,.hljs-symbol{color:#0086b3}.hljs-built_in,.hljs-builtin-name{color:#005cc5}.hljs-name,.hljs-section{color:#63a35c}.hljs-tag{color:#333}.hljs-attr,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo,.hljs-title{color:#795da3}.hljs-addition{background-color:#eaffea;color:#55a532}.hljs-deletion{background-color:#ffecec;color:#bd2c00}.hljs-link{text-decoration:underline}.markdown-body{word-wrap:break-word;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd;padding:6px 13px}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{background-color:#f7f7f7;border-radius:3px;font-size:85%;line-height:1.45;overflow:auto;padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-body{max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body .emoji{vertical-align:top}.markdown-body pre{border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:3px solid #6ce26c!important;box-sizing:initial;color:#afafaf!important;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert>p:last-child{margin-bottom:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body .alert>p:last-child,.markdown-body .alert>ul:last-child{margin-bottom:0}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:#777;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:8px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}.ui-toc-label{background-color:#e6e6e6;border:none;color:#868686;transition:opacity .2s}.ui-toc .open .ui-toc-label{color:#fff;opacity:1;transition:opacity .2s}.ui-toc-label:focus{background-color:#ccc;color:#000;opacity:.3}.ui-toc-label:hover{background-color:#ccc;opacity:1;transition:opacity .2s}.ui-toc-dropdown{margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:#767676;display:block;font-size:13px;font-weight:500;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-left:1px solid #000;color:#000;padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-left:2px solid #000;color:#000;font-weight:700;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-left:none;border-right:2px solid #000;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-tw] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang=zh-cn] .markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang^=ja]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-tw]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html .markdown-body[lang=zh-cn]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol}html[lang^=ja] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html[lang=zh-tw] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html[lang=zh-cn] .ui-toc-dropdown{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}html .ui-toc-dropdown[lang^=ja]{font-family:Source Sans Pro,Helvetica,Arial,Meiryo UI,MS PGothic,MS Pゴシック,sans-serif}html .ui-toc-dropdown[lang=zh-tw]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft JhengHei UI,微軟正黑UI,sans-serif}html .ui-toc-dropdown[lang=zh-cn]{font-family:Source Sans Pro,Helvetica,Arial,Microsoft YaHei UI,微软雅黑UI,sans-serif}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:#999;display:block;font-size:12px;font-weight:500;margin-left:10px;margin-top:10px;padding:4px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{color:#888;cursor:pointer;vertical-align:middle}.ui-more-info .fa{font-size:16px}.ui-connectedGithub,.ui-published-note{color:#888}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{color:#888;padding-left:22px;text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{color:#888;text-decoration:underline}.ui-connectedGithub .fa{font-size:20px}.ui-published-note .fa{font-size:20px;vertical-align:top}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,MS ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
  23. </style>
  24. <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
  25. <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  26. <!--[if lt IE 9]>
  27. <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
  28. <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
  29. <script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
  30. <![endif]-->
  31. </head>
  32. <body>
  33. <div id="doc" class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true"><h1 id="Lab-11-Docker" data-id="Lab-11-Docker" style=""><a class="anchor hidden-xs" href="#Lab-11-Docker" title="Lab-11-Docker"><span class="octicon octicon-link"></span></a><span>Lab 11: Docker</span></h1><h2 id="Task-1-Install-Docker-on-Ubuntu" data-id="Task-1-Install-Docker-on-Ubuntu" style=""><a class="anchor hidden-xs" href="#Task-1-Install-Docker-on-Ubuntu" title="Task-1-Install-Docker-on-Ubuntu"><span class="octicon octicon-link"></span></a><span>Task 1: Install Docker on Ubuntu</span></h2><ul>
  34. <li><span>Update the list of packages:</span><pre><code>$ sudo apt update
  35. </code></pre>
  36. </li>
  37. <li><span>Install Docker:</span><pre><code>$ sudo apt install docker.io
  38. </code></pre>
  39. </li>
  40. <li><span>Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it’s running:</span><pre><code>$ sudo systemctl status docker
  41. </code></pre>
  42. </li>
  43. </ul><p><span>It is recommended that you do not run docker as the root user. If you currently cannot run </span><code>$ docker</code><span> with your non-root account, then take the following steps:</span></p><ul>
  44. <li><span>Add your username to the docker group:</span><pre><code>$ sudo usermod -aG docker ${USER}
  45. </code></pre>
  46. </li>
  47. <li><span>To apply the new group membership, log out of the server and back in, or type the following:</span><pre><code>$ su - ${USER}
  48. </code></pre>
  49. </li>
  50. <li><span>Confirm that your user is now added to the docker group by typing </span><code>$ groups</code><span>.</span><pre><code>$ groups
  51. user2 adm cdrom sudo dip plugdev lpadmin lxd sambashare docker
  52. </code></pre>
  53. </li>
  54. </ul><blockquote>
  55. <p><span>If you need to add a user to the docker group that you’re not logged in as, declare that username explicitly using:</span></p>
  56. <pre><code>$ sudo usermod -aG docker &lt;username&gt;
  57. </code></pre>
  58. </blockquote><h2 id="Task-2-Pull-images-and-run-containers" data-id="Task-2-Pull-images-and-run-containers" style=""><a class="anchor hidden-xs" href="#Task-2-Pull-images-and-run-containers" title="Task-2-Pull-images-and-run-containers"><span class="octicon octicon-link"></span></a><span>Task 2: Pull images and run containers</span></h2><ul>
  59. <li><span>Locate the application you want to run on Docker hub. Let’s run the Docker </span><code>hello-world</code><span> application </span><a href="https://hub.docker.com/_/hello-world" target="_blank" rel="noopener"><span>https://hub.docker.com/_/hello-world</span></a><span>.</span><pre><code>$ docker run hello-world
  60. </code></pre>
  61. <span>Docker will first search locally for the </span><code>hello-world</code><span> image. It will then download the image from Docker Hub if it is not found locally.</span><pre><code>Unable to find image 'hello-world:latest' locally
  62. latest: Pulling from library/hello-world
  63. 2db29710123e: Pull complete
  64. Digest: sha256:faa03e786c97f07ef34423fccceeec2398ec8a5759259f94d99078f264e9d7af
  65. Status: Downloaded newer image for hello-world:latest
  66. Hello from Docker!
  67. This message shows that your installation appears to be working correctly.
  68. ...
  69. </code></pre>
  70. <blockquote>
  71. <p><span>Docker Hub is the default repository for Docker installations.</span></p>
  72. </blockquote>
  73. </li>
  74. <li><span>You can search for images available on the Docker Hub by using the </span><code>search</code><span> option. Let’s search for “nginx”:</span><pre><code>$ docker search nginx
  75. </code></pre>
  76. <img src="https://i.imgur.com/5SL5esj.png" alt="" loading="lazy"></li>
  77. <li><span>Let’s download the </span><code>nginx</code><span> image to our machine without running it. Use the </span><code>pull</code><span> option:</span><pre><code>$ docker pull nginx
  78. </code></pre>
  79. </li>
  80. <li><span>To see all images downloaded to your machine run:</span><pre><code>$ docker images
  81. REPOSITORY TAG IMAGE ID CREATED SIZE
  82. nginx latest 76c69feac34e 2 weeks ago 142MB
  83. hello-world latest feb5d9fea6a5 13 months ago 13.3kB
  84. </code></pre>
  85. </li>
  86. <li><span>Unlike the </span><code>hello-world</code><span> container that ran once and exited, some containers run endlessly and their logs are written to the terminal. We can run these containers in the background or in detached mode with the </span><code>-d</code><span> flag. Let’s run </span><code>nginx</code><span> in the background</span><pre><code>$ docker run -d nginx
  87. </code></pre>
  88. </li>
  89. <li><span>Run </span><code>$ docker ps</code><span> to view active containers.</span><pre><code>$ docker ps
  90. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  91. f2e1f7608e47 nginx "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 80/tcp sweet_clarke
  92. </code></pre>
  93. <blockquote>
  94. <p><span>The </span><code>hello-world</code><span> application we ran earlier does not run continuously. It simply prints the message and exits.</span></p>
  95. </blockquote>
  96. </li>
  97. <li><span>To view all containers (active and inactive), run </span><code>$ docker ps -a</code><pre><code>$ docker ps -a
  98. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  99. f2e1f7608e47 nginx "/docker-entrypoint.…" 33 seconds ago Up 32 seconds 80/tcp sweet_clarke
  100. 6e4d35a225ec hello-world "/hello" About a minute ago Exited (0) About a minute ago gallant_edison
  101. </code></pre>
  102. <blockquote>
  103. <p><span>You can interact with a container by using the container ID or the unique container name. For example, the container ID and container name of the container created from the </span><code>nginx</code><span> image is </span><code>f2e1f7608e47</code><span> and </span><code>sweet_clarke</code><span> respectively.</span></p>
  104. </blockquote>
  105. </li>
  106. <li><span>To enter the shell of a running container and execute commands, run </span><code>$ docker exec -it &lt;container-name&gt; bash</code><span>:</span><pre><code>$ docker exec -it sweet_clarke bash
  107. root@f2e1f7608e47:/#
  108. </code></pre>
  109. </li>
  110. <li><span>While in the container, view nginx default index file:</span><pre><code>root@f2e1f7608e47:/# cat /usr/share/nginx/html/index.html
  111. &lt;!DOCTYPE html&gt;
  112. &lt;html&gt;
  113. &lt;head&gt;
  114. &lt;title&gt;Welcome to nginx!&lt;/title&gt;
  115. &lt;style&gt;
  116. html { color-scheme: light dark; }
  117. body { width: 35em; margin: 0 auto;
  118. font-family: Tahoma, Verdana, Arial, sans-serif; }
  119. &lt;/style&gt;
  120. &lt;/head&gt;
  121. &lt;body&gt;
  122. &lt;h1&gt;Welcome to nginx!&lt;/h1&gt;
  123. &lt;p&gt;If you see this page, the nginx web server is successfully installed and
  124. working. Further configuration is required.&lt;/p&gt;
  125. &lt;p&gt;For online documentation and support please refer to
  126. &lt;a href="http://nginx.org/"&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;
  127. Commercial support is available at
  128. &lt;a href="http://nginx.com/"&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;
  129. &lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;
  130. &lt;/body&gt;
  131. &lt;/html&gt;
  132. </code></pre>
  133. <span>Navigate the shell to see its capabilities. Administrators can make changes to the Docker applications they deploy by entering the container shell.</span></li>
  134. <li><span>When done exploring the container shell, run </span><code>$ exit</code><span> to close the shell and return to your host machine.</span></li>
  135. <li><span>To stop a container, run </span><code>$ docker stop &lt;cotainer-name&gt;</code><span>. Let’s stop the </span><code>sweet_clarke</code><span> container:</span><pre><code>$ docker stop sweet_clarke
  136. </code></pre>
  137. </li>
  138. <li><span>View a list of all containers again. The status should show that it exited.</span><pre><code>$ docker ps -a
  139. </code></pre>
  140. </li>
  141. <li><span>You can restart a stopped container by running: </span><code>$ docker start &lt;cotainer-name&gt;</code><span>.</span>
  142. <blockquote>
  143. <p><strong><span>Note</span></strong><span> that </span><code>$ docker run &lt;image-name&gt;</code><span> creates a new container, therefore it’s not necessary to use </span><code>docker run</code><span> when the container is already created from the image, unless your intention is to create multiple containers.</span></p>
  144. </blockquote>
  145. </li>
  146. <li><span>You can remove a container with </span><code>$ docker rm &lt;container-name&gt;</code><span>.</span><pre><code>$ docker rm sweet_clarke
  147. $ docker rm 6e4d35a225ec # container ID for hello-world
  148. </code></pre>
  149. </li>
  150. <li><span>Let’s also remove the </span><code>hello-world</code><span> and the </span><code>nginx</code><span> images from our local machine.</span><br>
  151. <span>First, view available images:</span><pre><code>$ docker images -a
  152. REPOSITORY TAG IMAGE ID CREATED SIZE
  153. hello-world latest feb5d9fea6a5 13 months ago 13.3kB
  154. nginx latest f2e1f7608e47 2 years ago 100.2MB
  155. </code></pre>
  156. <span>Use the </span><code>rmi</code><span> option to remove the images:</span><pre><code>$ docker rmi hello-world nginx
  157. Untagged: hello-world:latest
  158. Untagged: hello-world@sha256:faa03e786c97f07ef34423fccceeec2398ec8a5759259f94d99078f264e9d7af
  159. Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
  160. Deleted: sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359
  161. Untagged: nginx:latest
  162. Untagged: nginx@sha256:943c25b4b66b332184d5ba6bb18234273551593016c0e0ae906bab111548239f
  163. Deleted: sha256:76c69feac34e85768b284f84416c3546b240e8cb4f68acbbe5ad261a8b36f39f
  164. Deleted: sha256:8b811a30cb94c227fb2ae61a2a1ec1e93381dbef06f9ea6b5c06df4f27651fed
  165. Deleted: sha256:470cc6f5d954afeb2695504eff0eda9f8da0e1b3b8bde30e74d9c48dbcb99906
  166. Deleted: sha256:1c277c746c47ba650267f58cc6e1ea430ce726065c79691ce04235d90209caff
  167. Deleted: sha256:953e18d40076df9e65564241b34cfba85ab1a6c0634c67e92d6a1f633c5b97d9
  168. Deleted: sha256:f0a780360f49b2b6afc28882ed2399799e6615862e7dc64451fb3688a33fe712
  169. Deleted: sha256:a12586ed027fafddcddcc63b31671f406c25e43342479fc92a330e7e30d65f2e
  170. </code></pre>
  171. </li>
  172. </ul><h2 id="Task-3-Create-a-custom-Docker-image" data-id="Task-3-Create-a-custom-Docker-image" style=""><a class="anchor hidden-xs" href="#Task-3-Create-a-custom-Docker-image" title="Task-3-Create-a-custom-Docker-image"><span class="octicon octicon-link"></span></a><span>Task 3: Create a custom Docker image</span></h2><p><span>Let’s create a static page website and run it on a Python web server.</span></p><blockquote>
  173. <p><strong><span>Note:</span></strong><span> There are more effective ways to set up a web server. We use the methods in this lab simply to explore the process of creating a Docker image.</span></p>
  174. </blockquote><ul>
  175. <li><span>Create a directory for the Docker application and navigate to it:</span><pre><code>$ mkdir ~/pythonweb &amp;&amp; cd ~/pythonweb
  176. </code></pre>
  177. </li>
  178. <li><span>Create a </span><code>Dockerfile</code><span> in the directory:</span><pre><code>$ touch Dockerfile
  179. </code></pre>
  180. </li>
  181. <li><span>Add the following lines to </span><code>Dockerfile</code><span>:</span>
  182. <ol>
  183. <li><span>To pull the docker image for Ubuntu 22.04:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">FROM ubuntu:jammy
  184. </div></div></code></pre>
  185. </li>
  186. <li><span>To update the sources list and install python3:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">RUN apt-get update &amp;&amp; apt-get install -y python3 --no-install-recommends
  187. </div></div></code></pre>
  188. </li>
  189. </ol>
  190. <blockquote>
  191. <p><span>The python web server listens on port </span><code>8000</code><span> by default. Network access to container services is disabled by default.</span></p>
  192. </blockquote>
  193. <ol start="4">
  194. <li><span>To expose port </span><code>8000</code><span> to devices outside the container</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">EXPOSE 8000
  195. </div></div></code></pre>
  196. </li>
  197. <li><span>To start the python web server when the contaner is executed:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">ENTRYPOINT ["python3", "-m", "http.server"]
  198. </div></div></code></pre>
  199. </li>
  200. </ol>
  201. <span>The </span><code>Dockerfile</code><span> should look like this:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  202. <span></span>
  203. <span></span>
  204. <span></span></div><div class="code">FROM ubuntu:jammy
  205. RUN apt-get update &amp;&amp; apt-get install -y python3 --no-install-recommends
  206. EXPOSE 8000
  207. ENTRYPOINT ["python3", "-m", "http.server"]
  208. </div></div></code></pre>
  209. <blockquote>
  210. <p><code>RUN</code><span> is used to specify commands that should be run when building the image.</span><br>
  211. <code>ENTRYPOINT</code><span> and </span><code>CMD</code><span> define commands the container executes when it launches.</span></p>
  212. </blockquote>
  213. </li>
  214. <li><span>Build the image:</span><pre><code>docker build -t pythonweb:latest .
  215. </code></pre>
  216. <blockquote>
  217. <p><span>The </span><code>.</code><span> at the end represents the location of the </span><code>Dockerfile</code><span>. In this case it is in the CWD. Otherwise, we would have specified the directory where the </span><code>Dockerfile</code><span> is located.</span></p>
  218. </blockquote>
  219. </li>
  220. <li><span>Check your docker images and you should see something similar to the following:</span><pre><code>$ docker images
  221. REPOSITORY TAG IMAGE ID CREATED SIZE
  222. pythonweb latest 60e7915677a4 About a minute ago 147MB
  223. ubuntu jammy a8780b506fa4 10 days ago 77.8MB
  224. </code></pre>
  225. </li>
  226. <li><span>Run the image </span><code>pythonweb</code><span> and map port 80 on the host machine to port 8000 on the container. This will allow users interact with the web server in the container via the host machine.</span><pre><code>$ docker run -p 80:8000 -d pythonweb
  227. </code></pre>
  228. </li>
  229. <li><span>View the contents of the web server in your browser:</span><br>
  230. <img src="https://i.imgur.com/O10RFHK.png" alt="" loading="lazy"><br>
  231. <span>The Python web server works, but there is no index page, and it shows system files. Let’s proceed to create an index web page, add a working directory, and update the image with the new configuration.</span></li>
  232. <li><span>Create a directory to contain the web files.</span><pre><code>$ mkdir ~/pythonweb/webfiles/
  233. </code></pre>
  234. </li>
  235. <li><span>Create </span><code>index.html</code><span> in </span><code>~/pythonweb/webfiles/index.html</code><span>:</span><pre><code>$ vi ~/pythonweb/webfiles/index.html
  236. </code></pre>
  237. <span>Add the following lines to the file:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  238. <span></span>
  239. <span></span>
  240. <span></span></div><div class="code">&lt;html&gt;
  241. &lt;h1&gt;SNA Lab&lt;/h1&gt;
  242. &lt;p&gt;SNA rocks :)&lt;/p&gt;
  243. &lt;/html&gt;
  244. </div></div></code></pre>
  245. </li>
  246. <li><span>Modify the </span><code>Dockerfile</code><span> and add the following lines:</span>
  247. <ol>
  248. <li><span>To copy the contents of </span><code>webfiles</code><span> directory to the image:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">COPY webfiles/ /usr/share/webfiles
  249. </div></div></code></pre>
  250. </li>
  251. <li><span>To change the container working directory to the </span><code>/usr/share/webfiles</code><span> directory</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code">WORKDIR /usr/share/webfiles
  252. </div></div></code></pre>
  253. </li>
  254. </ol>
  255. <span>The final </span><code>Dockerfile</code><span> after the modification is shown below:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  256. <span></span>
  257. <span></span>
  258. <span></span>
  259. <span></span>
  260. <span></span></div><div class="code">FROM ubuntu:jammy
  261. RUN apt-get update &amp;&amp; apt-get install -y python3 --no-install-recommends
  262. COPY webfiles/ /usr/share/webfiles
  263. WORKDIR /usr/share/webfiles
  264. EXPOSE 8000
  265. ENTRYPOINT ["python3", "-m", "http.server"]
  266. </div></div></code></pre>
  267. </li>
  268. <li><span>Check running containers, stop the container running </span><code>pythonweb</code><span>, and remove the container:</span><pre><code>$ docker ps -a
  269. $ docker stop &lt;container-name&gt;
  270. $ docker rm &lt;container-name&gt;
  271. </code></pre>
  272. </li>
  273. <li><span>Remove the </span><code>pythonweb</code><span> image.</span><pre><code>$ docker rmi pythonweb
  274. </code></pre>
  275. </li>
  276. <li><span>Build the image</span><pre><code>docker build -t pythonweb:latest .
  277. </code></pre>
  278. </li>
  279. <li><span>Run the updated </span><code>pythonweb</code><span> image. This time, let’s specify a container name with the </span><code>--name</code><span> flag. This is better than relying on the random names generated by Docker:</span><pre><code>$ docker run -p 80:8000 -d --name snaweb-container pythonweb
  280. </code></pre>
  281. <span>Run </span><code>docker ps</code><span> to view the running container:</span><pre><code>$ docker ps
  282. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  283. ecfb00c4039f pythonweb "python3 -m http.ser…" 6 seconds ago Up 5 seconds 0.0.0.0:80-&gt;8000/tcp, :::80-&gt;8000/tcp snaweb-container
  284. </code></pre>
  285. </li>
  286. <li><span>Visit the page again and you should have results similar to the following:</span><br>
  287. <img src="https://i.imgur.com/jRd5Wq8.png" alt="" loading="lazy"></li>
  288. </ul><h2 id="Task-4-Docker-inspect-and-container-logs" data-id="Task-4-Docker-inspect-and-container-logs" style=""><a class="anchor hidden-xs" href="#Task-4-Docker-inspect-and-container-logs" title="Task-4-Docker-inspect-and-container-logs"><span class="octicon octicon-link"></span></a><span>Task 4: Docker </span><code>inspect</code><span> and container logs</span></h2><p><span>Docker </span><code>inspect</code><span> is used to view low-level information on Docker objects.</span></p><ul>
  289. <li><span>Inspect the </span><code>snaweb-container</code><span> container:</span><pre><code>$ docker inspect snaweb-container
  290. </code></pre>
  291. <span>The result is JSON data that contains some useful information if analyzed properly.</span><br>
  292. <span>You can filter the results from </span><code>inspect</code><span> without manually reading everything in the large volume of output it generates.</span></li>
  293. <li><span>Get the full container ID for </span><code>snaweb-container</code><span>:</span><pre><code>docker container inspect -f '{{.Id}}' snaweb-container
  294. </code></pre>
  295. </li>
  296. <li><span>View the containers main process:</span><pre><code>$ docker container inspect -f '{{printf "%s " .Path}}{{range .Args}}{{printf "%s " .}}{{end}}' snaweb-container
  297. </code></pre>
  298. </li>
  299. <li><span>List all port bindings:</span><pre><code>$ docker container inspect -f '{{range $target, $published := .NetworkSettings.Ports}}{{range $published}}{{printf "%s -&gt; %s:%s\n" $target .HostIp .HostPort}}{{end}}{{end}}' snaweb-container
  300. </code></pre>
  301. </li>
  302. <li><span>View the network your container is connected to:</span><pre><code>$ docker inspect -f "{{json .NetworkSettings.Networks }}" snaweb-container
  303. </code></pre>
  304. <span>The sample output shows that my container is connected to the </span><code>bridge</code><span> network:</span><pre><code>{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"ece6245e2975ad3a709dbf7d993a59454c703f09c68b892fd3922581ed967a8e","EndpointID":"40fd7af8985dba6f7f654bffef4df2de363db00b360f630ee19d2d78704df5a1","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02","DriverOpts":null}}
  305. </code></pre>
  306. </li>
  307. <li><span>List the containers connected to a network along with their IP addresses:</span>
  308. <blockquote>
  309. <p><span>Replace </span><code>bridge</code><span> in the command with your network name.</span></p>
  310. </blockquote>
  311. <pre><code>$ docker network inspect -f '{{range .Containers}}{{printf "%s -&gt; %s\n" .Name .IPv4Address}}{{end}}' bridge
  312. </code></pre>
  313. </li>
  314. </ul><p><span>Container logging helps developers keep track of patterns, troubleshoot issues, and fix bugs.</span></p><ul>
  315. <li><span>View the container logs with </span><code>$ docker logs &lt;container-name&gt;</code><span>:</span><pre><code>$ docker logs snaweb-container
  316. </code></pre>
  317. </li>
  318. <li><span>Container logs are stored in the </span><code>/var/lib/docker/containers/ID/ID-json.log</code><span>.</span></li>
  319. <li><span>Use </span><code>inspect</code><span> to find the full log path for </span><code>snaweb-container</code><span>:</span><pre><code>$ docker container inspect -f '{{.LogPath}}' snaweb-container
  320. </code></pre>
  321. <span>View the log file with tail:</span><pre><code>$ sudo tail /var/lib/docker/containers/ecfb00c4039fddb81a5185fd2287a908cefd140e8f1d832ab65a71759aac39ce/ecfb00c4039fddb81a5185fd2287a908cefd140e8f1d832ab65a71759aac39ce-json.log
  322. {"log":"172.17.0.1 - - [13/Nov/2022 16:34:00] \"GET / HTTP/1.1\" 200 -\n","stream":"stderr","time":"2022-11-13T16:34:00.810777628Z"}
  323. {"log":"172.17.0.1 - - [13/Nov/2022 16:48:49] \"GET / HTTP/1.1\" 304 -\n","stream":"stderr","time":"2022-11-13T16:48:49.9306387Z"}
  324. {"log":"192.168.132.1 - - [13/Nov/2022 16:49:11] \"GET / HTTP/1.1\" 200 -\n","stream":"stderr","time":"2022-11-13T16:49:11.494390274Z"}
  325. {"log":"192.168.132.1 - - [13/Nov/2022 16:49:11] code 404, message File not found\n","stream":"stderr","time":"2022-11-13T16:49:11.584257708Z"}
  326. {"log":"192.168.132.1 - - [13/Nov/2022 16:49:11] \"GET /favicon.ico HTTP/1.1\" 404 -\n","stream":"stderr","time":"2022-11-13T16:49:11.584310308Z"}
  327. </code></pre>
  328. </li>
  329. </ul><h2 id="Questions-to-answer" data-id="Questions-to-answer" style=""><a class="anchor hidden-xs" href="#Questions-to-answer" title="Questions-to-answer"><span class="octicon octicon-link"></span></a><span>Questions to answer</span></h2><ol>
  330. <li><span>Compare and contrast </span><code>ENTRYPOINT</code><span> and </span><code>CMD</code><span> in Dockerfile. In what situation would you use each of them?</span></li>
  331. <li><span>List five security precautions you will take when building or deploying a Docker resource (image or container).</span></li>
  332. <li><span>Show a single line command that will remove all exited Docker containers. Do not use any text filtering editor. Show test results.</span></li>
  333. <li><span>Show how you can copy files to a running container without entering the container’s interactive shell.</span></li>
  334. <li><span>Create a dockerized web application running on nginx. The web index page </span><code>index.html</code><span> should be located on your host machine. The directory containing the index page should be mounted to the container and served from there.</span>
  335. <blockquote>
  336. <p><span>This means that you should be able to modify the web index page on your host machine without interacting with the container.</span><br>
  337. <span>Show all steps taken for the configuration including the test results.</span></p>
  338. </blockquote>
  339. </li>
  340. <li><span>Setup rsyslog on your host machine as a central logging server. Create a Docker container and configure it to forward its log to your central logging server.</span>
  341. <blockquote>
  342. <p><span>Show steps and test results.</span></p>
  343. </blockquote>
  344. </li>
  345. </ol><h3 id="Bonus" data-id="Bonus" style=""><a class="anchor hidden-xs" href="#Bonus" title="Bonus"><span class="octicon octicon-link"></span></a><span>Bonus</span></h3><ol start="7">
  346. <li><span>Dockerize any open source application of your choice, and host it on Docker hub. Share link to the repository.</span></li>
  347. <li><span>Find and fix the problems in the following Dockerfile. There are some issues building the image and also running the container:</span><pre><code class="hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
  348. <span></span>
  349. <span></span>
  350. <span></span>
  351. <span></span></div><div class="code">FROM alpine
  352. RUN apt-get update &amp;&amp; apt-get install -y python3 --no-install-recommends
  353. RUN touch index.html
  354. RUN echo "&lt;html&gt;&lt;h1&gt;Testing web&lt;/h1&gt;&lt;/html&gt;" &gt;&gt; index.html
  355. CMD ["python", "-m", "http.server"]
  356. </div></div></code></pre>
  357. <blockquote>
  358. <p><span>Show all steps taken to fix it, and a working solution.</span></p>
  359. </blockquote>
  360. </li>
  361. </ol></div>
  362. <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
  363. <div class="pull-right dropdown">
  364. <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
  365. <i class="fa fa-bars"></i>
  366. </a>
  367. <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
  368. <div class="toc"><ul class="nav">
  369. <li class=""><a href="#Lab-11-Docker" title="Lab 11: Docker">Lab 11: Docker</a><ul class="nav">
  370. <li class=""><a href="#Task-1-Install-Docker-on-Ubuntu" title="Task 1: Install Docker on Ubuntu">Task 1: Install Docker on Ubuntu</a></li>
  371. <li class=""><a href="#Task-2-Pull-images-and-run-containers" title="Task 2: Pull images and run containers">Task 2: Pull images and run containers</a></li>
  372. <li><a href="#Task-3-Create-a-custom-Docker-image" title="Task 3: Create a custom Docker image">Task 3: Create a custom Docker image</a></li>
  373. <li><a href="#Task-4-Docker-inspect-and-container-logs" title="Task 4: Docker inspect and container logs">Task 4: Docker inspect and container logs</a></li>
  374. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  375. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  376. </ul>
  377. </li>
  378. </ul>
  379. </li>
  380. </ul>
  381. </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
  382. </ul>
  383. </div>
  384. </div>
  385. <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" null null>
  386. <div class="toc"><ul class="nav">
  387. <li class=""><a href="#Lab-11-Docker" title="Lab 11: Docker">Lab 11: Docker</a><ul class="nav">
  388. <li class=""><a href="#Task-1-Install-Docker-on-Ubuntu" title="Task 1: Install Docker on Ubuntu">Task 1: Install Docker on Ubuntu</a></li>
  389. <li class=""><a href="#Task-2-Pull-images-and-run-containers" title="Task 2: Pull images and run containers">Task 2: Pull images and run containers</a></li>
  390. <li><a href="#Task-3-Create-a-custom-Docker-image" title="Task 3: Create a custom Docker image">Task 3: Create a custom Docker image</a></li>
  391. <li><a href="#Task-4-Docker-inspect-and-container-logs" title="Task 4: Docker inspect and container logs">Task 4: Docker inspect and container logs</a></li>
  392. <li><a href="#Questions-to-answer" title="Questions to answer">Questions to answer</a><ul class="nav">
  393. <li><a href="#Bonus" title="Bonus">Bonus</a></li>
  394. </ul>
  395. </li>
  396. </ul>
  397. </li>
  398. </ul>
  399. </div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
  400. </div>
  401. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  402. <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
  403. <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
  404. <script>
  405. var markdown = $(".markdown-body");
  406. //smooth all hash trigger scrolling
  407. function smoothHashScroll() {
  408. var hashElements = $("a[href^='#']").toArray();
  409. for (var i = 0; i < hashElements.length; i++) {
  410. var element = hashElements[i];
  411. var $element = $(element);
  412. var hash = element.hash;
  413. if (hash) {
  414. $element.on('click', function (e) {
  415. // store hash
  416. var hash = this.hash;
  417. if ($(hash).length <= 0) return;
  418. // prevent default anchor click behavior
  419. e.preventDefault();
  420. // animate
  421. $('body, html').stop(true, true).animate({
  422. scrollTop: $(hash).offset().top
  423. }, 100, "linear", function () {
  424. // when done, add hash to url
  425. // (default click behaviour)
  426. window.location.hash = hash;
  427. });
  428. });
  429. }
  430. }
  431. }
  432. smoothHashScroll();
  433. var toc = $('.ui-toc');
  434. var tocAffix = $('.ui-affix-toc');
  435. var tocDropdown = $('.ui-toc-dropdown');
  436. //toc
  437. tocDropdown.click(function (e) {
  438. e.stopPropagation();
  439. });
  440. var enoughForAffixToc = true;
  441. function generateScrollspy() {
  442. $(document.body).scrollspy({
  443. target: ''
  444. });
  445. $(document.body).scrollspy('refresh');
  446. if (enoughForAffixToc) {
  447. toc.hide();
  448. tocAffix.show();
  449. } else {
  450. tocAffix.hide();
  451. toc.show();
  452. }
  453. $(document.body).scroll();
  454. }
  455. function windowResize() {
  456. //toc right
  457. var paddingRight = parseFloat(markdown.css('padding-right'));
  458. var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
  459. toc.css('right', right + 'px');
  460. //affix toc left
  461. var newbool;
  462. var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
  463. //for ipad or wider device
  464. if (rightMargin >= 133) {
  465. newbool = true;
  466. var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
  467. var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
  468. tocAffix.css('left', left + 'px');
  469. } else {
  470. newbool = false;
  471. }
  472. if (newbool != enoughForAffixToc) {
  473. enoughForAffixToc = newbool;
  474. generateScrollspy();
  475. }
  476. }
  477. $(window).resize(function () {
  478. windowResize();
  479. });
  480. $(document).ready(function () {
  481. windowResize();
  482. generateScrollspy();
  483. });
  484. //remove hash
  485. function removeHash() {
  486. window.location.hash = '';
  487. }
  488. var backtotop = $('.back-to-top');
  489. var gotobottom = $('.go-to-bottom');
  490. backtotop.click(function (e) {
  491. e.preventDefault();
  492. e.stopPropagation();
  493. if (scrollToTop)
  494. scrollToTop();
  495. removeHash();
  496. });
  497. gotobottom.click(function (e) {
  498. e.preventDefault();
  499. e.stopPropagation();
  500. if (scrollToBottom)
  501. scrollToBottom();
  502. removeHash();
  503. });
  504. var toggle = $('.expand-toggle');
  505. var tocExpand = false;
  506. checkExpandToggle();
  507. toggle.click(function (e) {
  508. e.preventDefault();
  509. e.stopPropagation();
  510. tocExpand = !tocExpand;
  511. checkExpandToggle();
  512. })
  513. function checkExpandToggle () {
  514. var toc = $('.ui-toc-dropdown .toc');
  515. var toggle = $('.expand-toggle');
  516. if (!tocExpand) {
  517. toc.removeClass('expand');
  518. toggle.text('Expand all');
  519. } else {
  520. toc.addClass('expand');
  521. toggle.text('Collapse all');
  522. }
  523. }
  524. function scrollToTop() {
  525. $('body, html').stop(true, true).animate({
  526. scrollTop: 0
  527. }, 100, "linear");
  528. }
  529. function scrollToBottom() {
  530. $('body, html').stop(true, true).animate({
  531. scrollTop: $(document.body)[0].scrollHeight
  532. }, 100, "linear");
  533. }
  534. </script>
  535. </body>
  536. </html>