commit e3e645a29a1b83e1871ebb1371c142edef4e5003 Author: Travis CI User Date: Thu May 13 17:44:54 2021 +0800 deploy diff --git a/404.html b/404.html new file mode 100644 index 0000000..858cf45 --- /dev/null +++ b/404.html @@ -0,0 +1,20 @@ + + + + + + LINUX-TUTORIAL + + + + + + + + +

404

There's nothing here.
+ Take me home. +
+ + + diff --git a/assets/css/0.styles.45d9d031.css b/assets/css/0.styles.45d9d031.css new file mode 100644 index 0000000..f0c037a --- /dev/null +++ b/assets/css/0.styles.45d9d031.css @@ -0,0 +1 @@ +.medium-zoom-overlay{z-index:100}.medium-zoom-overlay~img{z-index:101}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number,div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}html{scroll-behavior:smooth}.go-to-top[data-v-5fd4ef0c]{cursor:pointer;position:fixed;bottom:2rem;right:2.5rem;width:2rem;color:#3eaf7c;z-index:1}.go-to-top[data-v-5fd4ef0c]:hover{color:#72cda4}@media (max-width:959px){.go-to-top[data-v-5fd4ef0c]{display:none}}.fade-enter-active[data-v-5fd4ef0c],.fade-leave-active[data-v-5fd4ef0c]{transition:opacity .3s}.fade-enter[data-v-5fd4ef0c],.fade-leave-to[data-v-5fd4ef0c]{opacity:0}.vuepress-flowchart{overflow:scroll;text-align:center;font-size:0;min-height:200px;display:flex;justify-content:center;align-items:center;transition:all 1s;padding:10px}.vuepress-flowchart>svg{max-width:100%;height:auto}.vuepress-flowchart.loading{background-color:#f3f6f8}.operation-element,.parallel-element{rx:5px;ry:5px}.vuepress-flowchart-loading-icon{width:40px;height:40px;fill:#3eaf7c}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/linux-tutorial/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983}.sw-update-popup[data-v-fec8b358]{position:fixed;right:1em;bottom:1em;padding:1em;border:1px solid #3eaf7c;border-radius:3px;background:#fff;box-shadow:0 4px 16px rgba(0,0,0,.5);text-align:center;z-index:3}.sw-update-popup>button[data-v-fec8b358]{margin-top:.5em;padding:.25em 2em}.sw-update-popup-enter-active[data-v-fec8b358],.sw-update-popup-leave-active[data-v-fec8b358]{transition:opacity .3s,transform .3s}.sw-update-popup-enter[data-v-fec8b358],.sw-update-popup-leave-to[data-v-fec8b358]{opacity:0;transform:translateY(50%) scale(.5)} \ No newline at end of file diff --git a/assets/img/search.83621669.svg b/assets/img/search.83621669.svg new file mode 100644 index 0000000..03d8391 --- /dev/null +++ b/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/assets/js/10.7933187b.js b/assets/js/10.7933187b.js new file mode 100644 index 0000000..ce23d11 --- /dev/null +++ b/assets/js/10.7933187b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{398:function(t,e,r){"use strict";r.r(e);var o=r(15),n=Object(o.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("p",[r("img",{attrs:{src:"https://badgen.net/github/license/dunwu/linux-tutorial",alt:"license"}}),t._v(" "),r("img",{attrs:{src:"https://travis-ci.com/dunwu/linux-tutorial.svg?branch=master",alt:"build"}})]),t._v(" "),r("blockquote",[r("p",[t._v("📚 "),r("strong",[t._v("linux-tutorial")]),t._v(" 是一个 Linux 教程。")]),t._v(" "),r("p",[t._v("🔁 项目同步维护在 "),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("github"),r("OutboundLink")],1),t._v(" | "),r("a",{attrs:{href:"https://gitee.com/turnon/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("gitee"),r("OutboundLink")],1)]),t._v(" "),r("p",[t._v("📖 "),r("a",{attrs:{href:"https://dunwu.github.io/linux-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("电子书"),r("OutboundLink")],1),t._v(" | "),r("a",{attrs:{href:"http://turnon.gitee.io/linux-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("电子书(国内)"),r("OutboundLink")],1)])]),t._v(" "),r("h2",{attrs:{id:"📖-内容"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#📖-内容"}},[t._v("#")]),t._v(" 📖 内容")]),t._v(" "),r("h3",{attrs:{id:"linux-命令"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#linux-命令"}},[t._v("#")]),t._v(" Linux 命令")]),t._v(" "),r("blockquote",[r("p",[t._v("学习 Linux 的第一步:当然是从 "),r("RouterLink",{attrs:{to:"/linux/cli/"}},[t._v("Linux 命令")]),t._v(" 入手了。")],1)]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-help.html"}},[t._v("查看 Linux 命令帮助信息")]),t._v(" - 关键词:"),r("code",[t._v("help")]),t._v(", "),r("code",[t._v("whatis")]),t._v(", "),r("code",[t._v("info")]),t._v(", "),r("code",[t._v("which")]),t._v(", "),r("code",[t._v("whereis")]),t._v(", "),r("code",[t._v("man")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-dir.html"}},[t._v("Linux 文件目录管理")]),t._v(" - 关键词:"),r("code",[t._v("cd")]),t._v(", "),r("code",[t._v("ls")]),t._v(", "),r("code",[t._v("pwd")]),t._v(", "),r("code",[t._v("mkdir")]),t._v(", "),r("code",[t._v("rmdir")]),t._v(", "),r("code",[t._v("tree")]),t._v(", "),r("code",[t._v("touch")]),t._v(", "),r("code",[t._v("ln")]),t._v(", "),r("code",[t._v("rename")]),t._v(", "),r("code",[t._v("stat")]),t._v(", "),r("code",[t._v("file")]),t._v(", "),r("code",[t._v("chmod")]),t._v(", "),r("code",[t._v("chown")]),t._v(", "),r("code",[t._v("locate")]),t._v(", "),r("code",[t._v("find")]),t._v(", "),r("code",[t._v("cp")]),t._v(", "),r("code",[t._v("mv")]),t._v(", "),r("code",[t._v("rm")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-file.html"}},[t._v("Linux 文件内容查看命令")]),t._v(" - 关键词:"),r("code",[t._v("cat")]),t._v(", "),r("code",[t._v("head")]),t._v(", "),r("code",[t._v("tail")]),t._v(", "),r("code",[t._v("more")]),t._v(", "),r("code",[t._v("less")]),t._v(", "),r("code",[t._v("sed")]),t._v(", "),r("code",[t._v("vi")]),t._v(", "),r("code",[t._v("grep")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-file-compress.html"}},[t._v("Linux 文件压缩和解压")]),t._v(" - 关键词:"),r("code",[t._v("tar")]),t._v(", "),r("code",[t._v("gzip")]),t._v(", "),r("code",[t._v("zip")]),t._v(", "),r("code",[t._v("unzip")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-user.html"}},[t._v("Linux 用户管理")]),t._v(" - 关键词:"),r("code",[t._v("groupadd")]),t._v(", "),r("code",[t._v("groupdel")]),t._v(", "),r("code",[t._v("groupmod")]),t._v(", "),r("code",[t._v("useradd")]),t._v(", "),r("code",[t._v("userdel")]),t._v(", "),r("code",[t._v("usermod")]),t._v(", "),r("code",[t._v("passwd")]),t._v(", "),r("code",[t._v("su")]),t._v(", "),r("code",[t._v("sudo")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-system.html"}},[t._v("Linux 系统管理")]),t._v(" - 关键词:"),r("code",[t._v("reboot")]),t._v(", "),r("code",[t._v("exit")]),t._v(", "),r("code",[t._v("shutdown")]),t._v(", "),r("code",[t._v("date")]),t._v(", "),r("code",[t._v("mount")]),t._v(", "),r("code",[t._v("umount")]),t._v(", "),r("code",[t._v("ps")]),t._v(", "),r("code",[t._v("kill")]),t._v(", "),r("code",[t._v("systemctl")]),t._v(", "),r("code",[t._v("service")]),t._v(", "),r("code",[t._v("crontab")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-net.html"}},[t._v("Linux 网络管理")]),t._v(" - 关键词:关键词:"),r("code",[t._v("curl")]),t._v(", "),r("code",[t._v("wget")]),t._v(", "),r("code",[t._v("telnet")]),t._v(", "),r("code",[t._v("ip")]),t._v(", "),r("code",[t._v("hostname")]),t._v(", "),r("code",[t._v("ifconfig")]),t._v(", "),r("code",[t._v("route")]),t._v(", "),r("code",[t._v("ssh")]),t._v(", "),r("code",[t._v("ssh-keygen")]),t._v(", "),r("code",[t._v("firewalld")]),t._v(", "),r("code",[t._v("iptables")]),t._v(", "),r("code",[t._v("host")]),t._v(", "),r("code",[t._v("nslookup")]),t._v(", "),r("code",[t._v("nc")]),t._v("/"),r("code",[t._v("netcat")]),t._v(", "),r("code",[t._v("ping")]),t._v(", "),r("code",[t._v("traceroute")]),t._v(", "),r("code",[t._v("netstat")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-hardware.html"}},[t._v("Linux 硬件管理")]),t._v(" - 关键词:"),r("code",[t._v("df")]),t._v(", "),r("code",[t._v("du")]),t._v(", "),r("code",[t._v("top")]),t._v(", "),r("code",[t._v("free")]),t._v(", "),r("code",[t._v("iotop")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/cli/linux-cli-software.html"}},[t._v("Linux 软件管理")]),t._v(" - 关键词:"),r("code",[t._v("rpm")]),t._v(", "),r("code",[t._v("yum")]),t._v(", "),r("code",[t._v("apt-get")])],1)]),t._v(" "),r("h3",{attrs:{id:"linux-运维"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#linux-运维"}},[t._v("#")]),t._v(" Linux 运维")]),t._v(" "),r("blockquote",[r("p",[t._v("Linux 系统的常见运维工作。")])]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/linux/ops/network-ops.html"}},[t._v("网络运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/samba.html"}},[t._v("Samba")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/ntp.html"}},[t._v("NTP")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/firewalld.html"}},[t._v("Firewalld")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/crontab.html"}},[t._v("Crontab")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/systemd.html"}},[t._v("Systemd")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/vim.html"}},[t._v("Vim")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/iptables.html"}},[t._v("Iptables")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/ops/zsh.html"}},[t._v("oh-my-zsh")])],1)]),t._v(" "),r("h3",{attrs:{id:"软件运维"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#软件运维"}},[t._v("#")]),t._v(" 软件运维")]),t._v(" "),r("blockquote",[r("p",[t._v("部署在 Linux 系统上的软件运维。")]),t._v(" "),r("p",[t._v("配套安装脚本:⌨ "),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft",target:"_blank",rel:"noopener noreferrer"}},[t._v("软件运维配置脚本集合"),r("OutboundLink")],1)])]),t._v(" "),r("ul",[r("li",[t._v("开发环境\n"),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/linux/soft/jdk-install.html"}},[t._v("JDK 安装")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/maven-install.html"}},[t._v("Maven 安装")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/nodejs-install.html"}},[t._v("Nodejs 安装")])],1)])]),t._v(" "),r("li",[t._v("开发工具\n"),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/linux/soft/nexus-ops.html"}},[t._v("Nexus 运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/gitlab-ops.html"}},[t._v("Gitlab 运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/jenkins-ops.html"}},[t._v("Jenkins 运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/svn-ops.html"}},[t._v("Svn 运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/yapi-ops.html"}},[t._v("YApi 运维")])],1)])]),t._v(" "),r("li",[t._v("中间件服务\n"),r("ul",[r("li",[r("a",{attrs:{href:"linux/soft/elastic"}},[t._v("Elastic 运维")])]),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/kafka-install.html"}},[t._v("Kafka 运维")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/rocketmq-install.html"}},[t._v("RocketMQ 运维")])],1),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/javatech/blob/master/docs/technology/monitor/zookeeper-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Zookeeper 运维"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/nacos-install.html"}},[t._v("Nacos 运维")])],1)])]),t._v(" "),r("li",[t._v("服务器\n"),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/nginx-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nginx 教程"),r("OutboundLink")],1),t._v(" 📚")]),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/linux/soft/tomcat-install.html"}},[t._v("Tomcat 运维")])],1)])]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/db-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据库"),r("OutboundLink")],1),t._v(" 📚\n"),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/db-tutorial/blob/master/docs/sql/mysql/mysql-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Mysql 运维"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Redis 运维"),r("OutboundLink")],1)])])])]),t._v(" "),r("h3",{attrs:{id:"docker"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#docker"}},[t._v("#")]),t._v(" Docker")]),t._v(" "),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/docker/docker-quickstart.html"}},[t._v("Docker 快速入门")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/docker/docker-dockerfile.html"}},[t._v("Dockerfile 最佳实践")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/docker/docker-cheat-sheet.html"}},[t._v("Docker Cheat Sheet")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/docker/kubernetes.html"}},[t._v("Kubernetes 应用指南")])],1)]),t._v(" "),r("h3",{attrs:{id:"其他"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#其他"}},[t._v("#")]),t._v(" 其他")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/blog/blob/master/source/_posts/coding/python.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("一篇文章让你彻底掌握 Python"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/blog/blob/master/source/_posts/coding/shell.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("一篇文章让你彻底掌握 Shell"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/blog/blob/master/source/_posts/tools/git.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Git 从入门到精通"),r("OutboundLink")],1)])]),t._v(" "),r("h2",{attrs:{id:"⌨-脚本"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#⌨-脚本"}},[t._v("#")]),t._v(" ⌨ 脚本")]),t._v(" "),r("h3",{attrs:{id:"shell-脚本大全"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#shell-脚本大全"}},[t._v("#")]),t._v(" Shell 脚本大全")]),t._v(" "),r("p",[r("strong",[t._v("Shell 脚本大全")]),t._v(" 精心收集、整理了 Linux 环境下的常见 Shell 脚本操作片段。")]),t._v(" "),r("p",[t._v("源码:"),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/shell",target:"_blank",rel:"noopener noreferrer"}},[r("strong",[t._v("Shell 脚本大全")]),r("OutboundLink")],1)]),t._v(" "),r("h3",{attrs:{id:"centos-运维脚本集合"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#centos-运维脚本集合"}},[t._v("#")]),t._v(" CentOS 运维脚本集合")]),t._v(" "),r("p",[t._v("本人作为一名 Java 后端,苦于经常在 CentOS 环境上开荒虚拟机。为提高效率,写了一套 Shell 脚本,提供如下功能:安装常用 lib 库、命令工具、设置 DNS、NTP、配置国内 yum 源、一键安装常用软件等。")]),t._v(" "),r("p",[t._v("源码:"),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux",target:"_blank",rel:"noopener noreferrer"}},[r("strong",[t._v("CentOS 常规操作运维脚本集合")]),r("OutboundLink")],1)]),t._v(" "),r("h2",{attrs:{id:"📚-资料"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#📚-资料"}},[t._v("#")]),t._v(" 📚 资料")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("Linux 命令")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("命令行的艺术"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://man.linuxde.net/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 命令大全"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/jaywcjlove/linux-command",target:"_blank",rel:"noopener noreferrer"}},[t._v("linux-command"),r("OutboundLink")],1)])])]),t._v(" "),r("li",[r("strong",[t._v("社区网站")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://linux.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 中国"),r("OutboundLink")],1),t._v(" - 各种资讯、文章、技术")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.shiyanlou.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("实验楼"),r("OutboundLink")],1),t._v(" - 免费提供了 Linux 在线环境,不用在自己机子上装系统也可以学习 Linux,超方便实用。")]),t._v(" "),r("li",[r("a",{attrs:{href:"http://linux.vbird.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("鸟哥的 linux 私房菜"),r("OutboundLink")],1),t._v(" - 非常适合 Linux 入门初学者看的教程。")]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.linuxidc.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 公社"),r("OutboundLink")],1),t._v(" - Linux 相关的新闻、教程、主题、壁纸都有。")]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.linuxde.net",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux Today"),r("OutboundLink")],1),t._v(" - Linux 新闻资讯发布,Linux 职业技术学习!。")])])]),t._v(" "),r("li",[r("strong",[t._v("知识相关")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"http://www.jianshu.com/p/59f759207862",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 思维导图整理"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.jianshu.com/p/fe2a790b41eb",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 初学者进阶学习资源整理"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.shiyanlou.com/courses/1",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 基础入门(新版)"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.jianshu.com/p/c5ae8f061cfe",target:"_blank",rel:"noopener noreferrer"}},[t._v("【译】Linux 概念架构的理解"),r("OutboundLink")],1),t._v(" "),r("a",{attrs:{href:"http://oss.org.cn/ossdocs/linux/kernel/a1/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("En"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 守护进程的启动方法"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.shiyanlou.com/questions/2992",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 编程之内存映射"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://blog.huachao.me/2016/1/Linux%E7%9F%A5%E8%AF%86%E7%82%B9%E5%B0%8F%E7%BB%93/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 知识点小结"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://linux.cn/article-6971-1.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("10 大白帽黑客专用的 Linux 操作系统"),r("OutboundLink")],1)])])]),t._v(" "),r("li",[r("strong",[t._v("软件工具")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://www.gitbook.com/book/alim0x/awesome-linux-software-zh_cn/details",target:"_blank",rel:"noopener noreferrer"}},[t._v("超赞的 Linux 软件"),r("OutboundLink")],1),t._v(" Github 仓库"),r("a",{attrs:{href:"https://github.com/alim0x/Awesome-Linux-Software-zh_CN",target:"_blank",rel:"noopener noreferrer"}},[t._v("Zh"),r("OutboundLink")],1),t._v(" "),r("a",{attrs:{href:"https://github.com/VoLuong/Awesome-Linux-Software",target:"_blank",rel:"noopener noreferrer"}},[t._v("En"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://os.51cto.com/art/201607/513796.htm",target:"_blank",rel:"noopener noreferrer"}},[t._v("程序员喜欢的 9 款最佳的 Linux 文件比较工具"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.codeceo.com/article/5-linux-productivity-tools.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("提高 Linux 开发效率的 5 个工具"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://os.51cto.com/art/201603/508027.htm",target:"_blank",rel:"noopener noreferrer"}},[t._v("你要了解的 11 款面向 Linux 系统的一流备份实用工具"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.simlinux.com/archives/264.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("16 个很有用的在线工具"),r("OutboundLink")],1)]),t._v(" "),r("li",[t._v("Adobe 软件的最佳替代品 "),r("a",{attrs:{href:"https://linux.cn/article-8928-1.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("原文在这里"),r("OutboundLink")],1),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://wiki.gnome.org/Apps/Evince",target:"_blank",rel:"noopener noreferrer"}},[t._v("Evince (Adobe Acrobat Reader)"),r("OutboundLink")],1),t._v(" 一个“支持多种文档格式的文档查看器”,可以查看 PDF,还支持各种漫画书格式")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://pixlr.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Pixlr (Adobe Photoshop)"),r("OutboundLink")],1),t._v(" 一个强大的图像编辑工具")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://inkscape.org/zh/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Inkscape (Adobe Illustrator)"),r("OutboundLink")],1),t._v(" 一个专业的矢量图形编辑器")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://pinegrow.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Pinegrow Web Editor (Adobe Dreamweaver)"),r("OutboundLink")],1),t._v(" 一个可视化编辑制作 HTML 网站")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.scribus.net/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Scribus (Adobe InDesign)"),r("OutboundLink")],1),t._v(" 一个开源电子杂志制作软件")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://webflow.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Webflow (Adobe Muse)"),r("OutboundLink")],1),t._v(" 一款可以帮助用户不用编码就可以快速创建网站的谷歌浏览器插件。")]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.maefloresta.com/portal/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Tupi (Adobe Animate)"),r("OutboundLink")],1),t._v(" 一款可以创建 HTML5 动画的工具。")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.blackmagicdesign.com",target:"_blank",rel:"noopener noreferrer"}},[t._v("Black Magic Fusion (Adobe After Effects)"),r("OutboundLink")],1),t._v(" 一款先进的合成软件,广泛应用于视觉特效、广电影视设计以及 3D 动画设计等领域。")])])])])]),t._v(" "),r("li",[r("strong",[t._v("中国开源镜像")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"http://mirrors.aliyun.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("阿里云开源镜像站"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.163.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("网易开源镜像站"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.sohu.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("搜狐开源镜像站"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirror.bjtu.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("北京交通大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirror.lzu.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("兰州大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.xmu.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("厦门大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://ftp.sjtu.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("上海交通大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.tuna.tsinghua.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("清华大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.ustc.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("中国科学技术大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirror.neu.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("东北大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.zju.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("浙江大学"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://mirrors.neusoft.edu.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("东软信息学院"),r("OutboundLink")],1)])])])]),t._v(" "),r("h2",{attrs:{id:"🚪-传送门"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#🚪-传送门"}},[t._v("#")]),t._v(" 🚪 传送门")]),t._v(" "),r("p",[t._v("◾ 🏠 "),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("LINUX-TUTORIAL 首页"),r("OutboundLink")],1),t._v(" ◾ 🎯 "),r("a",{attrs:{href:"https://github.com/dunwu/blog",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的博客"),r("OutboundLink")],1),t._v(" ◾")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/11.b9b41530.js b/assets/js/11.b9b41530.js new file mode 100644 index 0000000..f94fc63 --- /dev/null +++ b/assets/js/11.b9b41530.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{399:function(r,e,t){"use strict";t.r(e);var o=t(15),n=Object(o.a)({},(function(){var r=this,e=r.$createElement,t=r._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":r.$parent.slotKey}},[t("h1",{attrs:{id:"docker-教程"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-教程"}},[r._v("#")]),r._v(" Docker 教程")]),r._v(" "),t("h2",{attrs:{id:"📖-内容"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#📖-内容"}},[r._v("#")]),r._v(" 📖 内容")]),r._v(" "),t("ul",[t("li",[t("RouterLink",{attrs:{to:"/docker/docker/docker-quickstart.html"}},[r._v("Docker 快速入门")])],1),r._v(" "),t("li",[t("RouterLink",{attrs:{to:"/docker/docker/docker-dockerfile.html"}},[r._v("Dockerfile 最佳实践")])],1),r._v(" "),t("li",[t("RouterLink",{attrs:{to:"/docker/docker/docker-cheat-sheet.html"}},[r._v("Docker Cheat Sheet")])],1),r._v(" "),t("li",[t("RouterLink",{attrs:{to:"/docker/docker/kubernetes.html"}},[r._v("Kubernetes 应用指南")])],1)]),r._v(" "),t("h2",{attrs:{id:"📚-资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#📚-资料"}},[r._v("#")]),r._v(" 📚 资料")]),r._v(" "),t("ul",[t("li",[t("strong",[r._v("官方")]),r._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"http://www.docker.com",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 官网"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 官方文档"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/moby/moby",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker Github"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/docker/compose",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker Compose Github"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://hub.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker Hub"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://www.docker.com/community/open-source",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 开源"),t("OutboundLink")],1)])])]),r._v(" "),t("li",[t("strong",[r._v("资源整理")]),r._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/veggiemonk/awesome-docker",target:"_blank",rel:"noopener noreferrer"}},[r._v("Awesome Docker"),t("OutboundLink")],1)])])]),r._v(" "),t("li",[t("strong",[r._v("教程")]),r._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/yeasy/docker_practice",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker — 从入门到实践"),t("OutboundLink")],1),r._v(" - 非常详尽的 Docker 中文教程")]),r._v(" "),t("li",[t("a",{attrs:{href:"https://www.docker-cn.com/",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 中文网站"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker-cn.com/engine/installation/",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 安装手册"),t("OutboundLink")],1)])])]),r._v(" "),t("li",[t("strong",[r._v("镜像")]),r._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://hub.tenxcloud.com/",target:"_blank",rel:"noopener noreferrer"}},[r._v("时速云镜像仓库"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://c.163.com/hub#/m/library/",target:"_blank",rel:"noopener noreferrer"}},[r._v("网易云镜像服务"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://hub.daocloud.io/",target:"_blank",rel:"noopener noreferrer"}},[r._v("DaoCloud 镜像市场"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://cr.console.aliyun.com/",target:"_blank",rel:"noopener noreferrer"}},[r._v("阿里云镜像库"),t("OutboundLink")],1)])])]),r._v(" "),t("li",[t("strong",[r._v("文章")]),r._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker 入门教程"),t("OutboundLink")],1)]),r._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn",target:"_blank",rel:"noopener noreferrer"}},[r._v("Docker Cheat Sheet"),t("OutboundLink")],1)])])])]),r._v(" "),t("h2",{attrs:{id:"🚪-传送门"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#🚪-传送门"}},[r._v("#")]),r._v(" 🚪 传送门")]),r._v(" "),t("p",[r._v("◾ 🏠 "),t("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[r._v("DB-TUTORIAL 首页"),t("OutboundLink")],1),r._v(" ◾ 🎯 "),t("a",{attrs:{href:"https://github.com/dunwu/blog",target:"_blank",rel:"noopener noreferrer"}},[r._v("我的博客"),t("OutboundLink")],1),r._v(" ◾")])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/12.70a5dba8.js b/assets/js/12.70a5dba8.js new file mode 100644 index 0000000..5d75742 --- /dev/null +++ b/assets/js/12.70a5dba8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{400:function(e,r,t){"use strict";t.r(r);var a=t(15),n=Object(a.a)({},(function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"docker-cheat-sheet"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-cheat-sheet"}},[e._v("#")]),e._v(" Docker Cheat Sheet")]),e._v(" "),t("blockquote",[t("p",[e._v("内容主要搬迁自:"),t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Cheat Sheet"),t("OutboundLink")],1)])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"#%E4%B8%BA%E4%BD%95%E4%BD%BF%E7%94%A8-docker"}},[e._v("为何使用 Docker")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E8%BF%90%E7%BB%B4"}},[e._v("运维")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%AE%B9%E5%99%A8container"}},[e._v("容器(Container)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E9%95%9C%E5%83%8Fimages"}},[e._v("镜像(Images)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E7%BD%91%E7%BB%9Cnetworks"}},[e._v("网络(Networks)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E4%BB%93%E7%AE%A1%E4%B8%AD%E5%BF%83%E5%92%8C%E4%BB%93%E5%BA%93registry--repository"}},[e._v("仓管中心和仓库(Registry & Repository)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#dockerfile"}},[e._v("Dockerfile")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%B1%82layers"}},[e._v("层(Layers)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E9%93%BE%E6%8E%A5links"}},[e._v("链接(Links)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%8D%B7%E6%A0%87volumes"}},[e._v("卷标(Volumes)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E6%9A%B4%E9%9C%B2%E7%AB%AF%E5%8F%A3exposing-ports"}},[e._v("暴露端口(Exposing ports)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5"}},[e._v("最佳实践")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%AE%89%E5%85%A8security"}},[e._v("安全(Security)")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%B0%8F%E8%B4%B4%E5%A3%AB"}},[e._v("小贴士")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[e._v("参考资料")])])]),e._v(" "),t("h2",{attrs:{id:"为何使用-docker"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#为何使用-docker"}},[e._v("#")]),e._v(" 为何使用 Docker")]),e._v(" "),t("p",[e._v("「通过 Docker,开发者可以使用任何语言任何工具创建任何应用。“Dockerized” 的应用是完全可移植的,能在任何地方运行 - 不管是同事的 OS X 和 Windows 笔记本,或是在云端运行的 Ubuntu QA 服务,还是在虚拟机运行的 Red Hat 产品数据中心。")]),e._v(" "),t("p",[e._v("Docker Hub 上有 13000+ 的应用,开发者可以从中选取一个进行快速扩展开发。Docker 跟踪管理变更和依赖关系,让系统管理员能更容易理解开发人员是如何让应用运转起来的。而开发者可以通过 Docker Hub 的共有/私有仓库,构建他们的自动化编译,与其他合作者共享成果。")]),e._v(" "),t("p",[e._v("Docker 帮助开发者更快地构建和发布高质量的应用。」—— "),t("a",{attrs:{href:"https://www.docker.com/what-docker/#copy1",target:"_blank",rel:"noopener noreferrer"}},[e._v("什么是 Docker"),t("OutboundLink")],1)]),e._v(" "),t("h2",{attrs:{id:"运维"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#运维"}},[e._v("#")]),e._v(" 运维")]),e._v(" "),t("h3",{attrs:{id:"安装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[e._v("#")]),e._v(" 安装")]),e._v(" "),t("p",[e._v("Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到。")]),e._v(" "),t("p",[e._v("Docker CE 的安装请参考官方文档。")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/docker-for-mac/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Mac"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/docker-for-windows/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Windows"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/linux/docker-ce/ubuntu/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Ubuntu"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/linux/docker-ce/debian/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Debian"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/linux/docker-ce/centos/",target:"_blank",rel:"noopener noreferrer"}},[e._v("CentOS"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/linux/docker-ce/fedora/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Fedora"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/linux/docker-ce/binaries/",target:"_blank",rel:"noopener noreferrer"}},[e._v("其他 Linux 发行版"),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"检查版本"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#检查版本"}},[e._v("#")]),e._v(" 检查版本")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/version/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker version")]),t("OutboundLink")],1),e._v(" 查看你正在运行的 Docker 版本。")]),e._v(" "),t("p",[e._v("获取 Docker 服务版本:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker version --format '{{.Server.Version}}'\n")])])]),t("p",[e._v("你也可以输出原始的 JSON 数据:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker version --format '{{json .}}'\n")])])]),t("h3",{attrs:{id:"docker-加速"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-加速"}},[e._v("#")]),e._v(" Docker 加速")]),e._v(" "),t("p",[e._v("国内访问 Docker Hub 很慢,所以,推荐配置 Docker 镜像仓库来提速。")]),e._v(" "),t("p",[e._v("镜像仓库清单:")]),e._v(" "),t("table",[t("thead",[t("tr",[t("th",[e._v("镜像仓库")]),e._v(" "),t("th",[e._v("镜像仓库地址")]),e._v(" "),t("th",[e._v("说明")])])]),e._v(" "),t("tbody",[t("tr",[t("td",[t("a",{attrs:{href:"https://daocloud.io/mirror",target:"_blank",rel:"noopener noreferrer"}},[e._v("DaoCloud 镜像站"),t("OutboundLink")],1)]),e._v(" "),t("td",[t("code",[e._v("http://f1361db2.m.daocloud.io")])]),e._v(" "),t("td",[e._v("开发者需要开通 DaoCloud 账户,然后可以得到专属加速器。")])]),e._v(" "),t("tr",[t("td",[t("a",{attrs:{href:"https://cr.console.aliyun.com",target:"_blank",rel:"noopener noreferrer"}},[e._v("阿里云"),t("OutboundLink")],1)]),e._v(" "),t("td",[t("code",[e._v("https://yourcode.mirror.aliyuncs.com")])]),e._v(" "),t("td",[e._v("开发者需要开通阿里开发者帐户,再使用阿里的加速服务。登录后阿里开发者帐户后,"),t("code",[e._v("https://cr.console.aliyun.com/undefined/instances/mirrors")]),e._v(" 中查看你的您的专属加速器地址。")])]),e._v(" "),t("tr",[t("td",[t("a",{attrs:{href:"https://c.163yun.com/hub",target:"_blank",rel:"noopener noreferrer"}},[e._v("网易云"),t("OutboundLink")],1)]),e._v(" "),t("td",[t("code",[e._v("https://hub-mirror.c.163.com")])]),e._v(" "),t("td",[e._v("直接配置即可,亲测较为稳定。")])])])]),e._v(" "),t("p",[e._v("配置镜像仓库方法(以 CentOS 为例):")]),e._v(" "),t("blockquote",[t("p",[e._v("下面的示例为在 CentOS 环境中,指定镜像仓库为 "),t("code",[e._v("https://hub-mirror.c.163.com")])])]),e._v(" "),t("p",[e._v("(1)修改配置文件")]),e._v(" "),t("p",[e._v("修改 "),t("code",[e._v("/etc/docker/daemon.json")]),e._v(" ,如果不存在则新建。执行以下 Shell:")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("mkdir")]),e._v(" -p /etc/docker\n"),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">>")]),e._v(" /etc/docker/daemon.json "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<<")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('EOF\n{\n "registry-mirrors": [\n "https://hub-mirror.c.163.com"\n ]\n}\nEOF')]),e._v("\n")])])]),t("p",[e._v("重启 docker 以生效:")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" systemctl daemon-reload\n"),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" systemctl restart docker\n")])])]),t("p",[e._v("执行 "),t("code",[e._v("docker info")]),e._v(" 命令,查看 "),t("code",[e._v("Registry Mirrors")]),e._v(" 是否已被改为 "),t("code",[e._v("https://hub-mirror.c.163.com")]),e._v(" ,如果是,则表示配置成功。")]),e._v(" "),t("h2",{attrs:{id:"容器-container"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#容器-container"}},[e._v("#")]),e._v(" 容器(Container)")]),e._v(" "),t("p",[t("a",{attrs:{href:"http://etherealmind.com/basics-docker-containers-hypervisors-coreos/",target:"_blank",rel:"noopener noreferrer"}},[e._v("关于 Docker 进程隔离的基础"),t("OutboundLink")],1),e._v("。容器 (Container) 之于虚拟机 (Virtual Machine) 就好比线程之于进程。或者你可以把他们想成是「吃了类固醇的 chroots」。")]),e._v(" "),t("h3",{attrs:{id:"生命周期"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#生命周期"}},[e._v("#")]),e._v(" 生命周期")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/create",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker create")]),t("OutboundLink")],1),e._v(" 创建容器但不启动它。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/rename/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker rename")]),t("OutboundLink")],1),e._v(" 用于重命名容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/run",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker run")]),t("OutboundLink")],1),e._v(" 一键创建并同时启动该容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/rm",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker rm")]),t("OutboundLink")],1),e._v(" 删除容器。\n"),t("ul",[t("li",[e._v("如果要删除一个运行中的容器,可以添加 "),t("code",[e._v("-f")]),e._v(" 参数。Docker 会发送 "),t("code",[e._v("SIGKILL")]),e._v(" 信号给容器。")])])]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/update/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker update")]),t("OutboundLink")],1),e._v(" 调整容器的资源限制。")]),e._v(" "),t("li",[e._v("清理掉所有处于终止状态的容器。")])]),e._v(" "),t("p",[e._v("通常情况下,不使用任何命令行选项启动一个容器,该容器将会立即启动并停止。若需保持其运行,你可以使用 "),t("code",[e._v("docker run -td container_id")]),e._v(" 命令。选项 "),t("code",[e._v("-t")]),e._v(" 表示分配一个 pseudo-TTY 会话,"),t("code",[e._v("-d")]),e._v(" 表示自动将容器与终端分离(也就是说在后台运行容器,并输出容器 ID)。")]),e._v(" "),t("p",[e._v("如果你需要一个临时容器,可使用 "),t("code",[e._v("docker run --rm")]),e._v(" 会在容器停止之后删除它。")]),e._v(" "),t("p",[e._v("如果你需要映射宿主机 (host) 的目录到 Docker 容器内,可使用 "),t("code",[e._v("docker run -v $HOSTDIR:$DOCKERDIR")]),e._v("。详见 "),t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#%E5%8D%B7%E6%A0%87volumes",target:"_blank",rel:"noopener noreferrer"}},[e._v("卷标(Volumes)"),t("OutboundLink")],1),e._v(" 一节。")]),e._v(" "),t("p",[e._v("如果你想同时删除与容器相关联的卷标,那么在删除容器的时候必须包含 "),t("code",[e._v("-v")]),e._v(" 选项,像这样 "),t("code",[e._v("docker rm -v")]),e._v("。")]),e._v(" "),t("p",[e._v("从 Docker 1.10 起,其内置一套各容器独立的 "),t("a",{attrs:{href:"https://docs.docker.com/engine/admin/logging/overview/",target:"_blank",rel:"noopener noreferrer"}},[e._v("日志引擎"),t("OutboundLink")],1),e._v(",每个容器可以独立使用。你可以使用 "),t("code",[e._v("docker run --log-driver=syslog")]),e._v(" 来自定义日志引擎(例如以上的 "),t("code",[e._v("syslog")]),e._v(")。")]),e._v(" "),t("h3",{attrs:{id:"启动和停止"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#启动和停止"}},[e._v("#")]),e._v(" 启动和停止")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/start",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker start")]),t("OutboundLink")],1),e._v(" 启动已存在的容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/stop",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker stop")]),t("OutboundLink")],1),e._v(" 停止运行中的容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/restart",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker restart")]),t("OutboundLink")],1),e._v(" 重启容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/pause/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker pause")]),t("OutboundLink")],1),e._v(" 暂停运行中的容器,将其「冻结」在当前状态。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/unpause/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker unpause")]),t("OutboundLink")],1),e._v(" 结束容器暂停状态。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/wait",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker wait")]),t("OutboundLink")],1),e._v(" 阻塞地等待某个运行中的容器直到停止。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/kill",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker kill")]),t("OutboundLink")],1),e._v(" 向运行中的容器发送 SIGKILL 指令。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/attach",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker attach")]),t("OutboundLink")],1),e._v(" 连接到运行中的容器。")])]),e._v(" "),t("p",[e._v("如果你想将容器的端口 (ports) 暴露至宿主机,请见 "),t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#%E6%9A%B4%E9%9C%B2%E7%AB%AF%E5%8F%A3exposing-ports",target:"_blank",rel:"noopener noreferrer"}},[e._v("暴露端口"),t("OutboundLink")],1),e._v(" 一节。")]),e._v(" "),t("p",[e._v("关于 Docker 实例崩溃后的重启策略,详见 "),t("a",{attrs:{href:"http://container42.com/2014/09/30/docker-restart-policies/",target:"_blank",rel:"noopener noreferrer"}},[e._v("本文"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h4",{attrs:{id:"cpu-限制"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#cpu-限制"}},[e._v("#")]),e._v(" CPU 限制")]),e._v(" "),t("p",[e._v("你可以限制 CPU 资源占用,无论是指定百分比,或是特定核心数。")]),e._v(" "),t("p",[e._v("例如,你可以设置 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/run/#/cpu-share-constraint",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("cpu-shares")]),t("OutboundLink")],1),e._v("。该配置看起来有点奇怪 -- 1024 表示 100% CPU,因此如果你希望容器使用所有 CPU 内核的 50%,应将其设置为 512:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -ti --c 512 agileek/cpuset-test\n")])])]),t("p",[e._v("更多信息请参阅 https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/#_cpu。")]),e._v(" "),t("p",[e._v("通过 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/run/#/cpuset-constraint",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("cpuset-cpus")]),t("OutboundLink")],1),e._v(" 可使用特定 CPU 内核。")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -ti --cpuset-cpus=0,4,6 agileek/cpuset-test\n")])])]),t("p",[e._v("请参阅 https://agileek.github.io/docker/2014/08/06/docker-cpuset/ 获取更多细节以及一些不错的视频。")]),e._v(" "),t("p",[e._v("注意,Docker 在容器内仍然能够 "),t("strong",[e._v("看到")]),e._v(" 全部 CPU -- 它仅仅是不使用全部而已。请参阅 https://github.com/docker/docker/issues/20770 获取更多细节。")]),e._v(" "),t("h4",{attrs:{id:"内存限制"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#内存限制"}},[e._v("#")]),e._v(" 内存限制")]),e._v(" "),t("p",[e._v("同样,亦可给 Docker 设置 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/run/#/user-memory-constraints",target:"_blank",rel:"noopener noreferrer"}},[e._v("内存限制"),t("OutboundLink")],1),e._v(":")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -it -m 300M ubuntu:14.04 /bin/bash\n")])])]),t("h4",{attrs:{id:"能力-capabilities"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#能力-capabilities"}},[e._v("#")]),e._v(" 能力(Capabilities)")]),e._v(" "),t("p",[e._v("Linux 的 Capability 可以通过使用 "),t("code",[e._v("cap-add")]),e._v(" 和 "),t("code",[e._v("cap-drop")]),e._v(" 设置。请参阅 https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities 获取更多细节。这有助于提高安全性。")]),e._v(" "),t("p",[e._v("如需要挂载基于 FUSE 的文件系统,你需要结合 "),t("code",[e._v("--cap-add")]),e._v(" 和 "),t("code",[e._v("--device")]),e._v(" 使用:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs\n")])])]),t("p",[e._v("授予对某个设备的访问权限:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -it --device=/dev/ttyUSB0 debian bash\n")])])]),t("p",[e._v("授予对所有设备的访问权限:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash\n")])])]),t("p",[e._v("有关容器特权的更多信息请参阅 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities",target:"_blank",rel:"noopener noreferrer"}},[e._v("本文"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h3",{attrs:{id:"信息"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#信息"}},[e._v("#")]),e._v(" 信息")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/ps",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker ps")]),t("OutboundLink")],1),e._v(" 查看运行中的所有容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/logs",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker logs")]),t("OutboundLink")],1),e._v(" 从容器中读取日志。(你也可以使用自定义日志驱动,不过在 1.10 中,它只支持 "),t("code",[e._v("json-file")]),e._v(" 和 "),t("code",[e._v("journald")]),e._v(")。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/inspect",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker inspect")]),t("OutboundLink")],1),e._v(" 查看某个容器的所有信息(包括 IP 地址)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/events",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker events")]),t("OutboundLink")],1),e._v(" 从容器中获取事件 (events)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/port",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker port")]),t("OutboundLink")],1),e._v(" 查看容器的公开端口。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/top",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker top")]),t("OutboundLink")],1),e._v(" 查看容器中活动进程。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/stats",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker stats")]),t("OutboundLink")],1),e._v(" 查看容器的资源使用量统计信息。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/diff",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker diff")]),t("OutboundLink")],1),e._v(" 查看容器文件系统中存在改动的文件。")])]),e._v(" "),t("p",[t("code",[e._v("docker ps -a")]),e._v(" 将显示所有容器,包括运行中和已停止的。")]),e._v(" "),t("p",[t("code",[e._v("docker stats --all")]),e._v(" 同样将显示所有容器,默认仅显示运行中的容器。")]),e._v(" "),t("h3",{attrs:{id:"导入-导出"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#导入-导出"}},[e._v("#")]),e._v(" 导入 / 导出")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/cp",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker cp")]),t("OutboundLink")],1),e._v(" 在容器和本地文件系统之间复制文件或目录。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/export",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker export")]),t("OutboundLink")],1),e._v(" 将容器的文件系统打包为归档文件流 (tarball archive stream) 并输出至标准输出 (STDOUT)。")])]),e._v(" "),t("h3",{attrs:{id:"执行命令"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#执行命令"}},[e._v("#")]),e._v(" 执行命令")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/exec",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker exec")]),t("OutboundLink")],1),e._v(" 在容器内执行命令。")])]),e._v(" "),t("p",[e._v("例如,进入正在运行的 "),t("code",[e._v("foo")]),e._v(" 容器,并连接 (attach) 到一个新的 Shell 进程:"),t("code",[e._v("docker exec -it foo /bin/bash")]),e._v("。")]),e._v(" "),t("h2",{attrs:{id:"镜像-images"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#镜像-images"}},[e._v("#")]),e._v(" 镜像(Images)")]),e._v(" "),t("p",[e._v("镜像是 "),t("a",{attrs:{href:"https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 容器的模板"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h3",{attrs:{id:"生命周期-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#生命周期-2"}},[e._v("#")]),e._v(" 生命周期")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/images",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker images")]),t("OutboundLink")],1),e._v(" 查看所有镜像。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/import",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker import")]),t("OutboundLink")],1),e._v(" 从归档文件创建镜像。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/build",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker build")]),t("OutboundLink")],1),e._v(" 从 Dockerfile 创建镜像。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/commit",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker commit")]),t("OutboundLink")],1),e._v(" 为容器创建镜像,如果容器正在运行则会临时暂停。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/rmi",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker rmi")]),t("OutboundLink")],1),e._v(" 删除镜像。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/load",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker load")]),t("OutboundLink")],1),e._v(" 从标准输入 (STDIN) 加载归档包 (tar archive) 作为镜像,包括镜像本身和标签 (tags, 0.7 起)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/save",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker save")]),t("OutboundLink")],1),e._v(" 将镜像打包为归档包,并输出至标准输出 (STDOUT),包括所有的父层、标签和版本 (parent layers, tags, versions, 0.7 起)。")])]),e._v(" "),t("h3",{attrs:{id:"其它信息"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#其它信息"}},[e._v("#")]),e._v(" 其它信息")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/history",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker history")]),t("OutboundLink")],1),e._v(" 查看镜像的历史记录。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/tag",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker tag")]),t("OutboundLink")],1),e._v(" 给镜像打标签命名(本地或者仓库均可)。")])]),e._v(" "),t("h3",{attrs:{id:"清理"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#清理"}},[e._v("#")]),e._v(" 清理")]),e._v(" "),t("p",[e._v("虽然你可以用 "),t("code",[e._v("docker rmi")]),e._v(" 命令来删除指定的镜像,不过有个名为 "),t("a",{attrs:{href:"https://github.com/spotify/docker-gc",target:"_blank",rel:"noopener noreferrer"}},[e._v("docker-gc"),t("OutboundLink")],1),e._v(" 的工具,它可以以一种安全的方式,清理掉那些不再被任何容器使用的镜像。Docker 1.13 起,使用 "),t("code",[e._v("docker image prune")]),e._v(" 亦可删除未使用的镜像。参见 "),t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#%E6%B8%85%E7%90%86",target:"_blank",rel:"noopener noreferrer"}},[e._v("清理"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h3",{attrs:{id:"加载-保存镜像"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#加载-保存镜像"}},[e._v("#")]),e._v(" 加载 / 保存镜像")]),e._v(" "),t("p",[e._v("从文件中加载镜像:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker load < my_image.tar.gz\n")])])]),t("p",[e._v("保存既有镜像:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker save my_image:my_tag | gzip > my_image.tar.gz\n")])])]),t("h3",{attrs:{id:"导入-导出容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#导入-导出容器"}},[e._v("#")]),e._v(" 导入 / 导出容器")]),e._v(" "),t("p",[e._v("从文件中导入容器镜像:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("cat my_container.tar.gz | docker import - my_image:my_tag\n")])])]),t("p",[e._v("导出既有容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker export my_container | gzip > my_container.tar.gz\n")])])]),t("h3",{attrs:{id:"加载已保存的镜像-与-导入已导出为镜像的容器-的不同"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#加载已保存的镜像-与-导入已导出为镜像的容器-的不同"}},[e._v("#")]),e._v(" 加载已保存的镜像 与 导入已导出为镜像的容器 的不同")]),e._v(" "),t("p",[e._v("通过 "),t("code",[e._v("load")]),e._v(" 命令来加载镜像,会创建一个新的镜像,并继承原镜像的所有历史。 通过 "),t("code",[e._v("import")]),e._v(" 将容器作为镜像导入,也会创建一个新的镜像,但并不包含原镜像的历史,因此会比使用 "),t("code",[e._v("load")]),e._v(" 方式生成的镜像更小。")]),e._v(" "),t("h2",{attrs:{id:"网络-networks"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网络-networks"}},[e._v("#")]),e._v(" 网络(Networks)")]),e._v(" "),t("p",[e._v("Docker 具备 "),t("a",{attrs:{href:"https://docs.docker.com/engine/userguide/networking/",target:"_blank",rel:"noopener noreferrer"}},[e._v("网络"),t("OutboundLink")],1),e._v(" 功能。我并不是很了解它,所以这是一个扩展本文的好地方。文档 "),t("a",{attrs:{href:"https://docs.docker.com/engine/userguide/networking/work-with-networks/",target:"_blank",rel:"noopener noreferrer"}},[e._v("使用网络"),t("OutboundLink")],1),e._v(" 指出,这是一种无需暴露端口即可实现 Docker 容器间通信的好方法。")]),e._v(" "),t("h3",{attrs:{id:"生命周期-3"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#生命周期-3"}},[e._v("#")]),e._v(" 生命周期")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_create/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network create")]),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_rm/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network rm")]),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"其它信息-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#其它信息-2"}},[e._v("#")]),e._v(" 其它信息")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_ls/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network ls")]),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_inspect/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network inspect")]),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"建立连接"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#建立连接"}},[e._v("#")]),e._v(" 建立连接")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_connect/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network connect")]),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/network_disconnect/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker network disconnect")]),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("你可以 "),t("a",{attrs:{href:"https://blog.jessfraz.com/post/ips-for-all-the-things/",target:"_blank",rel:"noopener noreferrer"}},[e._v("为容器指定 IP 地址"),t("OutboundLink")],1),e._v(":")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("# 使用你自己的子网和网关创建一个桥接网络\ndocker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic\n\n# 基于以上创建的网络,运行一个 Nginx 容器并指定 IP\n$ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx\n\n# 在其他地方使用 CURL 访问这个 IP(假设该 IP 为公网)\n$ curl 203.0.113.2\n")])])]),t("h2",{attrs:{id:"暴露端口-exposing-ports"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#暴露端口-exposing-ports"}},[e._v("#")]),e._v(" 暴露端口(Exposing ports)")]),e._v(" "),t("p",[e._v("通过宿主容器暴露输入端口相当 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/run/#expose-incoming-ports",target:"_blank",rel:"noopener noreferrer"}},[e._v("繁琐但有效的"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("例如使用 "),t("code",[e._v("-p")]),e._v(" 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage\n")])])]),t("p",[e._v("你可以使用 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#expose",target:"_blank",rel:"noopener noreferrer"}},[e._v("EXPOSE"),t("OutboundLink")],1),e._v(" 告知 Docker,该容器在运行时监听指定的端口:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("EXPOSE \n")])])]),t("p",[e._v("但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 "),t("code",[e._v("-p")]),e._v(" 。比如说你要在 localhost 上暴露容器的端口:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination :\n")])])]),t("p",[e._v("如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 "),t("a",{attrs:{href:"https://docs.vagrantup.com/v2/networking/forwarded_ports.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("forwarded_port"),t("OutboundLink")],1),e._v(" 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|\n ...\n\n (49000..49900).each do |port|\n config.vm.network :forwarded_port, :host => port, :guest => port\n end\n\n ...\nend\n")])])]),t("p",[e._v("如果你忘记了将什么端口映射到宿主机上的话,可使用 "),t("code",[e._v("docker port")]),e._v(" 查看:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker port CONTAINER $CONTAINERPORT\n")])])]),t("h2",{attrs:{id:"仓管中心和仓库-registry-repository"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#仓管中心和仓库-registry-repository"}},[e._v("#")]),e._v(" 仓管中心和仓库(Registry & Repository)")]),e._v(" "),t("p",[e._v("仓库 (repository) 是 "),t("em",[e._v("被托管(hosted)")]),e._v(" 的已命名镜像 (tagged images) 的集合,这组镜像用于构建容器文件系统。")]),e._v(" "),t("p",[e._v("仓管中心 (registry) 则是 "),t("em",[e._v("托管服务(host)")]),e._v(" -- 用于存储仓库并提供 HTTP API,以便 "),t("a",{attrs:{href:"https://docs.docker.com/engine/tutorials/dockerrepos/",target:"_blank",rel:"noopener noreferrer"}},[e._v("管理仓库的上传和下载"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("Docker 官方托管着自己的 "),t("a",{attrs:{href:"https://hub.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("仓管中心"),t("OutboundLink")],1),e._v(",包含着数量众多的仓库。不过话虽如此,这个仓管中心 "),t("a",{attrs:{href:"https://titanous.com/posts/docker-insecurity",target:"_blank",rel:"noopener noreferrer"}},[e._v("并没有很好地验证镜像"),t("OutboundLink")],1),e._v(",所以如果你担心安全问题的话,请尽量避免使用它。")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/login",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker login")]),t("OutboundLink")],1),e._v(" 登入仓管中心。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/logout",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker logout")]),t("OutboundLink")],1),e._v(" 登出仓管中心。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/search",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker search")]),t("OutboundLink")],1),e._v(" 从仓管中心检索镜像。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/pull",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker pull")]),t("OutboundLink")],1),e._v(" 从仓管中心拉取镜像到本地。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/push",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker push")]),t("OutboundLink")],1),e._v(" 从本地推送镜像到仓管中心。")])]),e._v(" "),t("h3",{attrs:{id:"本地仓管中心"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#本地仓管中心"}},[e._v("#")]),e._v(" 本地仓管中心")]),e._v(" "),t("p",[e._v("你可以使用 "),t("a",{attrs:{href:"https://github.com/docker/distribution",target:"_blank",rel:"noopener noreferrer"}},[e._v("docker distribution"),t("OutboundLink")],1),e._v(" 项目搭建本地的仓管中心,详情参阅 "),t("a",{attrs:{href:"https://github.com/docker/docker.github.io/blob/master/registry/deploying.md",target:"_blank",rel:"noopener noreferrer"}},[e._v("本地发布 (local deploy)"),t("OutboundLink")],1),e._v(" 的介绍。")]),e._v(" "),t("p",[e._v("科学上网后,也可以看看 "),t("a",{attrs:{href:"https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution",target:"_blank",rel:"noopener noreferrer"}},[e._v("Google+ Group"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h2",{attrs:{id:"dockerfile"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dockerfile"}},[e._v("#")]),e._v(" Dockerfile")]),e._v(" "),t("p",[e._v("当你执行 "),t("code",[e._v("docker build")]),e._v(" 时,Docker 将会根据 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/",target:"_blank",rel:"noopener noreferrer"}},[e._v("配置文件"),t("OutboundLink")],1),e._v(" 启动 Docker 容器。远优于使用 "),t("code",[e._v("docker commit")]),e._v("。")]),e._v(" "),t("p",[e._v("以下是一些编写 Dockerfile 的常用编辑器,并链接到适配的语法高亮模块︰")]),e._v(" "),t("ul",[t("li",[e._v("如果你在使用 "),t("a",{attrs:{href:"http://jedit.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("jEdit"),t("OutboundLink")],1),e._v(",你可以使用我开发的 Dockerfile "),t("a",{attrs:{href:"https://github.com/wsargent/jedit-docker-mode",target:"_blank",rel:"noopener noreferrer"}},[e._v("语法高亮模块"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("li",[e._v("[Sublime Text 2](https://packagecontrol.io/packages/Dockerfile Syntax Highlighting)")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://atom.io/packages/language-docker",target:"_blank",rel:"noopener noreferrer"}},[e._v("Atom"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/ekalinin/Dockerfile.vim",target:"_blank",rel:"noopener noreferrer"}},[e._v("Vim"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/spotify/dockerfile-mode",target:"_blank",rel:"noopener noreferrer"}},[e._v("Emacs"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/docker/docker/tree/master/contrib/syntax/textmate",target:"_blank",rel:"noopener noreferrer"}},[e._v("TextMate"),t("OutboundLink")],1)]),e._v(" "),t("li",[e._v("更多信息请参阅 "),t("a",{attrs:{href:"https://domeide.github.io/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 遇上 IDE"),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"指令"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#指令"}},[e._v("#")]),e._v(" 指令")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#dockerignore-file",target:"_blank",rel:"noopener noreferrer"}},[e._v(".dockerignore"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#from",target:"_blank",rel:"noopener noreferrer"}},[e._v("FROM"),t("OutboundLink")],1),e._v(" 为其他指令设置基础镜像 (Base Image)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#maintainer-deprecated",target:"_blank",rel:"noopener noreferrer"}},[e._v("MAINTAINER (deprecated - use LABEL instead)"),t("OutboundLink")],1),e._v(" 为生成的镜像设置作者字段。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#run",target:"_blank",rel:"noopener noreferrer"}},[e._v("RUN"),t("OutboundLink")],1),e._v(" 在当前镜像的基础上生成一个新层并执行命令。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#cmd",target:"_blank",rel:"noopener noreferrer"}},[e._v("CMD"),t("OutboundLink")],1),e._v(" 设置容器默认执行命令。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#expose",target:"_blank",rel:"noopener noreferrer"}},[e._v("EXPOSE"),t("OutboundLink")],1),e._v(" 告知 Docker 容器在运行时所要监听的网络端口。注意:并没有实际上将端口设置为可访问。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#env",target:"_blank",rel:"noopener noreferrer"}},[e._v("ENV"),t("OutboundLink")],1),e._v(" 设置环境变量。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#add",target:"_blank",rel:"noopener noreferrer"}},[e._v("ADD"),t("OutboundLink")],1),e._v(" 将文件、目录或远程文件复制到容器中。缓存无效。请尽量用 "),t("code",[e._v("COPY")]),e._v(" 代替 "),t("code",[e._v("ADD")]),e._v("。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#copy",target:"_blank",rel:"noopener noreferrer"}},[e._v("COPY"),t("OutboundLink")],1),e._v(" 将文件或文件夹复制到容器中。注意:将使用 ROOT 用户复制文件,故无论 USER / WORKDIR 指令如何配置,你都需要手动修改其所有者("),t("code",[e._v("chown")]),e._v("),"),t("code",[e._v("ADD")]),e._v(" 也是一样。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#entrypoint",target:"_blank",rel:"noopener noreferrer"}},[e._v("ENTRYPOINT"),t("OutboundLink")],1),e._v(" 将容器设为可执行的。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#volume",target:"_blank",rel:"noopener noreferrer"}},[e._v("VOLUME"),t("OutboundLink")],1),e._v(" 在容器内部创建挂载点 (mount point) 指向外部挂载的卷标或其他容器。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#user",target:"_blank",rel:"noopener noreferrer"}},[e._v("USER"),t("OutboundLink")],1),e._v(" 设置随后执行 RUN / CMD / ENTRYPOINT 命令的用户名。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#workdir",target:"_blank",rel:"noopener noreferrer"}},[e._v("WORKDIR"),t("OutboundLink")],1),e._v(" 设置工作目录 (working directory)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#arg",target:"_blank",rel:"noopener noreferrer"}},[e._v("ARG"),t("OutboundLink")],1),e._v(" 定义编译时 (build-time) 变量。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#onbuild",target:"_blank",rel:"noopener noreferrer"}},[e._v("ONBUILD"),t("OutboundLink")],1),e._v(" 添加触发指令,当该镜像被作为其他镜像的基础镜像时该指令会被触发。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#stopsignal",target:"_blank",rel:"noopener noreferrer"}},[e._v("STOPSIGNAL"),t("OutboundLink")],1),e._v(" 设置停止容器时,向容器内发送的系统调用信号 (system call signal)。")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/config/labels-custom-metadata/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LABEL"),t("OutboundLink")],1),e._v(" 将键值对元数据 (key/value metadata) 应用到镜像、容器或是守护进程。")])]),e._v(" "),t("h3",{attrs:{id:"教程"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#教程"}},[e._v("#")]),e._v(" 教程")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"http://flux7.com/blogs/docker/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Flux7's Dockerfile Tutorial"),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"例子"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#例子"}},[e._v("#")]),e._v(" 例子")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#dockerfile-examples",target:"_blank",rel:"noopener noreferrer"}},[e._v("Examples"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Best practices for writing Dockerfiles"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"http://crosbymichael.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Michael Crosby"),t("OutboundLink")],1),e._v(" 还有更多的 "),t("a",{attrs:{href:"http://crosbymichael.com/dockerfile-best-practices.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Dockerfiles best practices"),t("OutboundLink")],1),e._v(" / "),t("a",{attrs:{href:"http://crosbymichael.com/dockerfile-best-practices-take-2.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("take 2"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"http://jonathan.bergknoff.com/journal/building-good-docker-images",target:"_blank",rel:"noopener noreferrer"}},[e._v("Building Good Docker Images"),t("OutboundLink")],1),e._v(" / "),t("a",{attrs:{href:"http://jonathan.bergknoff.com/journal/building-better-docker-images",target:"_blank",rel:"noopener noreferrer"}},[e._v("Building Better Docker Images"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://speakerdeck.com/garethr/managing-container-configuration-with-metadata",target:"_blank",rel:"noopener noreferrer"}},[e._v("Managing Container Configuration with Metadata"),t("OutboundLink")],1)])]),e._v(" "),t("h2",{attrs:{id:"层-layers"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#层-layers"}},[e._v("#")]),e._v(" 层(Layers)")]),e._v(" "),t("p",[e._v("Docker 的版本化文件系统是基于层的。就像 "),t("a",{attrs:{href:"https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Git 的提交或文件变更系统"),t("OutboundLink")],1),e._v(" 一样。")]),e._v(" "),t("h2",{attrs:{id:"链接-links"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#链接-links"}},[e._v("#")]),e._v(" 链接(Links)")]),e._v(" "),t("p",[e._v("链接 (links) "),t("a",{attrs:{href:"https://docs.docker.com/userguide/dockerlinks/",target:"_blank",rel:"noopener noreferrer"}},[e._v("通过 TCP/IP 端口"),t("OutboundLink")],1),e._v(" 实现 Docker 容器之间的通讯。"),t("a",{attrs:{href:"https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Atlassian"),t("OutboundLink")],1),e._v(" 展示了可用的例子。你还可以 "),t("a",{attrs:{href:"https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file",target:"_blank",rel:"noopener noreferrer"}},[e._v("通过主机名 (hostname) 链接"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("在某种意义上来说,该特性已经被 "),t("a",{attrs:{href:"https://docs.docker.com/network/",target:"_blank",rel:"noopener noreferrer"}},[e._v("自定义网络"),t("OutboundLink")],1),e._v(" 所替代。")]),e._v(" "),t("p",[e._v("注意: 如果你希望容器之间"),t("strong",[e._v("只")]),e._v("通过链接进行通讯,在启动 Docker 守护进程时,请使用 "),t("code",[e._v("-icc=false")]),e._v(" 来禁用内部进程通讯。")]),e._v(" "),t("p",[e._v("假设你有一个名为 CONTAINER 的容器(通过 "),t("code",[e._v("docker run --name CONTAINER")]),e._v(" 指定)并且在 Dockerfile 中,暴露了一个端口:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("EXPOSE 1337\n")])])]),t("p",[e._v("然后,我们创建另外一个名为 LINKED 的容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress\n")])])]),t("p",[e._v("然后 CONTAINER 暴露的端口和别名将会以如下的环境变量出现在 LINKED 中:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("$ALIAS_PORT_1337_TCP_PORT\n$ALIAS_PORT_1337_TCP_ADDR\n")])])]),t("p",[e._v("那么你便可以通过这种方式来连接它了。")]),e._v(" "),t("p",[e._v("使用 "),t("code",[e._v("docker rm --link")]),e._v(" 即可删除链接。")]),e._v(" "),t("p",[e._v("通常,Docker 容器(亦可理解为「服务」)之间的链接,是「服务发现」的一个子集。如果你打算在生产中大规模使用 Docker,这将是一个很大的问题。请参阅"),t("a",{attrs:{href:"https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Docker Ecosystem: Service Discovery and Distributed Configuration Stores"),t("OutboundLink")],1),e._v(" 获取更多信息。")]),e._v(" "),t("h2",{attrs:{id:"卷标-volumes-和挂载"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#卷标-volumes-和挂载"}},[e._v("#")]),e._v(" 卷标(Volumes)和挂载")]),e._v(" "),t("h3",{attrs:{id:"卷标"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#卷标"}},[e._v("#")]),e._v(" 卷标")]),e._v(" "),t("p",[e._v("Docker 的卷标 (volumes) 是 "),t("a",{attrs:{href:"https://docs.docker.com/engine/tutorials/dockervolumes/",target:"_blank",rel:"noopener noreferrer"}},[e._v("独立的文件系统"),t("OutboundLink")],1),e._v("。它们并非必须连接到特定的容器上。")]),e._v(" "),t("p",[t("code",[e._v("数据卷")]),e._v(" 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:")]),e._v(" "),t("ul",[t("li",[t("code",[e._v("数据卷")]),e._v(" 可以在容器之间共享和重用")]),e._v(" "),t("li",[e._v("对 "),t("code",[e._v("数据卷")]),e._v(" 的修改会立马生效")]),e._v(" "),t("li",[e._v("对 "),t("code",[e._v("数据卷")]),e._v(" 的更新,不会影响镜像")]),e._v(" "),t("li",[t("code",[e._v("数据卷")]),e._v(" 默认会一直存在,即使容器被删除")])]),e._v(" "),t("p",[e._v("卷标相关命令:")]),e._v(" "),t("ul",[t("li",[t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/volume_create/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker volume create")]),t("OutboundLink")],1),e._v(" - 创建卷标")])]),e._v(" "),t("li",[t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/volume_rm/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker volume rm")]),t("OutboundLink")],1),e._v(" - 删除卷标")])]),e._v(" "),t("li",[t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/volume_ls/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker volume ls")]),t("OutboundLink")],1),e._v(" - 查看卷标")])]),e._v(" "),t("li",[t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/volume_inspect/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker volume inspect")]),t("OutboundLink")],1),e._v(" - 查看数据卷的具体信息")])]),e._v(" "),t("li",[t("p",[t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/volume_prune/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker volume prune")]),t("OutboundLink")],1),e._v(" - 清理无主的数据卷")])])]),e._v(" "),t("p",[e._v("卷标在不能使用链接(只有 TCP/IP)的情况下非常有用。例如,如果你有两个 Docker 实例需要通讯并在文件系统上留下记录。")]),e._v(" "),t("p",[e._v("你可以一次性将其挂载到多个 docker 容器上,通过 "),t("code",[e._v("docker run --volumes-from")]),e._v("。")]),e._v(" "),t("p",[e._v("因为卷标是独立的文件系统,它们通常被用于存储各容器之间的瞬时状态。也就是说,你可以配置一个无状态临时容器,关掉之后,当你有第二个这种临时容器实例的时候,你可以从上一次保存的状态继续执行。")]),e._v(" "),t("p",[e._v("查看 "),t("a",{attrs:{href:"http://crosbymichael.com/advanced-docker-volumes.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("卷标进阶"),t("OutboundLink")],1),e._v(" 来获取更多细节。"),t("a",{attrs:{href:"http://container42.com/2014/11/03/docker-indepth-volumes/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Container42"),t("OutboundLink")],1),e._v(" 非常有用。")]),e._v(" "),t("p",[e._v("你可以 "),t("a",{attrs:{href:"https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume",target:"_blank",rel:"noopener noreferrer"}},[e._v("将宿主 MacOS 的文件夹映射为 Docker 卷标"),t("OutboundLink")],1),e._v(":")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -v /Users/wsargent/myapp/src:/src\n")])])]),t("p",[e._v("你也可以用远程 NFS 卷标,如果你觉得你 "),t("a",{attrs:{href:"https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume",target:"_blank",rel:"noopener noreferrer"}},[e._v("有足够勇气"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("还可以考虑运行一个纯数据容器,像 "),t("a",{attrs:{href:"http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/",target:"_blank",rel:"noopener noreferrer"}},[e._v("这里"),t("OutboundLink")],1),e._v(" 所说的那样,提供可移植数据。")]),e._v(" "),t("p",[e._v("记得,"),t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#%E5%B0%86%E6%96%87%E4%BB%B6%E6%8C%82%E8%BD%BD%E4%B8%BA%E5%8D%B7%E6%A0%87",target:"_blank",rel:"noopener noreferrer"}},[e._v("文件也可以被挂载为卷标"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h3",{attrs:{id:"挂载"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#挂载"}},[e._v("#")]),e._v(" 挂载")]),e._v(" "),t("p",[e._v("使用 "),t("code",[e._v("--mount")]),e._v(" 标记可以指定挂载一个本地主机的目录到容器中去。")]),e._v(" "),t("p",[e._v("在用 "),t("code",[e._v("docker run")]),e._v(" 命令的时候,使用 "),t("code",[e._v("--mount")]),e._v(" 标记来将 "),t("code",[e._v("数据卷")]),e._v(" 挂载到容器里。在一次 "),t("code",[e._v("docker run")]),e._v(" 中可以挂载多个 "),t("code",[e._v("数据卷")]),e._v("。")]),e._v(" "),t("h2",{attrs:{id:"最佳实践"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#最佳实践"}},[e._v("#")]),e._v(" 最佳实践")]),e._v(" "),t("p",[e._v("这里有一些最佳实践,以及争论焦点:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/",target:"_blank",rel:"noopener noreferrer"}},[e._v("The Rabbit Hole of Using Docker in Automated Tests"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://twitter.com/bridgetkromhout",target:"_blank",rel:"noopener noreferrer"}},[e._v("Bridget Kromhout"),t("OutboundLink")],1),e._v(" has a useful blog post on "),t("a",{attrs:{href:"http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("running Docker in production"),t("OutboundLink")],1),e._v(" at Dramafever.")]),e._v(" "),t("li",[e._v("There's also a best practices "),t("a",{attrs:{href:"http://developers.lyst.com/devops/2014/12/08/docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("blog post"),t("OutboundLink")],1),e._v(" from Lyst.")]),e._v(" "),t("li",[t("a",{attrs:{href:"https://engineering.salesforceiq.com/2013/11/05/a-docker-dev-environment-in-24-hours-part-2-of-2.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("A Docker Dev Environment in 24 Hours!"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Building a Development Environment With Docker"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container",target:"_blank",rel:"noopener noreferrer"}},[e._v("Discourse in a Docker Container"),t("OutboundLink")],1)])]),e._v(" "),t("h2",{attrs:{id:"安全-security"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安全-security"}},[e._v("#")]),e._v(" 安全(Security)")]),e._v(" "),t("p",[e._v("这节准备讨论一些关于 Docker 安全性的问题。Docker 官方文档 "),t("a",{attrs:{href:"https://docs.docker.com/articles/security/",target:"_blank",rel:"noopener noreferrer"}},[e._v("安全"),t("OutboundLink")],1),e._v(" 页面讲述了更多细节。")]),e._v(" "),t("p",[e._v("首先第一件事:Docker 是有 root 权限的。如果你在 "),t("code",[e._v("docker")]),e._v(" 组,那么你就有 "),t("a",{attrs:{href:"https://web.archive.org/web/20161226211755/http://reventlov.com/advisories/using-the-docker-command-to-root-the-host",target:"_blank",rel:"noopener noreferrer"}},[e._v("root 权限"),t("OutboundLink")],1),e._v("。如果你将 Docker 的 Unix Socket 暴露给容器,意味着你赋予了容器 "),t("a",{attrs:{href:"https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("宿主机 root 权限"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("Docker 不应当作为唯一的防御措施。你应当使其更加安全可靠。")]),e._v(" "),t("p",[e._v("为了更好地理解容器暴露了什么,可参阅由 "),t("a",{attrs:{href:"https://twitter.com/dyn___",target:"_blank",rel:"noopener noreferrer"}},[e._v("Aaron Grattafiori"),t("OutboundLink")],1),e._v(" 编写的 "),t("a",{attrs:{href:"https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf",target:"_blank",rel:"noopener noreferrer"}},[e._v("Understanding and Hardening Linux Containers"),t("OutboundLink")],1),e._v("。这是一个完整全面且包含大量链接和脚注的容器问题指南,介绍了许多有用的内容。即使你已经加固过容器,以下的安全提示依然十分有帮助,但并不能代替理解的过程。")]),e._v(" "),t("h3",{attrs:{id:"安全提示"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安全提示"}},[e._v("#")]),e._v(" 安全提示")]),e._v(" "),t("p",[e._v("为了最大的安全性,你应当考虑在虚拟机上运行 Docker。这是直接从 Docker 安全团队拿来的资料 -- "),t("a",{attrs:{href:"http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security",target:"_blank",rel:"noopener noreferrer"}},[e._v("slides"),t("OutboundLink")],1),e._v(" / "),t("a",{attrs:{href:"http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/",target:"_blank",rel:"noopener noreferrer"}},[e._v("notes"),t("OutboundLink")],1),e._v("。之后,可使用 AppArmor、seccomp、SELinux、grsec 等来 "),t("a",{attrs:{href:"http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/",target:"_blank",rel:"noopener noreferrer"}},[e._v("限制容器的权限"),t("OutboundLink")],1),e._v("。更多细节,请查阅 "),t("a",{attrs:{href:"https://blog.docker.com/2016/02/docker-engine-1-10-security/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 1.10 security features"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("Docker 镜像 ID 属于 "),t("a",{attrs:{href:"https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4",target:"_blank",rel:"noopener noreferrer"}},[e._v("敏感信息"),t("OutboundLink")],1),e._v(" 所以它不应该向外界公开。请将它们当作密码来对待。")]),e._v(" "),t("p",[e._v("阅读由 "),t("a",{attrs:{href:"https://github.com/konstruktoid",target:"_blank",rel:"noopener noreferrer"}},[e._v("Thomas Sjögren"),t("OutboundLink")],1),e._v(" 编写的 "),t("a",{attrs:{href:"https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Security Cheat Sheet"),t("OutboundLink")],1),e._v(":关于加固容器的不错的建议。")]),e._v(" "),t("p",[e._v("查看 "),t("a",{attrs:{href:"https://github.com/docker/docker-bench-security",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 安全测试脚本"),t("OutboundLink")],1),e._v(",下载 "),t("a",{attrs:{href:"https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/",target:"_blank",rel:"noopener noreferrer"}},[e._v("最佳实践白皮书"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("p",[e._v("你应当远离使用非稳定版本 grsecurity / pax 的内核,比如 "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Alpine_Linux",target:"_blank",rel:"noopener noreferrer"}},[e._v("Alpine Linux"),t("OutboundLink")],1),e._v("。如果在产品中用了 grsecurity,那么你应该考虑使用有 "),t("a",{attrs:{href:"https://grsecurity.net/business_support.php",target:"_blank",rel:"noopener noreferrer"}},[e._v("商业支持"),t("OutboundLink")],1),e._v(" 的 "),t("a",{attrs:{href:"https://grsecurity.net/announce.php",target:"_blank",rel:"noopener noreferrer"}},[e._v("稳定版本"),t("OutboundLink")],1),e._v(",就像你对待 RedHat 那样。虽然要 $200 每月,但对于你的运维预算来说不值一提。")]),e._v(" "),t("p",[e._v("从 Docker 1.11 开始,你可以轻松的限制在容器中可用的进程数,以防止 fork 炸弹。 这要求 Linux 内核 >= 4.3,并且要在内核配置中打开 CGROUP_PIDS=y。")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run --pids-limit=64\n")])])]),t("p",[e._v("同时,你也可以限制进程再获取新权限。该功能是 Linux 内核从 3.5 版本开始就拥有的。你可以从 "),t("a",{attrs:{href:"http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("这篇博客"),t("OutboundLink")],1),e._v(" 中阅读到更多关于这方面的内容。")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run --security-opt=no-new-privileges\n")])])]),t("p",[e._v("以下内容摘选自 "),t("a",{attrs:{href:"http://container-solutions.com/is-docker-safe-for-production/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Container Solutions"),t("OutboundLink")],1),e._v(" 的 "),t("a",{attrs:{href:"http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Security Cheat Sheet"),t("OutboundLink")],1),e._v("(PDF 版本,难以使用,故复制至此):")]),e._v(" "),t("p",[e._v("关闭内部进程通讯:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker -d --icc=false --iptables\n")])])]),t("p",[e._v("设置容器为只读:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run --read-only\n")])])]),t("p",[e._v("通过 hashsum 来验证卷标:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be\n")])])]),t("p",[e._v("设置卷标为只读:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run -v $(pwd)/secrets:/secrets:ro debian\n")])])]),t("p",[e._v("在 Dockerfile 中定义用户并以该用户运行,避免在容器中以 ROOT 身份操作:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("RUN groupadd -r user && useradd -r -g user user\nUSER user\n")])])]),t("h3",{attrs:{id:"用户命名空间-user-namespaces"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#用户命名空间-user-namespaces"}},[e._v("#")]),e._v(" 用户命名空间(User Namespaces)")]),e._v(" "),t("p",[e._v("还可以通过使用 "),t("a",{attrs:{href:"https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/",target:"_blank",rel:"noopener noreferrer"}},[e._v("用户命名空间"),t("OutboundLink")],1),e._v(" -- 自 1.10 版本起已内置,但默认并未启用。")]),e._v(" "),t("p",[e._v("要在 Ubuntu 15.10 中启用用户命名空间 (remap the userns),请 "),t("a",{attrs:{href:"https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/",target:"_blank",rel:"noopener noreferrer"}},[e._v("跟着这篇博客的例子"),t("OutboundLink")],1),e._v(" 来做。")]),e._v(" "),t("h3",{attrs:{id:"安全相关视频"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安全相关视频"}},[e._v("#")]),e._v(" 安全相关视频")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://youtu.be/04LOuMgNj9U",target:"_blank",rel:"noopener noreferrer"}},[e._v("Using Docker Safely"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://youtu.be/KmxOXmPhZbk",target:"_blank",rel:"noopener noreferrer"}},[e._v("Securing your applications using Docker"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://youtu.be/a9lE9Urr6AQ",target:"_blank",rel:"noopener noreferrer"}},[e._v("Container security: Do containers actually contain?"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://www.youtube.com/watch?v=iN6QbszB1R8",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linux Containers: Future or Fantasy?"),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"安全路线图"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安全路线图"}},[e._v("#")]),e._v(" 安全路线图")]),e._v(" "),t("p",[e._v("Docker 的路线图提到关于 "),t("a",{attrs:{href:"https://github.com/docker/docker/blob/master/ROADMAP.md#11-security",target:"_blank",rel:"noopener noreferrer"}},[e._v("seccomp 的支持"),t("OutboundLink")],1),e._v("。 一个名为 "),t("a",{attrs:{href:"https://github.com/jfrazelle/bane",target:"_blank",rel:"noopener noreferrer"}},[e._v("bane"),t("OutboundLink")],1),e._v(" 的 AppArmor 策略生成器正在实现 "),t("a",{attrs:{href:"https://github.com/docker/docker/issues/17142",target:"_blank",rel:"noopener noreferrer"}},[e._v("安全配置文件"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("h2",{attrs:{id:"小贴士"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#小贴士"}},[e._v("#")]),e._v(" 小贴士")]),e._v(" "),t("p",[e._v("链接:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes",target:"_blank",rel:"noopener noreferrer"}},[e._v("15 Docker Tips in 5 minutes"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://codefresh.io/blog/everyday-hacks-docker/",target:"_blank",rel:"noopener noreferrer"}},[e._v("CodeFresh Everyday Hacks Docker"),t("OutboundLink")],1)])]),e._v(" "),t("h3",{attrs:{id:"清理-2"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#清理-2"}},[e._v("#")]),e._v(" 清理")]),e._v(" "),t("p",[e._v("最新的 "),t("a",{attrs:{href:"https://github.com/docker/docker/pull/26108",target:"_blank",rel:"noopener noreferrer"}},[e._v("数据管理命令"),t("OutboundLink")],1),e._v(" 已在 Docker 1.13 实现:")]),e._v(" "),t("ul",[t("li",[t("code",[e._v("docker system prune")])]),e._v(" "),t("li",[t("code",[e._v("docker volume prune")])]),e._v(" "),t("li",[t("code",[e._v("docker network prune")])]),e._v(" "),t("li",[t("code",[e._v("docker container prune")])]),e._v(" "),t("li",[t("code",[e._v("docker image prune")])])]),e._v(" "),t("h3",{attrs:{id:"df-命令"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#df-命令"}},[e._v("#")]),e._v(" df 命令")]),e._v(" "),t("p",[t("code",[e._v("docker system df")]),e._v(" 将显示当前 Docker 各部分占用的磁盘空间。")]),e._v(" "),t("h3",{attrs:{id:"heredoc-声明-docker-容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#heredoc-声明-docker-容器"}},[e._v("#")]),e._v(" Heredoc 声明 Docker 容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker build -t htop - << EOF\nFROM alpine\nRUN apk --no-cache add htop\nEOF\n")])])]),t("h3",{attrs:{id:"最近一次的容器-id"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#最近一次的容器-id"}},[e._v("#")]),e._v(" 最近一次的容器 ID")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("alias dl='docker ps -l -q'\ndocker run ubuntu echo hello world\ndocker commit $(dl) helloworld\n")])])]),t("h3",{attrs:{id:"带命令的提交-需要-dockerfile"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#带命令的提交-需要-dockerfile"}},[e._v("#")]),e._v(" 带命令的提交(需要 Dockerfile)")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v('docker commit -run=\'{"Cmd":["postgres", "-too -many -opts"]}\' $(dl) postgres\n')])])]),t("h3",{attrs:{id:"获取-ip-地址"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#获取-ip-地址"}},[e._v("#")]),e._v(" 获取 IP 地址")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker inspect $(dl) | grep -wm1 IPAddress | cut -d '\"' -f 4\n")])])]),t("p",[e._v("或使用 "),t("a",{attrs:{href:"https://stedolan.github.io/jq/",target:"_blank",rel:"noopener noreferrer"}},[e._v("jq"),t("OutboundLink")],1),e._v(":")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress'\n")])])]),t("p",[e._v("或使用 "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/inspect",target:"_blank",rel:"noopener noreferrer"}},[e._v("go 模板"),t("OutboundLink")],1),e._v(":")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker inspect -f '{{ .NetworkSettings.IPAddress }}' \n")])])]),t("p",[e._v("或在通过 Dockerfile 构建镜像时,通过构建参数 (build argument) 传入:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("DOCKER_HOST_IP=`ifconfig | grep -E \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1`\necho DOCKER_HOST_IP = $DOCKER_HOST_IP\ndocker build \\\n --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP\n -t sometag \\\n some-directory/\n")])])]),t("h3",{attrs:{id:"获取端口映射"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#获取端口映射"}},[e._v("#")]),e._v(" 获取端口映射")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' \n")])])]),t("h3",{attrs:{id:"通过正则匹配容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#通过正则匹配容器"}},[e._v("#")]),e._v(" 通过正则匹配容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v('for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done`\n')])])]),t("h3",{attrs:{id:"获取环境变量配置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#获取环境变量配置"}},[e._v("#")]),e._v(" 获取环境变量配置")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker run --rm ubuntu env\n")])])]),t("h3",{attrs:{id:"强行终止运行中的容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#强行终止运行中的容器"}},[e._v("#")]),e._v(" 强行终止运行中的容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker kill $(docker ps -q)\n")])])]),t("h3",{attrs:{id:"删除所有容器-强行删除-无论容器运行或停止"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除所有容器-强行删除-无论容器运行或停止"}},[e._v("#")]),e._v(" 删除所有容器(强行删除!无论容器运行或停止)")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rm -f $(docker ps -qa)\n")])])]),t("h3",{attrs:{id:"删除旧容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除旧容器"}},[e._v("#")]),e._v(" 删除旧容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm\n")])])]),t("h3",{attrs:{id:"删除已停止的容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除已停止的容器"}},[e._v("#")]),e._v(" 删除已停止的容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rm -v `docker ps -a -q -f status=exited`\n")])])]),t("h3",{attrs:{id:"停止并删除容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#停止并删除容器"}},[e._v("#")]),e._v(" 停止并删除容器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq)\n")])])]),t("h3",{attrs:{id:"删除无用-dangling-的镜像"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除无用-dangling-的镜像"}},[e._v("#")]),e._v(" 删除无用 (dangling) 的镜像")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rmi $(docker images -q -f dangling=true)\n")])])]),t("h3",{attrs:{id:"删除所有镜像"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除所有镜像"}},[e._v("#")]),e._v(" 删除所有镜像")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rmi $(docker images -q)\n")])])]),t("h3",{attrs:{id:"删除无用-dangling-的卷标"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除无用-dangling-的卷标"}},[e._v("#")]),e._v(" 删除无用 (dangling) 的卷标")]),e._v(" "),t("p",[e._v("Docker 1.9 版本起:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker volume rm $(docker volume ls -q -f dangling=true)\n")])])]),t("p",[e._v("1.9.0 中,参数 "),t("code",[e._v("dangling=false")]),e._v(" 居然 "),t("em",[e._v("没")]),e._v(" 用 - 它会被忽略然后列出所有的卷标。")]),e._v(" "),t("h3",{attrs:{id:"查看镜像依赖"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#查看镜像依赖"}},[e._v("#")]),e._v(" 查看镜像依赖")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker images -viz | dot -Tpng -o docker.png\n")])])]),t("h3",{attrs:{id:"docker-容器瘦身"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-容器瘦身"}},[e._v("#")]),e._v(" Docker 容器瘦身")]),e._v(" "),t("ul",[t("li",[e._v("在某层 (RUN layer) 清理 APT")])]),e._v(" "),t("p",[e._v("这应当和其他 apt 命令在同一层中完成。 否则,前面的层将会保持原有信息,而你的镜像则依旧臃肿。")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("RUN {apt commands} \\\n && apt-get clean \\\n && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*\n")])])]),t("ul",[t("li",[e._v("压缩镜像")])]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("ID=$(docker run -d image-name /bin/bash)\ndocker export $ID | docker import – flat-image-name\n")])])]),t("ul",[t("li",[e._v("备份")])]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("ID=$(docker run -d image-name /bin/bash)\n(docker export $ID | gzip -c > image.tgz)\ngzip -dc image.tgz | docker import - flat-image-name\n")])])]),t("h3",{attrs:{id:"监视运行中容器的系统资源利用率"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#监视运行中容器的系统资源利用率"}},[e._v("#")]),e._v(" 监视运行中容器的系统资源利用率")]),e._v(" "),t("p",[e._v("检查某个容器的 CPU、内存以及网络 I/O 使用情况,你可以:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker stats \n")])])]),t("p",[e._v("按 ID 列出所有容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker stats $(docker ps -q)\n")])])]),t("p",[e._v("按名称列出所有容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker stats $(docker ps --format '{{.Names}}')\n")])])]),t("p",[e._v("按指定镜像名称列出所有容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker ps -a -f ancestor=ubuntu\n")])])]),t("p",[e._v("删除所有未标签命名 (untagged) 的容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rmi $(docker images | grep “^” | awk '{split($0,a,\" \"); print a[3]}')\n")])])]),t("p",[e._v("通过正则匹配删除指定容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f\n")])])]),t("p",[e._v("删除所有已退出 (exited) 的容器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }')\n")])])]),t("h3",{attrs:{id:"将文件挂载为卷标"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#将文件挂载为卷标"}},[e._v("#")]),e._v(" 将文件挂载为卷标")]),e._v(" "),t("p",[e._v("文件也可以被挂载为卷标。例如你可以仅仅注入单个配置文件:")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 从容器复制文件")]),e._v("\ndocker run --rm httpd "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" /usr/local/apache2/conf/httpd.conf "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" httpd.conf\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 编辑文件")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("vim")]),e._v(" httpd.conf\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 挂载修改后的配置启动容器")]),e._v("\ndocker run --rm -ti -v "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"'),t("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("$PWD")]),e._v('/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro"')]),e._v(" -p "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"80:80"')]),e._v(" httpd\n")])])]),t("h2",{attrs:{id:"参考资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[e._v("#")]),e._v(" 参考资料")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Cheat Sheet"),t("OutboundLink")],1)])])])}),[],!1,null,null,null);r.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/13.857dcc43.js b/assets/js/13.857dcc43.js new file mode 100644 index 0000000..ae0b829 --- /dev/null +++ b/assets/js/13.857dcc43.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{401:function(t,s,a){"use strict";a.r(s);var e=a(15),r=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"docker-compose"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#docker-compose"}},[t._v("#")]),t._v(" Docker Compose")]),t._v(" "),a("blockquote",[a("p",[a("a",{attrs:{href:"https://github.com/docker/compose",target:"_blank",rel:"noopener noreferrer"}},[t._v("compose"),a("OutboundLink")],1),t._v(" 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 "),a("code",[t._v("OpenStack")]),t._v(" 中的 "),a("code",[t._v("Heat")]),t._v(" 十分类似。")])]),t._v(" "),a("h2",{attrs:{id:"一、compose-简介"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#一、compose-简介"}},[t._v("#")]),t._v(" 一、Compose 简介")]),t._v(" "),a("p",[a("strong",[a("code",[t._v("Compose")]),t._v(" 的定位是:定义和运行多个 Docker 容器的应用")]),t._v("。 使用一个 "),a("code",[t._v("Dockerfile")]),t._v(" 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。")]),t._v(" "),a("p",[a("code",[t._v("Compose")]),t._v(" 恰好满足了这样的需求。它允许用户通过一个单独的 "),a("code",[t._v("docker-compose.yml")]),t._v(" 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。")]),t._v(" "),a("p",[a("code",[t._v("Compose")]),t._v(" 中有两个重要的概念:")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("服务 ("),a("code",[t._v("service")]),t._v(")")]),t._v(":一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。")]),t._v(" "),a("li",[a("strong",[t._v("项目 ("),a("code",[t._v("project")]),t._v(")")]),t._v(":由一组关联的应用容器组成的一个完整业务单元,在 "),a("code",[t._v("docker-compose.yml")]),t._v(" 文件中定义。")])]),t._v(" "),a("p",[a("code",[t._v("Compose")]),t._v(" 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。")]),t._v(" "),a("h2",{attrs:{id:"二、安装卸载"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#二、安装卸载"}},[t._v("#")]),t._v(" 二、安装卸载")]),t._v(" "),a("p",[a("code",[t._v("Compose")]),t._v(" 支持 Linux、macOS、Windows10 三大平台。")]),t._v(" "),a("p",[t._v("Linux 安装方式:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-"),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("uname")]),t._v(" -s"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")])]),t._v("-"),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("uname")]),t._v(" -m"),a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" /usr/local/bin/docker-compose\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" +x /usr/local/bin/docker-compose\n")])])]),a("blockquote",[a("p",[t._v("🔔 详情请参考:"),a("a",{attrs:{href:"https://docs.docker.com/compose/install/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Install Docker Compose"),a("OutboundLink")],1)])]),t._v(" "),a("h2",{attrs:{id:"三、快速入门"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#三、快速入门"}},[t._v("#")]),t._v(" 三、快速入门")]),t._v(" "),a("h3",{attrs:{id:"web-应用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#web-应用"}},[t._v("#")]),t._v(" web 应用")]),t._v(" "),a("p",[t._v("新建文件夹,在该目录中编写 "),a("code",[t._v("app.py")]),t._v(" 文件")]),t._v(" "),a("div",{staticClass:"language-python extra-class"},[a("pre",{pre:!0,attrs:{class:"language-python"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" flask "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Flask\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("from")]),t._v(" redis "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("import")]),t._v(" Redis\n\napp "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Flask"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("__name__"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nredis "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" Redis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("host"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'redis'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" port"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6379")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token decorator annotation punctuation"}},[t._v("@app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("route")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("def")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("hello")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" redis"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("incr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'hits'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Hello World! 该页面已被访问 {} 次。\\n'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("format")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" __name__ "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"__main__"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n app"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("run"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("host"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0.0.0.0"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" debug"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("True")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("h3",{attrs:{id:"dockerfile"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#dockerfile"}},[t._v("#")]),t._v(" Dockerfile")]),t._v(" "),a("p",[t._v("编写 "),a("code",[t._v("Dockerfile")]),t._v(" 文件,内容为")]),t._v(" "),a("div",{staticClass:"language-docker extra-class"},[a("pre",{pre:!0,attrs:{class:"language-docker"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" python"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("3.6"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("alpine\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" . /code\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WORKDIR")]),t._v(" /code\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" pip install redis flask\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"python"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"app.py"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),a("h3",{attrs:{id:"docker-compose-yml"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#docker-compose-yml"}},[t._v("#")]),t._v(" docker-compose.yml")]),t._v(" "),a("p",[t._v("编写 "),a("code",[t._v("docker-compose.yml")]),t._v(" 文件,这个是 Compose 使用的主模板文件。")]),t._v(" "),a("div",{staticClass:"language-yaml extra-class"},[a("pre",{pre:!0,attrs:{class:"language-yaml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("version")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'3'")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("services")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("web")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("build")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" .\n "),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("ports")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"5000:5000"')]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("redis")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("image")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"redis:alpine"')]),t._v("\n")])])]),a("h3",{attrs:{id:"运行-compose-项目"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#运行-compose-项目"}},[t._v("#")]),t._v(" 运行 compose 项目")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("$ docker-compose up\n")])])]),a("p",[t._v("此时访问本地 "),a("code",[t._v("5000")]),t._v(" 端口,每次刷新页面,计数就会加 1。")]),t._v(" "),a("h2",{attrs:{id:"四、命令"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#四、命令"}},[t._v("#")]),t._v(" 四、命令")]),t._v(" "),a("blockquote",[a("p",[t._v("🔔 请参考:")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://docs.docker.com/compose/reference/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Compose 官方命令说明文档"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/compose/commands.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Compose 命令说明中文文档"),a("OutboundLink")],1)])])]),t._v(" "),a("h2",{attrs:{id:"五、模板文件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#五、模板文件"}},[t._v("#")]),t._v(" 五、模板文件")]),t._v(" "),a("blockquote",[a("p",[a("code",[t._v("docker-compose.yml")]),t._v(" 文件是 Docker Compose 的模板文件,其作用类似于 Dockerfile 和 Docker。")])]),t._v(" "),a("p",[a("a",{attrs:{href:"https://docs.docker.com/compose/env-file/",target:"_blank",rel:"noopener noreferrer"}},[t._v("docker-compose.yml 支持的默认环境变量官方文档"),a("OutboundLink")],1)]),t._v(" "),a("h2",{attrs:{id:"参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("官方")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/docker/compose",target:"_blank",rel:"noopener noreferrer"}},[t._v("Docker Compose Github"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://docs.docker.com/compose/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Docker Compose 官方文档"),a("OutboundLink")],1)])])]),t._v(" "),a("li",[a("strong",[t._v("教程")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/compose/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Docker — 从入门到实践 - Docker Compose 项目"),a("OutboundLink")],1)])])])])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/14.5a603a55.js b/assets/js/14.5a603a55.js new file mode 100644 index 0000000..6da0481 --- /dev/null +++ b/assets/js/14.5a603a55.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{402:function(t,e,s){"use strict";s.r(e);var a=s(15),n=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"dockerfile-最佳实践"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dockerfile-最佳实践"}},[t._v("#")]),t._v(" Dockerfile 最佳实践")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"#%E4%B8%80dockerfile-%E6%8C%87%E4%BB%A4"}},[t._v("一、Dockerfile 指令")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"#from%E6%8C%87%E5%AE%9A%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F"}},[t._v("FROM(指定基础镜像)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#run%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4"}},[t._v("RUN(执行命令)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#copy%E5%A4%8D%E5%88%B6%E6%96%87%E4%BB%B6"}},[t._v("COPY(复制文件)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#add%E6%9B%B4%E9%AB%98%E7%BA%A7%E7%9A%84%E5%A4%8D%E5%88%B6%E6%96%87%E4%BB%B6"}},[t._v("ADD(更高级的复制文件)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#cmd%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%91%BD%E4%BB%A4"}},[t._v("CMD(容器启动命令)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#entrypoint%E5%85%A5%E5%8F%A3%E7%82%B9"}},[t._v("ENTRYPOINT(入口点)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#env%E8%AE%BE%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F"}},[t._v("ENV(设置环境变量)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#arg%E6%9E%84%E5%BB%BA%E5%8F%82%E6%95%B0"}},[t._v("ARG(构建参数)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#volume%E5%AE%9A%E4%B9%89%E5%8C%BF%E5%90%8D%E5%8D%B7"}},[t._v("VOLUME(定义匿名卷)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#expose%E6%9A%B4%E9%9C%B2%E7%AB%AF%E5%8F%A3"}},[t._v("EXPOSE(暴露端口)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#workdir%E6%8C%87%E5%AE%9A%E5%B7%A5%E4%BD%9C%E7%9B%AE%E5%BD%95"}},[t._v("WORKDIR(指定工作目录)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#user%E6%8C%87%E5%AE%9A%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7"}},[t._v("USER(指定当前用户)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#healthcheck%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5"}},[t._v("HEALTHCHECK(健康检查)")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#onbuild%E4%B8%BA%E4%BB%96%E4%BA%BA%E4%BD%9C%E5%AB%81%E8%A1%A3%E8%A3%B3"}},[t._v("ONBUILD(为他人作嫁衣裳)")])])])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[t._v("参考资料")])])]),t._v(" "),s("h2",{attrs:{id:"一、dockerfile-简介"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#一、dockerfile-简介"}},[t._v("#")]),t._v(" 一、Dockerfile 简介")]),t._v(" "),s("p",[t._v("Docker 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。")]),t._v(" "),s("p",[t._v("Dockerfile 是一个文本文件,其内包含了一条条的 "),s("strong",[t._v("指令(Instruction)")]),t._v(",每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。")]),t._v(" "),s("h3",{attrs:{id:"使用-dockerfile-构建镜像"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#使用-dockerfile-构建镜像"}},[t._v("#")]),t._v(" 使用 Dockerfile 构建镜像")]),t._v(" "),s("h2",{attrs:{id:"二、dockerfile-指令详解"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二、dockerfile-指令详解"}},[t._v("#")]),t._v(" 二、Dockerfile 指令详解")]),t._v(" "),s("h3",{attrs:{id:"from-指定基础镜像"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#from-指定基础镜像"}},[t._v("#")]),t._v(" FROM(指定基础镜像)")]),t._v(" "),s("blockquote",[s("p",[t._v("作用:"),s("strong",[s("code",[t._v("FROM")]),t._v(" 指令用于指定基础镜像")]),t._v("。")])]),t._v(" "),s("p",[t._v("所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 "),s("code",[t._v("nginx")]),t._v(" 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 "),s("code",[t._v("FROM")]),t._v(" 就是指定"),s("strong",[t._v("基础镜像")]),t._v(",因此一个 "),s("code",[t._v("Dockerfile")]),t._v(" 中 "),s("code",[t._v("FROM")]),t._v(" 是必备的指令,并且必须是第一条指令。")]),t._v(" "),s("p",[t._v("在 "),s("a",{attrs:{href:"https://store.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Docker Store"),s("OutboundLink")],1),t._v(" 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 "),s("a",{attrs:{href:"https://store.docker.com/images/nginx/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("nginx")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/redis/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("redis")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/mongo/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("mongo")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/mysql/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("mysql")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/httpd/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("httpd")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/php/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("php")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/tomcat/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("tomcat")]),s("OutboundLink")],1),t._v(" 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 "),s("a",{attrs:{href:"https://store.docker.com/images/node",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("node")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/openjdk/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("openjdk")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/python/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("python")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/ruby/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("ruby")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/golang/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("golang")]),s("OutboundLink")],1),t._v(" 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。")]),t._v(" "),s("p",[t._v("如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 "),s("a",{attrs:{href:"https://store.docker.com/images/ubuntu/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("ubuntu")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/debian/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("debian")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/centos/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("centos")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/fedora/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("fedora")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://store.docker.com/images/alpine/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("alpine")]),s("OutboundLink")],1),t._v(" 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。")]),t._v(" "),s("p",[t._v("除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 "),s("code",[t._v("scratch")]),t._v("。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" scratch\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n")])])]),s("p",[t._v("如果你以 "),s("code",[t._v("scratch")]),t._v(" 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。")]),t._v(" "),s("p",[t._v("不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 "),s("a",{attrs:{href:"https://hub.docker.com/_/swarm/",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("swarm")]),s("OutboundLink")],1),t._v("、"),s("a",{attrs:{href:"https://quay.io/repository/coreos/etcd",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("coreos/etcd")]),s("OutboundLink")],1),t._v("。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 "),s("code",[t._v("FROM scratch")]),t._v(" 会让镜像体积更加小巧。使用 "),s("a",{attrs:{href:"https://golang.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Go 语言"),s("OutboundLink")],1),t._v(" 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。")]),t._v(" "),s("h3",{attrs:{id:"run-执行命令"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#run-执行命令"}},[t._v("#")]),t._v(" RUN(执行命令)")]),t._v(" "),s("blockquote",[s("p",[s("strong",[s("code",[t._v("RUN")]),t._v(" 指令是用来执行命令行命令的")]),t._v("。由于命令行的强大能力,"),s("code",[t._v("RUN")]),t._v(" 指令在定制镜像时是最常用的指令之一。其格式有两种:")]),t._v(" "),s("ul",[s("li",[s("em",[t._v("shell")]),t._v(" 格式:"),s("code",[t._v("RUN <命令>")]),t._v(",就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 "),s("code",[t._v("RUN")]),t._v(" 指令就是这种格式。")])]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'

Hello, Docker!

'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(" /usr/share/nginx/html/index.html\n")])])]),s("ul",[s("li",[s("em",[t._v("exec")]),t._v(" 格式:"),s("code",[t._v('RUN ["可执行文件", "参数1", "参数2"]')]),t._v(",这更像是函数调用中的格式。")])])]),t._v(" "),s("p",[t._v("既然 "),s("code",[t._v("RUN")]),t._v(" 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如这样:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" debian"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("jessie\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get update\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y gcc libc6"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("dev make\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" wget "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("O redis.tar.gz "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"http://download.redis.io/releases/redis-3.2.5.tar.gz"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" mkdir "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("p /usr/src/redis\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" tar "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("xzf redis.tar.gz "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("strip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("components=1\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" make "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" make "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis install\n")])])]),s("p",[t._v("之前说过,Dockerfile 中每一个指令都会建立一层,"),s("code",[t._v("RUN")]),t._v(" 也不例外。每一个 "),s("code",[t._v("RUN")]),t._v(" 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,"),s("code",[t._v("commit")]),t._v(" 这一层的修改,构成新的镜像。")]),t._v(" "),s("p",[t._v("而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。")]),t._v(" "),s("p",[s("em",[t._v("Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。")])]),t._v(" "),s("p",[t._v("上面的 "),s("code",[t._v("Dockerfile")]),t._v(" 正确的写法应该是这样:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" debian"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("jessie\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" buildDeps="),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'gcc libc6-dev make'")]),t._v(" \\\n && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get update \\\n && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y $buildDeps \\\n && wget "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("O redis.tar.gz "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"http://download.redis.io/releases/redis-3.2.5.tar.gz"')]),t._v(" \\\n && mkdir "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("p /usr/src/redis \\\n && tar "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("xzf redis.tar.gz "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("strip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("components=1 \\\n && make "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis \\\n && make "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/src/redis install \\\n && rm "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rf /var/lib/apt/lists/* \\\n && rm redis.tar.gz \\\n && rm "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("r /usr/src/redis \\\n && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get purge "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("auto"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("remove $buildDeps\n")])])]),s("p",[t._v("首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 "),s("code",[t._v("RUN")]),t._v(" 对一一对应不同的命令,而是仅仅使用一个 "),s("code",[t._v("RUN")]),t._v(" 指令,并使用 "),s("code",[t._v("&&")]),t._v(" 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。")]),t._v(" "),s("p",[t._v("并且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 "),s("code",[t._v("\\")]),t._v(" 的命令换行方式,以及行首 "),s("code",[t._v("#")]),t._v(" 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。")]),t._v(" "),s("p",[t._v("此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了 "),s("code",[t._v("apt")]),t._v(" 缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。")]),t._v(" "),s("p",[t._v("很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。")]),t._v(" "),s("h3",{attrs:{id:"copy-复制文件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#copy-复制文件"}},[t._v("#")]),t._v(" COPY(复制文件)")]),t._v(" "),s("blockquote",[s("p",[s("strong",[s("code",[t._v("COPY")]),t._v(" 指令将从构建上下文目录中 "),s("code",[t._v("<源路径>")]),t._v(" 的文件/目录复制到新的一层的镜像内的 "),s("code",[t._v("<目标路径>")]),t._v(" 位置。")])])]),t._v(" "),s("p",[t._v("格式:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("COPY [--chown=:] <源路径>... <目标路径>")])]),t._v(" "),s("li",[s("code",[t._v('COPY [--chown=:] ["<源路径1>",... "<目标路径>"]')])])]),t._v(" "),s("p",[t._v("示例:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" package.json /usr/src/app/\n")])])]),s("p",[s("code",[t._v("<源路径>")]),t._v(" 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 "),s("a",{attrs:{href:"https://golang.org/pkg/path/filepath/#Match",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("filepath.Match")]),s("OutboundLink")],1),t._v(" 规则,如:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" hom* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" hom"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("?")]),t._v(".txt /mydir/\n")])])]),s("p",[s("code",[t._v("<目标路径>")]),t._v(" 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 "),s("code",[t._v("WORKDIR")]),t._v(" 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。")]),t._v(" "),s("p",[t._v("此外,还需要注意一点,使用 "),s("code",[t._v("COPY")]),t._v(" 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。")]),t._v(" "),s("p",[t._v("在使用该指令的时候还可以加上 "),s("code",[t._v("--chown=:")]),t._v(" 选项来改变文件的所属用户及所属组。")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=55"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("mygroup files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=bin files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=1 files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=10"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("11 files* /mydir/\n")])])]),s("h3",{attrs:{id:"add-更高级的复制文件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#add-更高级的复制文件"}},[t._v("#")]),t._v(" ADD(更高级的复制文件)")]),t._v(" "),s("blockquote",[s("p",[s("code",[t._v("ADD")]),t._v(" 指令和 "),s("code",[t._v("COPY")]),t._v(" 的格式和性质基本一致。但是在 "),s("code",[t._v("COPY")]),t._v(" 基础上增加了一些功能。")]),t._v(" "),s("p",[t._v("比如 "),s("code",[t._v("<源路径>")]),t._v(" 可以是一个 "),s("code",[t._v("URL")]),t._v(",这种情况下,Docker 引擎会试图去下载这个链接的文件放到 "),s("code",[t._v("<目标路径>")]),t._v("去。下载后的文件权限自动设置为 "),s("code",[t._v("600")]),t._v(",如果这并不是想要的权限,那么还需要增加额外的一层 "),s("code",[t._v("RUN")]),t._v(" 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 "),s("code",[t._v("RUN")]),t._v(" 指令进行解压缩。所以不如直接使用 "),s("code",[t._v("RUN")]),t._v(" 指令,然后使用 "),s("code",[t._v("wget")]),t._v(" 或者 "),s("code",[t._v("curl")]),t._v(" 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。")]),t._v(" "),s("p",[t._v("如果 "),s("code",[t._v("<源路径>")]),t._v(" 为一个 "),s("code",[t._v("tar")]),t._v(" 压缩文件的话,压缩格式为 "),s("code",[t._v("gzip")]),t._v(", "),s("code",[t._v("bzip2")]),t._v(" 以及 "),s("code",[t._v("xz")]),t._v(" 的情况下,"),s("code",[t._v("ADD")]),t._v(" 指令将会自动解压缩这个压缩文件到 "),s("code",[t._v("<目标路径>")]),t._v(" 去。")])]),t._v(" "),s("p",[t._v("在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 "),s("code",[t._v("ubuntu")]),t._v(" 中:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" scratch\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" ubuntu"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("xenial"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("core"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("cloudimg"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("amd64"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("root.tar.gz /\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n")])])]),s("p",[t._v("但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 "),s("code",[t._v("ADD")]),t._v(" 命令了。")]),t._v(" "),s("p",[t._v("在 Docker 官方的 "),s("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/appendix/best_practices.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Dockerfile 最佳实践文档"),s("OutboundLink")],1),t._v(" 中要求,尽可能的使用 "),s("code",[t._v("COPY")]),t._v(",因为 "),s("code",[t._v("COPY")]),t._v(" 的语义很明确,就是复制文件而已,而 "),s("code",[t._v("ADD")]),t._v(" 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 "),s("code",[t._v("ADD")]),t._v(" 的场合,就是所提及的需要自动解压缩的场合。")]),t._v(" "),s("p",[t._v("另外需要注意的是,"),s("code",[t._v("ADD")]),t._v(" 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。")]),t._v(" "),s("p",[t._v("因此在 "),s("code",[t._v("COPY")]),t._v(" 和 "),s("code",[t._v("ADD")]),t._v(" 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 "),s("code",[t._v("COPY")]),t._v(" 指令,仅在需要自动解压缩的场合使用 "),s("code",[t._v("ADD")]),t._v("。")]),t._v(" "),s("p",[t._v("在使用该指令的时候还可以加上 "),s("code",[t._v("--chown=:")]),t._v(" 选项来改变文件的所属用户及所属组。")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=55"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("mygroup files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=bin files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=1 files* /mydir/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ADD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("chown=10"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("11 files* /mydir/\n")])])]),s("h3",{attrs:{id:"cmd-容器启动命令"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#cmd-容器启动命令"}},[t._v("#")]),t._v(" CMD(容器启动命令)")]),t._v(" "),s("blockquote",[s("p",[t._v("之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。"),s("code",[t._v("CMD")]),t._v(" 指令就是用于指定默认的容器主进程的启动命令的。")])]),t._v(" "),s("p",[s("code",[t._v("CMD")]),t._v(" 指令的格式和 "),s("code",[t._v("RUN")]),t._v(" 相似,也是两种格式:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("shell")]),t._v(" 格式:"),s("code",[t._v("CMD <命令>")])]),t._v(" "),s("li",[s("code",[t._v("exec")]),t._v(" 格式:"),s("code",[t._v('CMD ["可执行文件", "参数1", "参数2"...]')])]),t._v(" "),s("li",[t._v("参数列表格式:"),s("code",[t._v('CMD ["参数1", "参数2"...]')]),t._v("。在指定了 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 指令后,用 "),s("code",[t._v("CMD")]),t._v(" 指定具体的参数。")])]),t._v(" "),s("p",[t._v("在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,"),s("code",[t._v("ubuntu")]),t._v(" 镜像默认的 "),s("code",[t._v("CMD")]),t._v(" 是 "),s("code",[t._v("/bin/bash")]),t._v(",如果我们直接 "),s("code",[t._v("docker run -it ubuntu")]),t._v(" 的话,会直接进入 "),s("code",[t._v("bash")]),t._v("。我们也可以在运行时指定运行别的命令,如 "),s("code",[t._v("docker run -it ubuntu cat /etc/os-release")]),t._v("。这就是用 "),s("code",[t._v("cat /etc/os-release")]),t._v(" 命令替换了默认的 "),s("code",[t._v("/bin/bash")]),t._v(" 命令了,输出了系统版本信息。")]),t._v(" "),s("p",[t._v("在指令格式上,一般推荐使用 "),s("code",[t._v("exec")]),t._v(" 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 "),s("code",[t._v('"')]),t._v(",而不要使用单引号。")]),t._v(" "),s("p",[t._v("如果使用 "),s("code",[t._v("shell")]),t._v(" 格式的话,实际的命令会被包装为 "),s("code",[t._v("sh -c")]),t._v(" 的参数的形式进行执行。比如:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" echo $HOME\n")])])]),s("p",[t._v("在实际执行中,会将其变更为:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"sh"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"-c"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"echo $HOME"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。")]),t._v(" "),s("p",[t._v("提到 "),s("code",[t._v("CMD")]),t._v(" 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。")]),t._v(" "),s("p",[t._v("Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。")]),t._v(" "),s("p",[t._v("一些初学者将 "),s("code",[t._v("CMD")]),t._v(" 写为:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" service nginx start\n")])])]),s("p",[t._v("然后发现容器执行后就立即退出了。甚至在容器内去使用 "),s("code",[t._v("systemctl")]),t._v(" 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。")]),t._v(" "),s("p",[t._v("对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。")]),t._v(" "),s("p",[t._v("而使用 "),s("code",[t._v("service nginx start")]),t._v(" 命令,则是希望 upstart 来以后台守护进程形式启动 "),s("code",[t._v("nginx")]),t._v(" 服务。而刚才说了 "),s("code",[t._v("CMD service nginx start")]),t._v(" 会被理解为 "),s("code",[t._v('CMD [ "sh", "-c", "service nginx start"]')]),t._v(",因此主进程实际上是 "),s("code",[t._v("sh")]),t._v("。那么当 "),s("code",[t._v("service nginx start")]),t._v(" 命令结束后,"),s("code",[t._v("sh")]),t._v(" 也就结束了,"),s("code",[t._v("sh")]),t._v(" 作为主进程退出了,自然就会令容器退出。")]),t._v(" "),s("p",[t._v("正确的做法是直接执行 "),s("code",[t._v("nginx")]),t._v(" 可执行文件,并且要求以前台形式运行。比如:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"nginx"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"-g"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"daemon off;"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("h3",{attrs:{id:"entrypoint-入口点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#entrypoint-入口点"}},[t._v("#")]),t._v(" ENTRYPOINT(入口点)")]),t._v(" "),s("p",[s("code",[t._v("ENTRYPOINT")]),t._v(" 的格式和 "),s("code",[t._v("RUN")]),t._v(" 指令格式一样,分为 "),s("code",[t._v("exec")]),t._v(" 格式和 "),s("code",[t._v("shell")]),t._v(" 格式。")]),t._v(" "),s("p",[s("code",[t._v("ENTRYPOINT")]),t._v(" 的目的和 "),s("code",[t._v("CMD")]),t._v(" 一样,都是在指定容器启动程序及参数。"),s("code",[t._v("ENTRYPOINT")]),t._v(" 在运行时也可以替代,不过比 "),s("code",[t._v("CMD")]),t._v(" 要略显繁琐,需要通过 "),s("code",[t._v("docker run")]),t._v(" 的参数 "),s("code",[t._v("--entrypoint")]),t._v(" 来指定。")]),t._v(" "),s("p",[t._v("当指定了 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 后,"),s("code",[t._v("CMD")]),t._v(" 的含义就发生了改变,不再是直接的运行其命令,而是将 "),s("code",[t._v("CMD")]),t._v(" 的内容作为参数传给 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 指令,换句话说实际执行时,将变为:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ENTRYPOINT"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),t._v("\n")])])]),s("p",[t._v("那么有了 "),s("code",[t._v("CMD")]),t._v(" 后,为什么还要有 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 呢?这种 "),s("code",[t._v(' ""')]),t._v(" 有什么好处么?让我们来看几个场景。")]),t._v(" "),s("h4",{attrs:{id:"场景一-让镜像变成像命令一样使用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#场景一-让镜像变成像命令一样使用"}},[t._v("#")]),t._v(" 场景一:让镜像变成像命令一样使用")]),t._v(" "),s("p",[t._v("假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 "),s("code",[t._v("CMD")]),t._v(" 来实现:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" ubuntu"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("18.04\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get update \\\n && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y curl \\\n && rm "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rf /var/lib/apt/lists/*\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"curl"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"-s"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://ip.cn"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("假如我们使用 "),s("code",[t._v("docker build -t myip .")]),t._v(" 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run myip\n当前 IP:61.148.226.66 来自:北京市 联通\n")])])]),s("p",[t._v("嗯,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 "),s("code",[t._v("CMD")]),t._v(" 中可以看到实质的命令是 "),s("code",[t._v("curl")]),t._v(",那么如果我们希望显示 HTTP 头信息,就需要加上 "),s("code",[t._v("-i")]),t._v(" 参数。那么我们可以直接加 "),s("code",[t._v("-i")]),t._v(" 参数给 "),s("code",[t._v("docker run myip")]),t._v(" 么?")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run myip -i\ndocker: Error response from daemon: invalid header field value "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"oci runtime error: container_linux.go:247: starting container process caused '),s("span",{pre:!0,attrs:{class:"token entity",title:'\\"'}},[t._v('\\"')]),t._v("exec: "),s("span",{pre:!0,attrs:{class:"token entity",title:"\\\\"}},[t._v("\\\\")]),s("span",{pre:!0,attrs:{class:"token entity",title:'\\"'}},[t._v('\\"')]),t._v("-i"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\\\"}},[t._v("\\\\")]),s("span",{pre:!0,attrs:{class:"token entity",title:'\\"'}},[t._v('\\"')]),t._v(": executable file not found in "),s("span",{pre:!0,attrs:{class:"token environment constant"}},[t._v("$PATH")]),s("span",{pre:!0,attrs:{class:"token entity",title:'\\"'}},[t._v('\\"')]),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v('"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n")])])]),s("p",[t._v("我们可以看到可执行文件找不到的报错,"),s("code",[t._v("executable file not found")]),t._v("。之前我们说过,跟在镜像名后面的是 "),s("code",[t._v("command")]),t._v(",运行时会替换 "),s("code",[t._v("CMD")]),t._v(" 的默认值。因此这里的 "),s("code",[t._v("-i")]),t._v(" 替换了原来的 "),s("code",[t._v("CMD")]),t._v(",而不是添加在原来的 "),s("code",[t._v("curl -s https://ip.cn")]),t._v(" 后面。而 "),s("code",[t._v("-i")]),t._v(" 根本不是命令,所以自然找不到。")]),t._v(" "),s("p",[t._v("那么如果我们希望加入 "),s("code",[t._v("-i")]),t._v(" 这参数,我们就必须重新完整的输入这个命令:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run myip "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" -s https://ip.cn -i\n")])])]),s("p",[t._v("这显然不是很好的解决方案,而使用 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 就可以解决这个问题。现在我们重新用 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 来实现这个镜像:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" ubuntu"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("18.04\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get update \\\n && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y curl \\\n && rm "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rf /var/lib/apt/lists/*\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ENTRYPOINT")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"curl"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"-s"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://ip.cn"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("这次我们再来尝试直接使用 "),s("code",[t._v("docker run myip -i")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run myip\n当前 IP:61.148.226.66 来自:北京市 联通\n\n$ docker run myip -i\nHTTP/1.1 "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("200")]),t._v(" OK\nServer: nginx/1.8.0\nDate: Tue, "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v(" Nov "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2016")]),t._v(" 05:12:40 GMT\nContent-Type: text/html"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("charset")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("UTF-8\nVary: Accept-Encoding\nX-Powered-By: PHP/5.6.24-1~dotdeb+7.1\nX-Cache: MISS from cache-2\nX-Cache-Lookup: MISS from cache-2:80\nX-Cache: MISS from proxy-2_6\nTransfer-Encoding: chunked\nVia: "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.1")]),t._v(" cache-2:80, "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1.1")]),t._v(" proxy-2_6:8006\nConnection: keep-alive\n\n当前 IP:61.148.226.66 来自:北京市 联通\n")])])]),s("p",[t._v("可以看到,这次成功了。这是因为当存在 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 后,"),s("code",[t._v("CMD")]),t._v(" 的内容将会作为参数传给 "),s("code",[t._v("ENTRYPOINT")]),t._v(",而这里 "),s("code",[t._v("-i")]),t._v(" 就是新的 "),s("code",[t._v("CMD")]),t._v(",因此会作为参数传给 "),s("code",[t._v("curl")]),t._v(",从而达到了我们预期的效果。")]),t._v(" "),s("h4",{attrs:{id:"场景二-应用运行前的准备工作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#场景二-应用运行前的准备工作"}},[t._v("#")]),t._v(" 场景二:应用运行前的准备工作")]),t._v(" "),s("p",[t._v("启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。")]),t._v(" "),s("p",[t._v("比如 "),s("code",[t._v("mysql")]),t._v(" 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的 mysql 服务器运行之前解决。")]),t._v(" "),s("p",[t._v("此外,可能希望避免使用 "),s("code",[t._v("root")]),t._v(" 用户去启动服务,从而提高安全性,而在启动服务前还需要以 "),s("code",[t._v("root")]),t._v(" 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 "),s("code",[t._v("root")]),t._v(" 身份执行,方便调试等。")]),t._v(" "),s("p",[t._v("这些准备工作是和容器 "),s("code",[t._v("CMD")]),t._v(" 无关的,无论 "),s("code",[t._v("CMD")]),t._v(" 为什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 中去执行,而这个脚本会将接到的参数(也就是 "),s("code",[t._v("")]),t._v(")作为命令,在脚本最后执行。比如官方镜像 "),s("code",[t._v("redis")]),t._v(" 中就是这么做的:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" alpine"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("3.4\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" addgroup "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("S redis && adduser "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("S "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("G redis redis\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ENTRYPOINT")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"docker-entrypoint.sh"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("EXPOSE")]),t._v(" 6379\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"redis-server"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("可以看到其中为了 redis 服务创建了 redis 用户,并在最后指定了 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 为 "),s("code",[t._v("docker-entrypoint.sh")]),t._v(" 脚本。")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token shebang important"}},[t._v("#!/bin/sh")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# allow the container to be started with `--user`")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$1")]),t._v('"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'redis-server'")]),t._v(" -a "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token variable"}},[s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$(")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("id")]),t._v(" -u"),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v(")")])]),t._v('"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'0'")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("then")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R redis "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("exec")]),t._v(" su-exec redis "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$0")]),t._v('"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$@")]),t._v('"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("fi")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("exec")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$@")]),t._v('"')]),t._v("\n")])])]),s("p",[t._v("该脚本的内容就是根据 "),s("code",[t._v("CMD")]),t._v(" 的内容来判断,如果是 "),s("code",[t._v("redis-server")]),t._v(" 的话,则切换到 "),s("code",[t._v("redis")]),t._v(" 用户身份启动服务器,否则依旧使用 "),s("code",[t._v("root")]),t._v(" 身份执行。比如:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run -it redis "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("id")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("uid")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("root"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("gid")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("root"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("groups")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("root"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("h3",{attrs:{id:"env-设置环境变量"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#env-设置环境变量"}},[t._v("#")]),t._v(" ENV(设置环境变量)")]),t._v(" "),s("blockquote",[s("p",[s("code",[t._v("ENV")]),t._v(" 指令用于设置环境变量。无论是后面的其它指令,如 "),s("code",[t._v("RUN")]),t._v(",还是运行时的应用,都可以直接使用这里定义的环境变量。")])]),t._v(" "),s("p",[t._v("格式:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("ENV ")])]),t._v(" "),s("li",[s("code",[t._v("ENV = =...")])])]),t._v(" "),s("p",[t._v("示例 1:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ENV")]),t._v(" VERSION=1.0 DEBUG=on \\\n NAME="),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Happy Feet"')]),t._v("\n")])])]),s("p",[t._v("这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。")]),t._v(" "),s("p",[t._v("示例 2:")]),t._v(" "),s("p",[t._v("定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方 "),s("code",[t._v("node")]),t._v(" 镜像 "),s("code",[t._v("Dockerfile")]),t._v(" 中,就有类似这样的代码:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ENV")]),t._v(" NODE_VERSION 7.2.0\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" curl "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("SLO "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"')]),t._v(" \\\n && curl "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("SLO "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"')]),t._v(" \\\n && gpg "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("batch "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("decrypt "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("output SHASUMS256.txt SHASUMS256.txt.asc \\\n && grep "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" node-v$NODE_VERSION-linux-x64.tar.xz\\$"')]),t._v(" SHASUMS256.txt "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("|")]),t._v(" sha256sum "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("c "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" \\\n && tar "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("xJf "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"node-v$NODE_VERSION-linux-x64.tar.xz"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("C /usr/local "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("strip"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("components=1 \\\n && rm "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"node-v$NODE_VERSION-linux-x64.tar.xz"')]),t._v(" SHASUMS256.txt.asc SHASUMS256.txt \\\n && ln "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("s /usr/local/bin/node /usr/local/bin/nodejs\n")])])]),s("p",[t._v("在这里先定义了环境变量 "),s("code",[t._v("NODE_VERSION")]),t._v(",其后的 "),s("code",[t._v("RUN")]),t._v(" 这层里,多次使用 "),s("code",[t._v("$NODE_VERSION")]),t._v(" 来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新 "),s("code",[t._v("7.2.0")]),t._v(" 即可,"),s("code",[t._v("Dockerfile")]),t._v(" 构建维护变得更轻松了。")]),t._v(" "),s("p",[t._v("下列指令可以支持环境变量展开: "),s("code",[t._v("ADD")]),t._v("、"),s("code",[t._v("COPY")]),t._v("、"),s("code",[t._v("ENV")]),t._v("、"),s("code",[t._v("EXPOSE")]),t._v("、"),s("code",[t._v("LABEL")]),t._v("、"),s("code",[t._v("USER")]),t._v("、"),s("code",[t._v("WORKDIR")]),t._v("、"),s("code",[t._v("VOLUME")]),t._v("、"),s("code",[t._v("STOPSIGNAL")]),t._v("、"),s("code",[t._v("ONBUILD")]),t._v("。")]),t._v(" "),s("p",[t._v("可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份 "),s("code",[t._v("Dockerfile")]),t._v(" 制作更多的镜像,只需使用不同的环境变量即可。")]),t._v(" "),s("h3",{attrs:{id:"arg-构建参数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#arg-构建参数"}},[t._v("#")]),t._v(" ARG(构建参数)")]),t._v(" "),s("blockquote",[s("p",[s("code",[t._v("Dockerfile")]),t._v(" 中的 "),s("code",[t._v("ARG")]),t._v(" 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 "),s("code",[t._v("docker build")]),t._v(" 中用 "),s("code",[t._v("--build-arg <参数名>=<值>")]),t._v(" 来覆盖。")]),t._v(" "),s("p",[t._v("构建参数和 "),s("code",[t._v("ENV")]),t._v(" 的效果一样,都是设置环境变量。所不同的是,"),s("code",[t._v("ARG")]),t._v(" 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 "),s("code",[t._v("ARG")]),t._v(" 保存密码之类的信息,因为 "),s("code",[t._v("docker history")]),t._v(" 还是可以看到所有值的。")])]),t._v(" "),s("p",[t._v("格式:"),s("code",[t._v("ARG <参数名>[=<默认值>]")])]),t._v(" "),s("p",[t._v("在 1.13 之前的版本,要求 "),s("code",[t._v("--build-arg")]),t._v(" 中的参数名,必须在 "),s("code",[t._v("Dockerfile")]),t._v(" 中用 "),s("code",[t._v("ARG")]),t._v(" 定义过了,换句话说,就是 "),s("code",[t._v("--build-arg")]),t._v(" 指定的参数,必须在 "),s("code",[t._v("Dockerfile")]),t._v(" 中使用了。如果对应参数没有被使用,则会报错退出构建。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用 CI 系统,用同样的构建流程构建不同的 "),s("code",[t._v("Dockerfile")]),t._v(" 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改。")]),t._v(" "),s("h3",{attrs:{id:"volume-定义匿名卷"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#volume-定义匿名卷"}},[t._v("#")]),t._v(" VOLUME(定义匿名卷)")]),t._v(" "),s("p",[t._v("格式:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v('VOLUME ["<路径1>", "<路径2>"...]')])]),t._v(" "),s("li",[s("code",[t._v("VOLUME <路径>")])])]),t._v(" "),s("p",[t._v("之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 "),s("code",[t._v("Dockerfile")]),t._v(" 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VOLUME")]),t._v(" /data\n")])])]),s("p",[t._v("这里的 "),s("code",[t._v("/data")]),t._v(" 目录就会在运行时自动挂载为匿名卷,任何向 "),s("code",[t._v("/data")]),t._v(" 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[t._v("docker run "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("d "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("v mydata"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("/data xxxx\n")])])]),s("p",[t._v("在这行命令中,就使用了 "),s("code",[t._v("mydata")]),t._v(" 这个命名卷挂载到了 "),s("code",[t._v("/data")]),t._v(" 这个位置,替代了 "),s("code",[t._v("Dockerfile")]),t._v(" 中定义的匿名卷的挂载配置。")]),t._v(" "),s("h3",{attrs:{id:"expose-暴露端口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#expose-暴露端口"}},[t._v("#")]),t._v(" EXPOSE(暴露端口)")]),t._v(" "),s("blockquote",[s("p",[s("code",[t._v("EXPOSE")]),t._v(" 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 "),s("code",[t._v("docker run -P")]),t._v(" 时,会自动随机映射 "),s("code",[t._v("EXPOSE")]),t._v(" 的端口。")]),t._v(" "),s("p",[t._v("要将 "),s("code",[t._v("EXPOSE")]),t._v(" 和在运行时使用 "),s("code",[t._v("-p <宿主端口>:<容器端口>")]),t._v(" 区分开来。"),s("code",[t._v("-p")]),t._v(",是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 "),s("code",[t._v("EXPOSE")]),t._v(" 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。")])]),t._v(" "),s("p",[t._v("格式:"),s("code",[t._v("EXPOSE <端口1> [<端口2>...]")]),t._v("。")]),t._v(" "),s("h3",{attrs:{id:"workdir-指定工作目录"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#workdir-指定工作目录"}},[t._v("#")]),t._v(" WORKDIR(指定工作目录)")]),t._v(" "),s("blockquote",[s("p",[t._v("使用 "),s("code",[t._v("WORKDIR")]),t._v(" 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,"),s("code",[t._v("WORKDIR")]),t._v(" 会帮你建立目录。")])]),t._v(" "),s("p",[t._v("格式:"),s("code",[t._v("WORKDIR <工作目录路径>")]),t._v("。")]),t._v(" "),s("p",[t._v("示例 1:")]),t._v(" "),s("p",[t._v("之前提到一些初学者常犯的错误是把 "),s("code",[t._v("Dockerfile")]),t._v(" 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" cd /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" echo "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hello"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(" world.txt\n")])])]),s("p",[t._v("如果将这个 "),s("code",[t._v("Dockerfile")]),t._v(" 进行构建镜像运行后,会发现找不到 "),s("code",[t._v("/app/world.txt")]),t._v(" 文件,或者其内容不是 "),s("code",[t._v("hello")]),t._v("。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 "),s("code",[t._v("Dockerfile")]),t._v(" 中,这两行 "),s("code",[t._v("RUN")]),t._v(" 命令的执行环境根本不同,是两个完全不同的容器。这就是对 "),s("code",[t._v("Dockerfile")]),t._v(" 构建分层存储的概念不了解所导致的错误。")]),t._v(" "),s("p",[t._v("之前说过每一个 "),s("code",[t._v("RUN")]),t._v(" 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 "),s("code",[t._v("RUN cd /app")]),t._v(" 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。")]),t._v(" "),s("p",[t._v("因此如果需要改变以后各层的工作目录的位置,那么应该使用 "),s("code",[t._v("WORKDIR")]),t._v(" 指令。")]),t._v(" "),s("h3",{attrs:{id:"label"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#label"}},[t._v("#")]),t._v(" LABEL")]),t._v(" "),s("p",[s("code",[t._v("LABEL")]),t._v("用于为镜像添加元数据,元数以键值对的形式指定:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("LABEL = = = ...\n")])])]),s("p",[t._v("使用"),s("code",[t._v("LABEL")]),t._v("指定元数据时,一条"),s("code",[t._v("LABEL")]),t._v("指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条"),s("code",[t._v("LABEL")]),t._v("指令指定,以免生成过多的中间镜像。")]),t._v(" "),s("p",[t._v("如,通过"),s("code",[t._v("LABEL")]),t._v("指定一些元数据:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"\n')])])]),s("p",[t._v("指定后可以通过"),s("code",[t._v("docker inspect")]),t._v("查看:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('$sudo docker inspect itbilu/test\n"Labels": {\n "version": "1.0",\n "description": "这是一个Web服务器",\n "by": "IT笔录"\n},\n')])])]),s("p",[s("em",[t._v("注意;")]),s("code",[t._v("Dockerfile")]),t._v("中还有个"),s("code",[t._v("MAINTAINER")]),t._v("命令,该命令用于指定镜像作者。但"),s("code",[t._v("MAINTAINER")]),t._v("并不推荐使用,更推荐使用"),s("code",[t._v("LABEL")]),t._v("来指定镜像作者。如:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('LABEL maintainer="itbilu.com"\n')])])]),s("h3",{attrs:{id:"user-指定当前用户"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#user-指定当前用户"}},[t._v("#")]),t._v(" USER(指定当前用户)")]),t._v(" "),s("blockquote",[s("p",[s("code",[t._v("USER")]),t._v(" 指令和 "),s("code",[t._v("WORKDIR")]),t._v(" 相似,都是改变环境状态并影响以后的层。"),s("code",[t._v("WORKDIR")]),t._v(" 是改变工作目录,"),s("code",[t._v("USER")]),t._v(" 则是改变之后层的执行 "),s("code",[t._v("RUN")]),t._v(", "),s("code",[t._v("CMD")]),t._v(" 以及 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 这类命令的身份。")]),t._v(" "),s("p",[t._v("当然,和 "),s("code",[t._v("WORKDIR")]),t._v(" 一样,"),s("code",[t._v("USER")]),t._v(" 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。")])]),t._v(" "),s("p",[t._v("格式:"),s("code",[t._v("USER <用户名>[:<用户组>]")])]),t._v(" "),s("p",[t._v("示例 1:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" groupadd "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("r redis && useradd "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("r "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("g redis redis\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("USER")]),t._v(" redis\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"redis-server"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("如果以 "),s("code",[t._v("root")]),t._v(" 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 "),s("code",[t._v("su")]),t._v("或者 "),s("code",[t._v("sudo")]),t._v(",这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 "),s("a",{attrs:{href:"https://github.com/tianon/gosu",target:"_blank",rel:"noopener noreferrer"}},[s("code",[t._v("gosu")]),s("OutboundLink")],1),t._v("。")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 建立 redis 用户,并使用 gosu 换另一个用户执行命令")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" groupadd "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("r redis && useradd "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("r "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("g redis redis\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 下载 gosu")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" wget "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("O /usr/local/bin/gosu "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64"')]),t._v(" \\\n && chmod +x /usr/local/bin/gosu \\\n && gosu nobody true\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置 CMD,并以另外的用户执行")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"exec"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"gosu"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"redis"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"redis-server"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("h3",{attrs:{id:"healthcheck-健康检查"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#healthcheck-健康检查"}},[t._v("#")]),t._v(" HEALTHCHECK(健康检查)")]),t._v(" "),s("p",[t._v("格式:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("HEALTHCHECK [选项] CMD <命令>")]),t._v(":设置检查容器健康状况的命令")]),t._v(" "),s("li",[s("code",[t._v("HEALTHCHECK NONE")]),t._v(":如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令")])]),t._v(" "),s("p",[s("code",[t._v("HEALTHCHECK")]),t._v(" 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。")]),t._v(" "),s("p",[t._v("在没有 "),s("code",[t._v("HEALTHCHECK")]),t._v(" 指令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了。在 1.12 以前,Docker 不会检测到容器的这种状态,从而不会重新调度,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。")]),t._v(" "),s("p",[t._v("而自 1.12 之后,Docker 提供了 "),s("code",[t._v("HEALTHCHECK")]),t._v(" 指令,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。")]),t._v(" "),s("p",[t._v("当在一个镜像指定了 "),s("code",[t._v("HEALTHCHECK")]),t._v(" 指令后,用其启动容器,初始状态会为 "),s("code",[t._v("starting")]),t._v(",在 "),s("code",[t._v("HEALTHCHECK")]),t._v(" 指令检查成功后变为 "),s("code",[t._v("healthy")]),t._v(",如果连续一定次数失败,则会变为 "),s("code",[t._v("unhealthy")]),t._v("。")]),t._v(" "),s("p",[s("code",[t._v("HEALTHCHECK")]),t._v(" 支持下列选项:")]),t._v(" "),s("ul",[s("li",[s("code",[t._v("--interval=<间隔>")]),t._v(":两次健康检查的间隔,默认为 30 秒;")]),t._v(" "),s("li",[s("code",[t._v("--timeout=<时长>")]),t._v(":健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;")]),t._v(" "),s("li",[s("code",[t._v("--retries=<次数>")]),t._v(":当连续失败指定次数后,则将容器状态视为 "),s("code",[t._v("unhealthy")]),t._v(",默认 3 次。")])]),t._v(" "),s("p",[t._v("和 "),s("code",[t._v("CMD")]),t._v(", "),s("code",[t._v("ENTRYPOINT")]),t._v(" 一样,"),s("code",[t._v("HEALTHCHECK")]),t._v(" 只可以出现一次,如果写了多个,只有最后一个生效。")]),t._v(" "),s("p",[t._v("在 "),s("code",[t._v("HEALTHCHECK [选项] CMD")]),t._v(" 后面的命令,格式和 "),s("code",[t._v("ENTRYPOINT")]),t._v(" 一样,分为 "),s("code",[t._v("shell")]),t._v(" 格式,和 "),s("code",[t._v("exec")]),t._v(" 格式。命令的返回值决定了该次健康检查的成功与否:"),s("code",[t._v("0")]),t._v(":成功;"),s("code",[t._v("1")]),t._v(":失败;"),s("code",[t._v("2")]),t._v(":保留,不要使用这个值。")]),t._v(" "),s("p",[t._v("假设我们有个镜像是个最简单的 Web 服务,我们希望增加健康检查来判断其 Web 服务是否在正常工作,我们可以用 "),s("code",[t._v("curl")]),t._v(" 来帮助判断,其 "),s("code",[t._v("Dockerfile")]),t._v(" 的 "),s("code",[t._v("HEALTHCHECK")]),t._v(" 可以这么写:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" nginx\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get update && apt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("get install "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("y curl && rm "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rf /var/lib/apt/lists/*\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("HEALTHCHECK")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("interval=5s "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("timeout=3s \\\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" curl "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("fs http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//localhost/ "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("|")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("|")]),t._v(" exit 1\n")])])]),s("p",[t._v("这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 "),s("code",[t._v("curl -fs http://localhost/ || exit 1")]),t._v(" 作为健康检查命令。")]),t._v(" "),s("p",[t._v("使用 "),s("code",[t._v("docker build")]),t._v(" 来构建这个镜像:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker build -t myweb:v1 "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n")])])]),s("p",[t._v("构建好了后,我们启动一个容器:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker run -d --name web -p "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v(":80 myweb:v1\n")])])]),s("p",[t._v("当运行该镜像后,可以通过 "),s("code",[t._v("docker container ls")]),t._v(" 看到最初的状态为 "),s("code",[t._v("(health: starting)")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker container "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v("\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n03e28eb00bd0 myweb:v1 "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"nginx -g \'daemon off"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" seconds ago Up "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" seconds "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("health: starting"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v("/tcp, "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("443")]),t._v("/tcp web\n")])])]),s("p",[t._v("在等待几秒钟后,再次 "),s("code",[t._v("docker container ls")]),t._v(",就会看到健康状态变化为了 "),s("code",[t._v("(healthy)")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker container "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v("\nCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\n03e28eb00bd0 myweb:v1 "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"nginx -g \'daemon off"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("18")]),t._v(" seconds ago Up "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("16")]),t._v(" seconds "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("healthy"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v("/tcp, "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("443")]),t._v("/tcp web\n")])])]),s("p",[t._v("如果健康检查连续失败超过了重试次数,状态就会变为 "),s("code",[t._v("(unhealthy)")]),t._v("。")]),t._v(" "),s("p",[t._v("为了帮助排障,健康检查命令的输出(包括 "),s("code",[t._v("stdout")]),t._v(" 以及 "),s("code",[t._v("stderr")]),t._v(")都会被存储于健康状态里,可以用 "),s("code",[t._v("docker inspect")]),t._v(" 来查看。")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("$ docker inspect --format "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'{{json .State.Health}}'")]),t._v(" web "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" python -m json.tool\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"FailingStreak"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(",\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Log"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"End"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2016-11-25T14:35:37.940957051Z"')]),t._v(",\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"ExitCode"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(",\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Output"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"'),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("Welcome to nginx!"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("

Welcome to nginx!

"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("

If you see this page, the nginx web server is successfully installed and"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("working. Further configuration is required.

"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("

For online documentation and support please refer to"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("nginx.org.
"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("Commercial support is available at"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("nginx.com.

"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v("

Thank you for using nginx.

"),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v(""),s("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[t._v("\\n")]),t._v('"')]),t._v(",\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Start"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2016-11-25T14:35:37.780192565Z"')]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(",\n "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Status"')]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"healthy"')]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"onbuild-为他人作嫁衣裳"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#onbuild-为他人作嫁衣裳"}},[t._v("#")]),t._v(" ONBUILD(为他人作嫁衣裳)")]),t._v(" "),s("p",[t._v("格式:"),s("code",[t._v("ONBUILD <其它指令>")]),t._v("。")]),t._v(" "),s("p",[s("code",[t._v("ONBUILD")]),t._v(" 是一个特殊的指令,它后面跟的是其它指令,比如 "),s("code",[t._v("RUN")]),t._v(", "),s("code",[t._v("COPY")]),t._v(" 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。")]),t._v(" "),s("p",[s("code",[t._v("Dockerfile")]),t._v(" 中的其它指令都是为了定制当前镜像而准备的,唯有 "),s("code",[t._v("ONBUILD")]),t._v(" 是为了帮助别人定制自己而准备的。")]),t._v(" "),s("p",[t._v("假设我们要制作 Node.js 所写的应用的镜像。我们都知道 Node.js 使用 "),s("code",[t._v("npm")]),t._v(" 进行包管理,所有依赖、配置、启动信息等会放到 "),s("code",[t._v("package.json")]),t._v(" 文件里。在拿到程序代码后,需要先进行 "),s("code",[t._v("npm install")]),t._v(" 才可以获得所有需要的依赖。然后就可以通过 "),s("code",[t._v("npm start")]),t._v("来启动应用。因此,一般来说会这样写 "),s("code",[t._v("Dockerfile")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("slim\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" mkdir /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WORKDIR")]),t._v(" /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" ./package.json /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"install"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" . /app/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"start"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("把这个 "),s("code",[t._v("Dockerfile")]),t._v(" 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 "),s("code",[t._v("Dockerfile")]),t._v(" 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。")]),t._v(" "),s("p",[t._v("如果第一个 Node.js 项目在开发过程中,发现这个 "),s("code",[t._v("Dockerfile")]),t._v(" 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 "),s("code",[t._v("Dockerfile")]),t._v(",再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 "),s("code",[t._v("Dockerfile")]),t._v(" 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 "),s("code",[t._v("Dockerfile")]),t._v(",而第二个项目的 "),s("code",[t._v("Dockerfile")]),t._v(" 就会被自动修复。")]),t._v(" "),s("p",[t._v("那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 "),s("code",[t._v("Dockerfile")]),t._v("的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 "),s("code",[t._v("Dockerfile")]),t._v(" 就会变为:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("slim\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" mkdir /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WORKDIR")]),t._v(" /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"start"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("这里我们把项目相关的构建指令拿出来,放到子项目里去。假设这个基础镜像的名字为 "),s("code",[t._v("my-node")]),t._v(" 的话,各个项目内的自己的 "),s("code",[t._v("Dockerfile")]),t._v(" 就变为:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" my"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("node\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" ./package.json /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"install"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" . /app/\n")])])]),s("p",[t._v("基础镜像变化后,各个项目都用这个 "),s("code",[t._v("Dockerfile")]),t._v(" 重新构建镜像,会继承基础镜像的更新。")]),t._v(" "),s("p",[t._v("那么,问题解决了么?没有。准确说,只解决了一半。如果这个 "),s("code",[t._v("Dockerfile")]),t._v(" 里面有些东西需要调整呢?比如 "),s("code",[t._v("npm install")]),t._v(" 都需要加一些参数,那怎么办?这一行 "),s("code",[t._v("RUN")]),t._v(" 是不可能放入基础镜像的,因为涉及到了当前项目的 "),s("code",[t._v("./package.json")]),t._v(",难道又要一个个修改么?所以说,这样制作基础镜像,只解决了原来的 "),s("code",[t._v("Dockerfile")]),t._v(" 的前 4 条指令的变化问题,而后面三条指令的变化则完全没办法处理。")]),t._v(" "),s("p",[s("code",[t._v("ONBUILD")]),t._v(" 可以解决这个问题。让我们用 "),s("code",[t._v("ONBUILD")]),t._v(" 重新写一下基础镜像的 "),s("code",[t._v("Dockerfile")]),t._v(":")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("slim\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" mkdir /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("WORKDIR")]),t._v(" /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ONBUILD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" ./package.json /app\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ONBUILD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("RUN")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"install"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("ONBUILD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("COPY")]),t._v(" . /app/\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("CMD")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"npm"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"start"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),s("p",[t._v("这次我们回到原始的 "),s("code",[t._v("Dockerfile")]),t._v(",但是这次将项目相关的指令加上 "),s("code",[t._v("ONBUILD")]),t._v(",这样在构建基础镜像的时候,这三行并不会被执行。然后各个项目的 "),s("code",[t._v("Dockerfile")]),t._v(" 就变成了简单地:")]),t._v(" "),s("div",{staticClass:"language-dockerfile extra-class"},[s("pre",{pre:!0,attrs:{class:"language-dockerfile"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("FROM")]),t._v(" my"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("node\n")])])]),s("p",[t._v("是的,只有这么一行。当在各个项目目录中,用这个只有一行的 "),s("code",[t._v("Dockerfile")]),t._v(" 构建镜像时,之前基础镜像的那三行 "),s("code",[t._v("ONBUILD")]),t._v(" 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 "),s("code",[t._v("npm install")]),t._v(",生成应用镜像。")]),t._v(" "),s("h2",{attrs:{id:"二、最佳实践"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二、最佳实践"}},[t._v("#")]),t._v(" 二、最佳实践")]),t._v(" "),s("p",[t._v("有任何的问题或建议,欢迎给我留言 😆")]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Dockerfie 官方文档"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://docs.docker.com/develop/develop-images/dockerfile_best-practices/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Best practices for writing Dockerfiles"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/docker-library/docs",target:"_blank",rel:"noopener noreferrer"}},[t._v("Docker 官方镜像 Dockerfile"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Dockerfile 指令详解"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);e.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/15.d217acb7.js b/assets/js/15.d217acb7.js new file mode 100644 index 0000000..089e589 --- /dev/null +++ b/assets/js/15.d217acb7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{403:function(e,a,t){"use strict";t.r(a);var r=t(15),s=Object(r.a)({},(function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"docker-快速入门"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-快速入门"}},[e._v("#")]),e._v(" Docker 快速入门")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"#%E4%B8%80docker-%E7%9A%84%E7%AE%80%E4%BB%8B"}},[e._v("一、Docker 的简介")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E4%BA%8Cdocker-%E7%9A%84%E8%BF%90%E7%BB%B4"}},[e._v("二、Docker 的运维")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E4%B8%89hello-world-%E5%AE%9E%E4%BE%8B"}},[e._v("三、hello world 实例")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%9B%9B%E5%88%B6%E4%BD%9C-docker-%E5%AE%B9%E5%99%A8"}},[e._v("四、制作 Docker 容器")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[e._v("参考资料")])])]),e._v(" "),t("h2",{attrs:{id:"一、docker-的简介"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#一、docker-的简介"}},[e._v("#")]),e._v(" 一、Docker 的简介")]),e._v(" "),t("h3",{attrs:{id:"什么是-docker"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#什么是-docker"}},[e._v("#")]),e._v(" 什么是 Docker")]),e._v(" "),t("blockquote",[t("p",[t("strong",[e._v("Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。")])])]),e._v(" "),t("p",[e._v("它是目前最流行的 Linux 容器解决方案。")]),e._v(" "),t("p",[e._v("Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。")]),e._v(" "),t("p",[e._v("总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。")]),e._v(" "),t("h3",{attrs:{id:"为什么需要-docker"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要-docker"}},[e._v("#")]),e._v(" 为什么需要 Docker")]),e._v(" "),t("ul",[t("li",[t("strong",[e._v("更高效的利用系统资源")]),e._v(" - 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,"),t("code",[e._v("Docker")]),e._v(" 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。")]),e._v(" "),t("li",[t("strong",[e._v("更快速的启动时间")]),e._v(" - 传统的虚拟机技术启动应用服务往往需要数分钟,而 "),t("code",[e._v("Docker")]),e._v(" 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。")]),e._v(" "),t("li",[t("strong",[e._v("一致的运行环境")]),e._v(" - 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 "),t("code",[e._v("Docker")]),e._v(" 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 "),t("em",[e._v("「这段代码在我机器上没问题啊」")]),e._v(" 这类问题。")]),e._v(" "),t("li",[t("strong",[e._v("持续交付和部署")]),e._v(" - 对开发和运维("),t("a",{attrs:{href:"https://zh.wikipedia.org/wiki/DevOps",target:"_blank",rel:"noopener noreferrer"}},[e._v("DevOps"),t("OutboundLink")],1),e._v(")人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 "),t("code",[e._v("Docker")]),e._v(" 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 "),t("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/image/dockerfile",target:"_blank",rel:"noopener noreferrer"}},[e._v("Dockerfile"),t("OutboundLink")],1),e._v(" 来进行镜像构建,并结合 "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Continuous_integration",target:"_blank",rel:"noopener noreferrer"}},[e._v("持续集成(Continuous Integration)"),t("OutboundLink")],1),e._v(" 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Continuous_delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("持续部署(Continuous Delivery/Deployment)"),t("OutboundLink")],1),e._v(" 系统进行自动部署。而且使用 "),t("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/image/build.html",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("Dockerfile")]),t("OutboundLink")],1),e._v(" 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。")]),e._v(" "),t("li",[t("strong",[e._v("更轻松的迁移")]),e._v(" - 由于 "),t("code",[e._v("Docker")]),e._v(" 确保了执行环境的一致性,使得应用的迁移更加容易。"),t("code",[e._v("Docker")]),e._v(" 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。")]),e._v(" "),t("li",[t("strong",[e._v("更轻松的维护和扩展")]),e._v(" - "),t("code",[e._v("Docker")]),e._v(" 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,"),t("code",[e._v("Docker")]),e._v(" 团队同各个开源项目团队一起维护了一大批高质量的 "),t("a",{attrs:{href:"https://hub.docker.com/search/?type=image&image_filter=official",target:"_blank",rel:"noopener noreferrer"}},[e._v("官方镜像"),t("OutboundLink")],1),e._v(",既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。")])]),e._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/docker/containers-and-vm.png",alt:"img"}})]),e._v(" "),t("h3",{attrs:{id:"docker-的主要用途"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-的主要用途"}},[e._v("#")]),e._v(" Docker 的主要用途")]),e._v(" "),t("p",[e._v("Docker 提供了被称为容器的松散隔离环境,在环境中可以打包和运行应用程序。隔离和安全性允许您在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机的内核中运行。这意味着您可以在给定的硬件组合上运行更多容器,而不是使用虚拟机。你甚至可以在实际上是虚拟机的主机中运行 Docker 容器!")]),e._v(" "),t("p",[e._v("Docker 的主要用途,目前有三大类。")]),e._v(" "),t("ul",[t("li",[e._v("**提供一次性的环境。**比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。")]),e._v(" "),t("li",[e._v("**提供弹性的云服务。**因为 Docker 容器可以随开随关,很适合动态扩容和缩容。")]),e._v(" "),t("li",[e._v("**组建微服务架构。**通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。")])]),e._v(" "),t("h3",{attrs:{id:"docker-的核心概念"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-的核心概念"}},[e._v("#")]),e._v(" Docker 的核心概念")]),e._v(" "),t("h4",{attrs:{id:"镜像"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#镜像"}},[e._v("#")]),e._v(" 镜像")]),e._v(" "),t("p",[e._v("Docker 把应用程序及其依赖,打包在镜像(Image)文件里面。")]),e._v(" "),t("p",[e._v("我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。")]),e._v(" "),t("p",[e._v("Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。")]),e._v(" "),t("p",[t("strong",[e._v("分层存储")])]),e._v(" "),t("p",[e._v("因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。")]),e._v(" "),t("p",[e._v("镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。")]),e._v(" "),t("p",[e._v("分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。")]),e._v(" "),t("h4",{attrs:{id:"容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#容器"}},[e._v("#")]),e._v(" 容器")]),e._v(" "),t("p",[e._v("镜像("),t("code",[e._v("Image")]),e._v(")和容器("),t("code",[e._v("Container")]),e._v(")的关系,就像是面向对象程序设计中的 "),t("code",[e._v("类")]),e._v(" 和 "),t("code",[e._v("实例")]),e._v(" 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。")]),e._v(" "),t("p",[e._v("容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 "),t("a",{attrs:{href:"https://en.wikipedia.org/wiki/Linux_namespaces",target:"_blank",rel:"noopener noreferrer"}},[e._v("命名空间"),t("OutboundLink")],1),e._v("。因此容器可以拥有自己的 "),t("code",[e._v("root")]),e._v(" 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。")]),e._v(" "),t("p",[e._v("前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为"),t("strong",[e._v("容器存储层")]),e._v("。")]),e._v(" "),t("p",[e._v("容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。")]),e._v(" "),t("p",[e._v("按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 "),t("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/data_management/volume.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("数据卷(Volume)"),t("OutboundLink")],1),e._v("、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。")]),e._v(" "),t("p",[e._v("数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。")]),e._v(" "),t("h4",{attrs:{id:"仓库"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#仓库"}},[e._v("#")]),e._v(" 仓库")]),e._v(" "),t("p",[e._v("镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,"),t("a",{attrs:{href:"https://yeasy.gitbooks.io/docker_practice/content/repository/registry.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker Registry"),t("OutboundLink")],1),e._v(" 就是这样的服务。")]),e._v(" "),t("p",[e._v("一个 "),t("strong",[e._v("Docker Registry")]),e._v(" 中可以包含多个"),t("strong",[e._v("仓库")]),e._v("("),t("code",[e._v("Repository")]),e._v(");每个仓库可以包含多个"),t("strong",[e._v("标签")]),e._v("("),t("code",[e._v("Tag")]),e._v(");每个标签对应一个镜像。")]),e._v(" "),t("p",[e._v("通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 "),t("code",[e._v("<仓库名>:<标签>")]),e._v(" 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 "),t("code",[e._v("latest")]),e._v(" 作为默认标签。")]),e._v(" "),t("p",[e._v("以 "),t("a",{attrs:{href:"https://store.docker.com/images/ubuntu",target:"_blank",rel:"noopener noreferrer"}},[e._v("Ubuntu 镜像"),t("OutboundLink")],1),e._v(" 为例,"),t("code",[e._v("ubuntu")]),e._v(" 是仓库的名字,其内包含有不同的版本标签,如,"),t("code",[e._v("16.04")]),e._v(", "),t("code",[e._v("18.04")]),e._v("。我们可以通过 "),t("code",[e._v("ubuntu:14.04")]),e._v(",或者 "),t("code",[e._v("ubuntu:18.04")]),e._v(" 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 "),t("code",[e._v("ubuntu")]),e._v(",那将视为 "),t("code",[e._v("ubuntu:latest")]),e._v("。")]),e._v(" "),t("p",[e._v("仓库名经常以 "),t("em",[e._v("两段式路径")]),e._v(" 形式出现,比如 "),t("code",[e._v("jwilder/nginx-proxy")]),e._v(",前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。")]),e._v(" "),t("h2",{attrs:{id:"二、docker-的运维"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#二、docker-的运维"}},[e._v("#")]),e._v(" 二、Docker 的运维")]),e._v(" "),t("p",[e._v("不同操作系统环境下安装 Docker 的方式有所不同,详情可以参:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.docker.com/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 官方安装指南"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://docker_practice.gitee.io/install/",target:"_blank",rel:"noopener noreferrer"}},[e._v("安装 Docker(中文)"),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("国内访问 Docker 比较慢,如果需要提速,可以参考 "),t("a",{attrs:{href:"https://docker_practice.gitee.io/install/mirror.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("镜像加速器"),t("OutboundLink")],1)]),e._v(" "),t("p",[e._v("安装完成后,运行下面的命令,验证是否安装成功。")]),e._v(" "),t("ul",[t("li",[t("code",[e._v("docker version")])]),e._v(" "),t("li",[t("code",[e._v("docker info")])])]),e._v(" "),t("p",[e._v("Docker 需要用户具有 sudo 权限,为了避免每次命令都输入"),t("code",[e._v("sudo")]),e._v(",可以把用户加入 Docker 用户组("),t("a",{attrs:{href:"https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user",target:"_blank",rel:"noopener noreferrer"}},[e._v("官方文档"),t("OutboundLink")],1),e._v(")。")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("usermod")]),e._v(" -aG docker "),t("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("$USER")]),e._v("\n")])])]),t("p",[e._v("Docker 是服务器----客户端架构。命令行运行"),t("code",[e._v("docker")]),e._v("命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动("),t("a",{attrs:{href:"https://docs.docker.com/config/daemon/systemd/",target:"_blank",rel:"noopener noreferrer"}},[e._v("官方文档"),t("OutboundLink")],1),e._v(")。")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# service 命令的用法")]),e._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("service")]),e._v(" docker start\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# systemctl 命令的用法")]),e._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sudo")]),e._v(" systemctl start docker\n")])])]),t("h2",{attrs:{id:"三、hello-world-实例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#三、hello-world-实例"}},[e._v("#")]),e._v(" 三、Hello World 实例")]),e._v(" "),t("p",[e._v('下面,我们通过最简单的 image 文件"'),t("a",{attrs:{href:"https://hub.docker.com/r/library/hello-world/",target:"_blank",rel:"noopener noreferrer"}},[e._v('hello world"'),t("OutboundLink")],1),e._v(",感受一下 Docker。")]),e._v(" "),t("p",[e._v("需要说明的是,国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站,具体的修改方法在"),t("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2018/02/docker-wordpress-tutorial.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("下一篇文章"),t("OutboundLink")],1),e._v("的第一节。有需要的朋友,可以先看一下。")]),e._v(" "),t("p",[e._v("首先,运行下面的命令,将 image 文件从仓库抓取到本地。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image pull library/hello-world\n")])])])]),e._v(" "),t("p",[e._v("上面代码中,"),t("code",[e._v("docker image pull")]),e._v("是抓取 image 文件的命令。"),t("code",[e._v("library/hello-world")]),e._v("是 image 文件在仓库里面的位置,其中"),t("code",[e._v("library")]),e._v("是 image 文件所在的组,"),t("code",[e._v("hello-world")]),e._v("是 image 文件的名字。")]),e._v(" "),t("p",[e._v("由于 Docker 官方提供的 image 文件,都放在"),t("a",{attrs:{href:"https://hub.docker.com/r/library/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("library")]),t("OutboundLink")],1),e._v("组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image pull hello-world\n")])])])]),e._v(" "),t("p",[e._v("抓取成功以后,就可以在本机看到这个 image 文件了。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("ls")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("现在,运行这个 image 文件。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run hello-world\n")])])])]),e._v(" "),t("p",[t("code",[e._v("docker container run")]),e._v("命令会从 image 文件,生成一个正在运行的容器实例。")]),e._v(" "),t("p",[e._v("注意,"),t("code",[e._v("docker container run")]),e._v("命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的"),t("code",[e._v("docker image pull")]),e._v("命令并不是必需的步骤。")]),e._v(" "),t("p",[e._v("如果运行成功,你会在屏幕上读到下面的输出。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run hello-world\n\nHello from Docker"),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("!")]),e._v("\nThis message shows that your installation appears to be working correctly.\n\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("..")]),e._v(". "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("..")]),e._v(".\n")])])])]),e._v(" "),t("p",[e._v("输出这段提示以后,"),t("code",[e._v("hello world")]),e._v("就会停止运行,容器自动终止。")]),e._v(" "),t("p",[e._v("有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run -it ubuntu "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("bash")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("对于那些不会自动终止的容器,必须使用"),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/commandline/container_kill/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("docker container kill")]),t("OutboundLink")],1),e._v(" 命令手动终止。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("kill")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("containID"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])])]),e._v(" "),t("h2",{attrs:{id:"四、制作-docker-容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#四、制作-docker-容器"}},[e._v("#")]),e._v(" 四、制作 Docker 容器")]),e._v(" "),t("p",[e._v("下面我以 "),t("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2017/08/koa.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("koa-demos"),t("OutboundLink")],1),e._v(" 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。")]),e._v(" "),t("p",[e._v("作为准备工作,请先"),t("a",{attrs:{href:"https://github.com/ruanyf/koa-demos/archive/master.zip",target:"_blank",rel:"noopener noreferrer"}},[e._v("下载源码"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("git")]),e._v(" clone https://github.com/ruanyf/koa-demos.git\n$ "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("cd")]),e._v(" koa-demos\n")])])])]),e._v(" "),t("h3",{attrs:{id:"编写-dockerfile-文件"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编写-dockerfile-文件"}},[e._v("#")]),e._v(" 编写 Dockerfile 文件")]),e._v(" "),t("p",[e._v("首先,在项目的根目录下,新建一个文本文件"),t("code",[e._v(".dockerignore")]),e._v(",写入下面的"),t("a",{attrs:{href:"https://github.com/ruanyf/koa-demos/blob/master/.dockerignore",target:"_blank",rel:"noopener noreferrer"}},[e._v("内容"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v(".git\nnode_modules\nnpm-debug.log\n")])])])]),e._v(" "),t("p",[e._v("上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。")]),e._v(" "),t("p",[e._v("然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的"),t("a",{attrs:{href:"https://github.com/ruanyf/koa-demos/blob/master/Dockerfile",target:"_blank",rel:"noopener noreferrer"}},[e._v("内容"),t("OutboundLink")],1),e._v("。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("FROM node:8.4\nCOPY "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v(" /app\nWORKDIR /app\nRUN "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("npm")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("install")]),e._v(" --registry"),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("https://registry.npm.taobao.org\nEXPOSE "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("3000")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("上面代码一共五行,含义如下。")]),e._v(" "),t("blockquote",[t("ul",[t("li",[t("code",[e._v("FROM node:8.4")]),e._v(":该 image 文件继承官方的 node image,冒号表示标签,这里标签是"),t("code",[e._v("8.4")]),e._v(",即 8.4 版本的 node。")]),e._v(" "),t("li",[t("code",[e._v("COPY . /app")]),e._v(":将当前目录下的所有文件(除了"),t("code",[e._v(".dockerignore")]),e._v("排除的路径),都拷贝进入 image 文件的"),t("code",[e._v("/app")]),e._v("目录。")]),e._v(" "),t("li",[t("code",[e._v("WORKDIR /app")]),e._v(":指定接下来的工作路径为"),t("code",[e._v("/app")]),e._v("。")]),e._v(" "),t("li",[t("code",[e._v("RUN npm install")]),e._v(":在"),t("code",[e._v("/app")]),e._v("目录下,运行"),t("code",[e._v("npm install")]),e._v("命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。")]),e._v(" "),t("li",[t("code",[e._v("EXPOSE 3000")]),e._v(":将容器 3000 端口暴露出来, 允许外部连接这个端口。")])])]),e._v(" "),t("h3",{attrs:{id:"创建-image-文件"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#创建-image-文件"}},[e._v("#")]),e._v(" 创建 image 文件")]),e._v(" "),t("p",[e._v("有了 Dockerfile 文件以后,就可以使用"),t("code",[e._v("docker image build")]),e._v("命令创建 image 文件了。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image build -t koa-demo "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 或者")]),e._v("\n$ docker image build -t koa-demo:0.0.1 "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("上面代码中,"),t("code",[e._v("-t")]),e._v("参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是"),t("code",[e._v("latest")]),e._v("。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。")]),e._v(" "),t("p",[e._v("如果运行成功,就可以看到新生成的 image 文件"),t("code",[e._v("koa-demo")]),e._v("了。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("ls")]),e._v("\n")])])])]),e._v(" "),t("h3",{attrs:{id:"生成容器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#生成容器"}},[e._v("#")]),e._v(" 生成容器")]),e._v(" "),t("p",[t("code",[e._v("docker container run")]),e._v("命令会从 image 文件生成容器。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run -p "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("8000")]),e._v(":3000 -it koa-demo /bin/bash\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 或者")]),e._v("\n$ docker container run -p "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("8000")]),e._v(":3000 -it koa-demo:0.0.1 /bin/bash\n")])])])]),e._v(" "),t("p",[e._v("上面命令的各个参数含义如下:")]),e._v(" "),t("blockquote",[t("ul",[t("li",[t("code",[e._v("-p")]),e._v("参数:容器的 3000 端口映射到本机的 8000 端口。")]),e._v(" "),t("li",[t("code",[e._v("-it")]),e._v("参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。")]),e._v(" "),t("li",[t("code",[e._v("koa-demo:0.0.1")]),e._v(":image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。")]),e._v(" "),t("li",[t("code",[e._v("/bin/bash")]),e._v(":容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。")])])]),e._v(" "),t("p",[e._v("如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("root@66d80f4aaf1e:/app"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("#")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("root@66d80f4aaf1e:/app"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# node demos/01.js")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v('这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示"Not Found",这是因为这个 '),t("a",{attrs:{href:"https://github.com/ruanyf/koa-demos/blob/master/demos/01.js",target:"_blank",rel:"noopener noreferrer"}},[e._v("demo"),t("OutboundLink")],1),e._v(" 没有写路由。")]),e._v(" "),t("p",[e._v("这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。")]),e._v(" "),t("p",[e._v("现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用"),t("code",[e._v("docker container kill")]),e._v("终止容器运行。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 在本机的另一个终端窗口,查出容器的 ID")]),e._v("\n$ docker container "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("ls")]),e._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 停止指定的容器运行")]),e._v("\n$ docker container "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("kill")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("containerID"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("容器停止运行之后,并不会消失,用下面的命令删除容器文件。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查出容器的 ID")]),e._v("\n$ docker container "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("ls")]),e._v(" --all\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 删除指定的容器文件")]),e._v("\n$ docker container "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("rm")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("containerID"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("也可以使用"),t("code",[e._v("docker container run")]),e._v("命令的"),t("code",[e._v("--rm")]),e._v("参数,在容器终止运行后自动删除容器文件。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run --rm -p "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("8000")]),e._v(":3000 -it koa-demo /bin/bash\n")])])])]),e._v(" "),t("h3",{attrs:{id:"cmd-命令"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#cmd-命令"}},[e._v("#")]),e._v(" CMD 命令")]),e._v(" "),t("p",[e._v("上一节的例子里面,容器启动以后,需要手动输入命令"),t("code",[e._v("node demos/01.js")]),e._v("。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("FROM node:8.4\nCOPY "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v(" /app\nWORKDIR /app\nRUN "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("npm")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("install")]),e._v(" --registry"),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("https://registry.npm.taobao.org\nEXPOSE "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("3000")]),e._v("\nCMD node demos/01.js\n")])])])]),e._v(" "),t("p",[e._v("上面的 Dockerfile 里面,多了最后一行"),t("code",[e._v("CMD node demos/01.js")]),e._v(",它表示容器启动后自动执行"),t("code",[e._v("node demos/01.js")]),e._v("。")]),e._v(" "),t("p",[e._v("你可能会问,"),t("code",[e._v("RUN")]),e._v("命令与"),t("code",[e._v("CMD")]),e._v("命令的区别在哪里?简单说,"),t("code",[e._v("RUN")]),e._v("命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;"),t("code",[e._v("CMD")]),e._v("命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个"),t("code",[e._v("RUN")]),e._v("命令,但是只能有一个"),t("code",[e._v("CMD")]),e._v("命令。")]),e._v(" "),t("p",[e._v("注意,指定了"),t("code",[e._v("CMD")]),e._v("命令以后,"),t("code",[e._v("docker container run")]),e._v("命令就不能附加命令了(比如前面的"),t("code",[e._v("/bin/bash")]),e._v("),否则它会覆盖"),t("code",[e._v("CMD")]),e._v("命令。现在,启动容器可以使用下面的命令。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker container run --rm -p "),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("8000")]),e._v(":3000 -it koa-demo:0.0.1\n")])])])]),e._v(" "),t("h3",{attrs:{id:"发布-image-文件"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#发布-image-文件"}},[e._v("#")]),e._v(" 发布 image 文件")]),e._v(" "),t("p",[e._v("容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。")]),e._v(" "),t("p",[e._v("首先,去 "),t("a",{attrs:{href:"https://hub.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("hub.docker.com"),t("OutboundLink")],1),e._v(" 或 "),t("a",{attrs:{href:"https://cloud.docker.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("cloud.docker.com"),t("OutboundLink")],1),e._v(" 注册一个账户。然后,用下面的命令登录。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker login\n")])])])]),e._v(" "),t("p",[e._v("接着,为本地的 image 标注用户名和版本。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image tag "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("imageName"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("username"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("/"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("repository"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(":"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("tag"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 实例")]),e._v("\n$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1\n")])])])]),e._v(" "),t("p",[e._v("也可以不标注用户名,重新构建一下 image 文件。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image build -t "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("username"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("/"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("repository"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(":"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("tag"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("最后,发布 image 文件。")]),e._v(" "),t("blockquote",[t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("$ docker image push "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("username"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("/"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("repository"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v(":"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),e._v("tag"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])])]),e._v(" "),t("p",[e._v("发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。")]),e._v(" "),t("h2",{attrs:{id:"参考资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[e._v("#")]),e._v(" 参考资料")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker 入门教程"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://github.com/yeasy/docker_practice",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker — 从入门到实践"),t("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/16.ad565eae.js b/assets/js/16.ad565eae.js new file mode 100644 index 0000000..e87464c --- /dev/null +++ b/assets/js/16.ad565eae.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{404:function(e,t,s){"use strict";s.r(t);var a=s(15),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h1",{attrs:{id:"kubernetes-应用指南"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#kubernetes-应用指南"}},[e._v("#")]),e._v(" Kubernetes 应用指南")]),e._v(" "),s("blockquote",[s("p",[e._v("Kubernetes 是谷歌开源的容器集群管理系统 是用于自动部署,扩展和管理 Docker 应用程序的开源系统,简称 K8S。")]),e._v(" "),s("p",[e._v("关键词: "),s("code",[e._v("docker")])])]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"#%E4%B8%80k8s-%E7%AE%80%E4%BB%8B"}},[e._v("一、K8S 简介")])]),e._v(" "),s("li",[s("a",{attrs:{href:"#%E4%BA%8Ck8s-%E5%91%BD%E4%BB%A4"}},[e._v("二、K8S 命令")])]),e._v(" "),s("li",[s("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[e._v("参考资料")])])]),e._v(" "),s("h2",{attrs:{id:"一、k8s-简介"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#一、k8s-简介"}},[e._v("#")]),e._v(" 一、K8S 简介")]),e._v(" "),s("p",[e._v("K8S 主控组件(Master) 包含三个进程,都运行在集群中的某个节上,通常这个节点被称为 master 节点。这些进程包括:"),s("code",[e._v("kube-apiserver")]),e._v("、"),s("code",[e._v("kube-controller-manager")]),e._v(" 和 "),s("code",[e._v("kube-scheduler")]),e._v("。")]),e._v(" "),s("p",[e._v("集群中的每个非 master 节点都运行两个进程:")]),e._v(" "),s("ul",[s("li",[e._v("kubelet,和 master 节点进行通信。")]),e._v(" "),s("li",[e._v("kube-proxy,一种网络代理,将 Kubernetes 的网络服务代理到每个节点上。")])]),e._v(" "),s("h3",{attrs:{id:"k8s-功能"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#k8s-功能"}},[e._v("#")]),e._v(" K8S 功能")]),e._v(" "),s("ul",[s("li",[e._v("基于容器的应用部署、维护和滚动升级")]),e._v(" "),s("li",[e._v("负载均衡和服务发现")]),e._v(" "),s("li",[e._v("跨机器和跨地区的集群调度")]),e._v(" "),s("li",[e._v("自动伸缩")]),e._v(" "),s("li",[e._v("无状态服务和有状态服务")]),e._v(" "),s("li",[e._v("广泛的 Volume 支持")]),e._v(" "),s("li",[e._v("插件机制保证扩展性")])]),e._v(" "),s("h3",{attrs:{id:"k8s-核心组件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#k8s-核心组件"}},[e._v("#")]),e._v(" K8S 核心组件")]),e._v(" "),s("p",[e._v("Kubernetes 主要由以下几个核心组件组成:")]),e._v(" "),s("ul",[s("li",[e._v("etcd 保存了整个集群的状态;")]),e._v(" "),s("li",[e._v("apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;")]),e._v(" "),s("li",[e._v("controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;")]),e._v(" "),s("li",[e._v("scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;")]),e._v(" "),s("li",[e._v("kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;")]),e._v(" "),s("li",[e._v("Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);")]),e._v(" "),s("li",[e._v("kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡")])]),e._v(" "),s("p",[s("img",{attrs:{src:"https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-LDAOok5ngY4pc1lEDes%2F-LpOIkR-zouVcB8QsFj_%2F-LpOIpZIYxaDoF-FJMZk%2Farchitecture.png?generation=1569161437087842&alt=media",alt:"img"}})]),e._v(" "),s("h3",{attrs:{id:"k8s-核心概念"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#k8s-核心概念"}},[e._v("#")]),e._v(" K8S 核心概念")]),e._v(" "),s("p",[e._v("K8S 包含若干抽象用来表示系统状态,包括:已部署的容器化应用和负载、与它们相关的网络和磁盘资源以及有关集群正在运行的其他操作的信息。")]),e._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/kubernetes/pod.svg",alt:"img"}})]),e._v(" "),s("ul",[s("li",[s("code",[e._v("Pod")]),e._v(" - K8S 使用 Pod 来管理容器,每个 Pod 可以包含一个或多个紧密关联的容器。Pod 是一组紧密关联的容器集合,它们共享 PID、IPC、Network 和 UTS namespace,是 K8S 调度的基本单位。Pod 内的多个容器共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。")]),e._v(" "),s("li",[s("code",[e._v("Node")]),e._v(" - Node 是 Pod 真正运行的主机,可以是物理机,也可以是虚拟机。为了管理 Pod,每个 Node 节点上至少要运行 container runtime(比如 docker 或者 rkt)、"),s("code",[e._v("kubelet")]),e._v(" 和 "),s("code",[e._v("kube-proxy")]),e._v(" 服务。")]),e._v(" "),s("li",[s("code",[e._v("Namespace")]),e._v(" - Namespace 是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的 pods, services, replication controllers 和 deployments 等都是属于某一个 namespace 的(默认是 default),而 node, persistentVolumes 等则不属于任何 namespace。")]),e._v(" "),s("li",[s("code",[e._v("Service")]),e._v(" - Service 是应用服务的抽象,通过 labels 为应用提供负载均衡和服务发现。匹配 labels 的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上。每个 Service 都会自动分配一个 cluster IP(仅在集群内部可访问的虚拟地址)和 DNS 名,其他容器可以通过该地址或 DNS 来访问服务,而不需要了解后端容器的运行。")]),e._v(" "),s("li",[s("code",[e._v("Label")]),e._v(" - Label 是识别 K8S 对象的标签,以 key/value 的方式附加到对象上(key 最长不能超过 63 字节,value 可以为空,也可以是不超过 253 字节的字符串)。Label 不提供唯一性,并且实际上经常是很多对象(如 Pods)都使用相同的 label 来标志具体的应用。Label 定义好后其他对象可以使用 Label Selector 来选择一组相同 label 的对象(比如 ReplicaSet 和 Service 用 label 来选择一组 Pod)。Label Selector 支持以下几种方式:\n"),s("ul",[s("li",[e._v("等式,如 "),s("code",[e._v("app=nginx")]),e._v(" 和 "),s("code",[e._v("env!=production")])]),e._v(" "),s("li",[e._v("集合,如 "),s("code",[e._v("env in (production, qa)")])]),e._v(" "),s("li",[e._v("多个 label(它们之间是 AND 关系),如 "),s("code",[e._v("app=nginx,env=test")])])])]),e._v(" "),s("li",[s("code",[e._v("Annotations")]),e._v(" - Annotations 是 key/value 形式附加于对象的注解。不同于 Labels 用于标志和选择对象,Annotations 则是用来记录一些附加信息,用来辅助应用部署、安全策略以及调度策略等。比如 deployment 使用 annotations 来记录 rolling update 的状态。")])]),e._v(" "),s("h2",{attrs:{id:"二、k8s-命令"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二、k8s-命令"}},[e._v("#")]),e._v(" 二、K8S 命令")]),e._v(" "),s("h3",{attrs:{id:"客户端配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#客户端配置"}},[e._v("#")]),e._v(" 客户端配置")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Setup autocomplete in bash; bash-completion package should be installed first")]),e._v("\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("source")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("kubectl completion "),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("bash")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# View Kubernetes config")]),e._v("\nkubectl config view\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# View specific config items by json path")]),e._v("\nkubectl config view -o "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("jsonpath")]),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[e._v("'{.users[?(@.name == \"k8s\")].user.password}'")]),e._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Set credentials for foo.kuberntes.com")]),e._v("\nkubectl config set-credentials kubeuser/foo.kubernetes.com --username"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("kubeuser --password"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("kubepassword\n")])])]),s("h3",{attrs:{id:"查找资源"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查找资源"}},[e._v("#")]),e._v(" 查找资源")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# List all services in the namespace")]),e._v("\nkubectl get services\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# List all pods in all namespaces in wide format")]),e._v("\nkubectl get pods -o wide --all-namespaces\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# List all pods in json (or yaml) format")]),e._v("\nkubectl get pods -o json\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Describe resource details (node, pod, svc)")]),e._v("\nkubectl describe nodes my-node\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# List services sorted by name")]),e._v("\nkubectl get services --sort-by"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(".metadata.name\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# List pods sorted by restart count")]),e._v("\nkubectl get pods --sort-by"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token string"}},[e._v("'.status.containerStatuses[0].restartCount'")]),e._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Rolling update pods for frontend-v1")]),e._v("\nkubectl rolling-update frontend-v1 -f frontend-v2.json\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Scale a replicaset named 'foo' to 3")]),e._v("\nkubectl scale --replicas"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("3")]),e._v(" rs/foo\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v('# Scale a resource specified in "foo.yaml" to 3')]),e._v("\nkubectl scale --replicas"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("3")]),e._v(" -f foo.yaml\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Execute a command in every pod / replica")]),e._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("for")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token for-or-select variable"}},[e._v("i")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("in")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("do")]),e._v(" kubectl "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("exec")]),e._v(" foo-"),s("span",{pre:!0,attrs:{class:"token variable"}},[e._v("$i")]),e._v(" -- "),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("sh")]),e._v(" -c "),s("span",{pre:!0,attrs:{class:"token string"}},[e._v("'echo "),s("span",{pre:!0,attrs:{class:"token variable"}},[s("span",{pre:!0,attrs:{class:"token variable"}},[e._v("$(")]),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("hostname")]),s("span",{pre:!0,attrs:{class:"token variable"}},[e._v(")")])]),e._v(" > /usr/share/nginx/html/index.html'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(";")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("done")]),e._v("\n")])])]),s("h3",{attrs:{id:"资源管理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#资源管理"}},[e._v("#")]),e._v(" 资源管理")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Get documentation for pod or service")]),e._v("\nkubectl explain pods,svc\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Create resource(s) like pods, services or daemonsets")]),e._v("\nkubectl create -f ./my-manifest.yaml\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Apply a configuration to a resource")]),e._v("\nkubectl apply -f ./my-manifest.yaml\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Start a single instance of Nginx")]),e._v("\nkubectl run nginx --image"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("nginx\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Create a secret with several keys")]),e._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<<")]),s("span",{pre:!0,attrs:{class:"token string"}},[e._v("EOF"),s("span",{pre:!0,attrs:{class:"token bash punctuation"}},[e._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" kubectl create -f -")]),e._v("\napiVersion: v1\nkind: Secret\nmetadata:\n name: mysecret\ntype: Opaque\ndata:\n password: "),s("span",{pre:!0,attrs:{class:"token variable"}},[s("span",{pre:!0,attrs:{class:"token variable"}},[e._v("$(")]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("echo")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[e._v('"s33msi4"')]),e._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" base64"),s("span",{pre:!0,attrs:{class:"token variable"}},[e._v(")")])]),e._v("\n username: "),s("span",{pre:!0,attrs:{class:"token variable"}},[s("span",{pre:!0,attrs:{class:"token variable"}},[e._v("$(")]),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("echo")]),e._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[e._v('"jane"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" base64"),s("span",{pre:!0,attrs:{class:"token variable"}},[e._v(")")])]),e._v("\nEOF")]),e._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Delete a resource")]),e._v("\nkubectl delete -f ./my-manifest.yaml\n")])])]),s("h3",{attrs:{id:"监控和日志"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#监控和日志"}},[e._v("#")]),e._v(" 监控和日志")]),e._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Deploy Heapster from Github repository")]),e._v("\nkubectl create -f deploy/kube-config/standalone/\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Show metrics for nodes")]),e._v("\nkubectl "),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("top")]),e._v(" node\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Show metrics for pods")]),e._v("\nkubectl "),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("top")]),e._v(" pod\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Show metrics for a given pod and its containers")]),e._v("\nkubectl "),s("span",{pre:!0,attrs:{class:"token function"}},[e._v("top")]),e._v(" pod pod_name --containers\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Dump pod logs (stdout)")]),e._v("\nkubectl logs pod_name\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Stream pod container logs (stdout, multi-container case)")]),e._v("\nkubectl logs -f pod_name -c my-container\n")])])]),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[e._v("#")]),e._v(" 参考资料")]),e._v(" "),s("ul",[s("li",[s("strong",[e._v("官方")]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://github.com/kubernetes/kubernetes",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kubernetes Github"),s("OutboundLink")],1)]),e._v(" "),s("li",[s("a",{attrs:{href:"https://kubernetes.io/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kubernetes 官网"),s("OutboundLink")],1)])])]),e._v(" "),s("li",[s("strong",[e._v("教程")]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://jimmysong.io/kubernetes-handbook/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kubernetes 中文指南"),s("OutboundLink")],1)]),e._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/rootsongjc/kubernetes-handbook",target:"_blank",rel:"noopener noreferrer"}},[e._v("kubernetes-handbook"),s("OutboundLink")],1)])])]),e._v(" "),s("li",[s("strong",[e._v("文章")]),e._v(" "),s("ul",[s("li",[e._v("https://github.com/LeCoupa/awesome-cheatsheets/blob/master/tools/kubernetes.sh")])])]),e._v(" "),s("li",[s("strong",[e._v("更多资源")]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://github.com/ramitsurana/awesome-kubernetes",target:"_blank",rel:"noopener noreferrer"}},[e._v("awesome-kubernetes"),s("OutboundLink")],1)])])])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/17.d43e9f56.js b/assets/js/17.d43e9f56.js new file mode 100644 index 0000000..be905e0 --- /dev/null +++ b/assets/js/17.d43e9f56.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{405:function(t,a,s){"use strict";s.r(a);var e=s(15),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"docker-安装-mysql"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#docker-安装-mysql"}},[t._v("#")]),t._v(" Docker 安装 MySQL")]),t._v(" "),s("blockquote",[s("p",[t._v("实测环境:Centos")])]),t._v(" "),s("h2",{attrs:{id:"查看可下载镜像"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查看可下载镜像"}},[t._v("#")]),t._v(" 查看可下载镜像")]),t._v(" "),s("div",{staticClass:"language-docker extra-class"},[s("pre",{pre:!0,attrs:{class:"language-docker"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# docker search mysql")]),t._v("\nINDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED\ndocker.io docker.io/mysql MySQL is a widely used"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" open"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("source relati"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 5757 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" \ndocker.io docker.io/mariadb MariaDB is a community"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("developed fork of M"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 1863 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" \ndocker.io docker.io/mysql/mysql"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("server Optimized MySQL Server Docker images. Crea"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 397 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n")])])]),s("h2",{attrs:{id:"选择下载官方镜像"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#选择下载官方镜像"}},[t._v("#")]),t._v(" 选择下载官方镜像")]),t._v(" "),s("p",[t._v("比如,我想下载最新版本,则执行如下命令:")]),t._v(" "),s("div",{staticClass:"language-docker extra-class"},[s("pre",{pre:!0,attrs:{class:"language-docker"}},[s("code",[t._v("docker pull mysql\n")])])]),s("h2",{attrs:{id:"使用镜像"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#使用镜像"}},[t._v("#")]),t._v(" 使用镜像")]),t._v(" "),s("div",{staticClass:"language-docker extra-class"},[s("pre",{pre:!0,attrs:{class:"language-docker"}},[s("code",[t._v("docker run "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("p 3306"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("3306 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("name mysql "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("v /opt/docker_v/mysql/conf"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("/etc/mysql/conf.d "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("e MYSQL_ROOT_PASSWORD=123456 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("d mysql\n")])])]),s("h2",{attrs:{id:"资源"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#资源"}},[t._v("#")]),t._v(" 资源")]),t._v(" "),s("ul",[s("li",[t._v("https://hub.docker.com/_/mysql/")])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/18.aa00ff43.js b/assets/js/18.aa00ff43.js new file mode 100644 index 0000000..0869e80 --- /dev/null +++ b/assets/js/18.aa00ff43.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{406:function(t,n,a){"use strict";a.r(n);var s=a(15),e=Object(s.a)({},(function(){var t=this,n=t.$createElement,a=t._self._c||n;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"docker-安装-nginx"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#docker-安装-nginx"}},[t._v("#")]),t._v(" Docker 安装 Nginx")]),t._v(" "),a("blockquote",[a("p",[t._v("实测环境:Centos")])]),t._v(" "),a("h2",{attrs:{id:"查看可用镜像"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#查看可用镜像"}},[t._v("#")]),t._v(" 查看可用镜像")]),t._v(" "),a("p",[t._v("执行 "),a("code",[t._v("docker search nginx")]),t._v(" 命令查看可用镜像:")]),t._v(" "),a("div",{staticClass:"language-docker extra-class"},[a("pre",{pre:!0,attrs:{class:"language-docker"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# docker search nginx")]),t._v("\nINDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED\ndocker.io docker.io/nginx Official build of Nginx. 8272 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" \ndocker.io docker.io/jwilder/nginx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("proxy Automated Nginx reverse proxy for docker c"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 1300 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\ndocker.io docker.io/richarvey/nginx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("php"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("fpm Container running Nginx + PHP"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("FPM capable "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 540 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\ndocker.io docker.io/jrcs/letsencrypt"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("nginx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("proxy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("companion LetsEncrypt container to use with nginx as"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v(" 336 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("OK"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("...")]),t._v("\n")])])]),a("h2",{attrs:{id:"选择下载镜像"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选择下载镜像"}},[t._v("#")]),t._v(" 选择下载镜像")]),t._v(" "),a("p",[t._v("执行 "),a("code",[t._v("docker pull nginx")]),t._v(" 命令下载镜像")]),t._v(" "),a("h2",{attrs:{id:"运行镜像"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#运行镜像"}},[t._v("#")]),t._v(" 运行镜像")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("docker run -p 80:80 --name mynginx -d nginx\n")])])])])}),[],!1,null,null,null);n.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/19.43ce44b3.js b/assets/js/19.43ce44b3.js new file mode 100644 index 0000000..2db8ceb --- /dev/null +++ b/assets/js/19.43ce44b3.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{407:function(e,v,_){"use strict";_.r(v);var o=_(15),t=Object(o.a)({},(function(){var e=this,v=e.$createElement,_=e._self._c||v;return _("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[_("h1",{attrs:{id:"linux-命令行"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#linux-命令行"}},[e._v("#")]),e._v(" Linux 命令行")]),e._v(" "),_("blockquote",[_("p",[e._v("学习 Linux 的第一步:当然是从 Linux 命令入手了。")])]),e._v(" "),_("h2",{attrs:{id:"📖-内容"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#📖-内容"}},[e._v("#")]),e._v(" 📖 内容")]),e._v(" "),_("ul",[_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-help.html"}},[e._v("查看 Linux 命令帮助信息")]),e._v(" - 关键词:"),_("code",[e._v("help")]),e._v(", "),_("code",[e._v("whatis")]),e._v(", "),_("code",[e._v("info")]),e._v(", "),_("code",[e._v("which")]),e._v(", "),_("code",[e._v("whereis")]),e._v(", "),_("code",[e._v("man")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-dir.html"}},[e._v("Linux 文件目录管理")]),e._v(" - 关键词:"),_("code",[e._v("cd")]),e._v(", "),_("code",[e._v("ls")]),e._v(", "),_("code",[e._v("pwd")]),e._v(", "),_("code",[e._v("mkdir")]),e._v(", "),_("code",[e._v("rmdir")]),e._v(", "),_("code",[e._v("tree")]),e._v(", "),_("code",[e._v("touch")]),e._v(", "),_("code",[e._v("ln")]),e._v(", "),_("code",[e._v("rename")]),e._v(", "),_("code",[e._v("stat")]),e._v(", "),_("code",[e._v("file")]),e._v(", "),_("code",[e._v("chmod")]),e._v(", "),_("code",[e._v("chown")]),e._v(", "),_("code",[e._v("locate")]),e._v(", "),_("code",[e._v("find")]),e._v(", "),_("code",[e._v("cp")]),e._v(", "),_("code",[e._v("mv")]),e._v(", "),_("code",[e._v("rm")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-file.html"}},[e._v("Linux 文件内容查看命令")]),e._v(" - 关键词:"),_("code",[e._v("cat")]),e._v(", "),_("code",[e._v("head")]),e._v(", "),_("code",[e._v("tail")]),e._v(", "),_("code",[e._v("more")]),e._v(", "),_("code",[e._v("less")]),e._v(", "),_("code",[e._v("sed")]),e._v(", "),_("code",[e._v("vi")]),e._v(", "),_("code",[e._v("grep")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-file-compress.html"}},[e._v("Linux 文件压缩和解压")]),e._v(" - 关键词:"),_("code",[e._v("tar")]),e._v(", "),_("code",[e._v("gzip")]),e._v(", "),_("code",[e._v("zip")]),e._v(", "),_("code",[e._v("unzip")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-user.html"}},[e._v("Linux 用户管理")]),e._v(" - 关键词:"),_("code",[e._v("groupadd")]),e._v(", "),_("code",[e._v("groupdel")]),e._v(", "),_("code",[e._v("groupmod")]),e._v(", "),_("code",[e._v("useradd")]),e._v(", "),_("code",[e._v("userdel")]),e._v(", "),_("code",[e._v("usermod")]),e._v(", "),_("code",[e._v("passwd")]),e._v(", "),_("code",[e._v("su")]),e._v(", "),_("code",[e._v("sudo")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-system.html"}},[e._v("Linux 系统管理")]),e._v(" - 关键词:"),_("code",[e._v("reboot")]),e._v(", "),_("code",[e._v("exit")]),e._v(", "),_("code",[e._v("shutdown")]),e._v(", "),_("code",[e._v("date")]),e._v(", "),_("code",[e._v("mount")]),e._v(", "),_("code",[e._v("umount")]),e._v(", "),_("code",[e._v("ps")]),e._v(", "),_("code",[e._v("kill")]),e._v(", "),_("code",[e._v("systemctl")]),e._v(", "),_("code",[e._v("service")]),e._v(", "),_("code",[e._v("crontab")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-net.html"}},[e._v("Linux 网络管理")]),e._v(" - 关键词:关键词:"),_("code",[e._v("curl")]),e._v(", "),_("code",[e._v("wget")]),e._v(", "),_("code",[e._v("telnet")]),e._v(", "),_("code",[e._v("ip")]),e._v(", "),_("code",[e._v("hostname")]),e._v(", "),_("code",[e._v("ifconfig")]),e._v(", "),_("code",[e._v("route")]),e._v(", "),_("code",[e._v("ssh")]),e._v(", "),_("code",[e._v("ssh-keygen")]),e._v(", "),_("code",[e._v("firewalld")]),e._v(", "),_("code",[e._v("iptables")]),e._v(", "),_("code",[e._v("host")]),e._v(", "),_("code",[e._v("nslookup")]),e._v(", "),_("code",[e._v("nc")]),e._v("/"),_("code",[e._v("netcat")]),e._v(", "),_("code",[e._v("ping")]),e._v(", "),_("code",[e._v("traceroute")]),e._v(", "),_("code",[e._v("netstat")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-hardware.html"}},[e._v("Linux 硬件管理")]),e._v(" - 关键词:"),_("code",[e._v("df")]),e._v(", "),_("code",[e._v("du")]),e._v(", "),_("code",[e._v("top")]),e._v(", "),_("code",[e._v("free")]),e._v(", "),_("code",[e._v("iotop")])],1),e._v(" "),_("li",[_("RouterLink",{attrs:{to:"/linux/cli/linux-cli-hardware.html"}},[e._v("Linux 软件管理")]),e._v(" - 关键词:"),_("code",[e._v("rpm")]),e._v(", "),_("code",[e._v("yum")]),e._v(", "),_("code",[e._v("apt-get")])],1)]),e._v(" "),_("h2",{attrs:{id:"📚-资料"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#📚-资料"}},[e._v("#")]),e._v(" 📚 资料")]),e._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://github.com/jlevy/the-art-of-command-line/blob/master/README-zh.md",target:"_blank",rel:"noopener noreferrer"}},[e._v("命令行的艺术"),_("OutboundLink")],1)]),e._v(" "),_("li",[_("a",{attrs:{href:"https://man.linuxde.net/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linux命令大全"),_("OutboundLink")],1)]),e._v(" "),_("li",[_("a",{attrs:{href:"https://github.com/jaywcjlove/linux-command",target:"_blank",rel:"noopener noreferrer"}},[e._v("linux-command"),_("OutboundLink")],1)])]),e._v(" "),_("h2",{attrs:{id:"🚪-传送门"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#🚪-传送门"}},[e._v("#")]),e._v(" 🚪 传送门")]),e._v(" "),_("p",[e._v("◾ 🏠 "),_("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[e._v("DB-TUTORIAL 首页"),_("OutboundLink")],1),e._v(" ◾ 🎯 "),_("a",{attrs:{href:"https://github.com/dunwu/blog",target:"_blank",rel:"noopener noreferrer"}},[e._v("我的博客"),_("OutboundLink")],1),e._v(" ◾")])])}),[],!1,null,null,null);v.default=t.exports}}]); \ No newline at end of file diff --git a/assets/js/20.5618e1ff.js b/assets/js/20.5618e1ff.js new file mode 100644 index 0000000..b016fbe --- /dev/null +++ b/assets/js/20.5618e1ff.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{408:function(e,s,a){"use strict";a.r(s);var t=a(15),n=Object(t.a)({},(function(){var e=this,s=e.$createElement,a=e._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"free"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#free"}},[e._v("#")]),e._v(" free")]),e._v(" "),a("p",[e._v("显示内存的使用情况")]),e._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[e._v("#")]),e._v(" 补充说明")]),e._v(" "),a("p",[a("strong",[e._v("free 命令")]),e._v(" 可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。")]),e._v(" "),a("h3",{attrs:{id:"语法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[e._v("#")]),e._v(" 语法")]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[e._v("free"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("选项"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n")])])]),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[e._v("#")]),e._v(" 选项")]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[e._v("-b "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 以Byte为单位显示内存使用情况;")]),e._v("\n-k "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 以KB为单位显示内存使用情况;")]),e._v("\n-m "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 以MB为单位显示内存使用情况;")]),e._v("\n-g "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 以GB为单位显示内存使用情况。")]),e._v("\n-o "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 不显示缓冲区调节列;")]),e._v("\n-s"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<")]),e._v("间隔秒数"),a("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 持续观察内存使用状况;")]),e._v("\n-t "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 显示内存总和列;")]),e._v("\n-V "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 显示版本信息。")]),e._v("\n")])])]),a("h3",{attrs:{id:"实例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[e._v("#")]),e._v(" 实例")]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("free")]),e._v(" -t "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 以总和的形式显示内存的使用信息")]),e._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("free")]),e._v(" -s "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("10")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 周期性的查询内存使用信息,每10s 执行一次命令")]),e._v("\n")])])]),a("p",[e._v("显示内存使用情况")]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("free")]),e._v(" -m\n total used "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("free")]),e._v(" shared buffers cached\nMem: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2016")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1973")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("42")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("163")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1497")]),e._v("\n-/+ buffers/cache: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("312")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1703")]),e._v("\nSwap: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("4094")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("4094")]),e._v("\n")])])]),a("p",[a("strong",[e._v("第一部分 Mem 行解释:")])]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[e._v("total:内存总数;\nused:已经使用的内存数;\nfree:空闲的内存数;\nshared:当前已经废弃不用;\nbuffers Buffer:缓存内存数;\ncached Page:缓存内存数。\n")])])]),a("p",[e._v("关系:total = used + free")]),e._v(" "),a("p",[a("strong",[e._v("第二部分(-/+ buffers/cache)解释:")])]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("-buffers/cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" used内存数:第一部分Mem行中的 used – buffers – cached\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("+buffers/cache"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" free内存数: 第一部分Mem行中的 "),a("span",{pre:!0,attrs:{class:"token function"}},[e._v("free")]),e._v(" + buffers + cached\n")])])]),a("p",[e._v("可见-buffers/cache 反映的是被程序实实在在吃掉的内存,而+buffers/cache 反映的是可以挪用的内存总数。")]),e._v(" "),a("p",[e._v("第三部分是指交换分区。")]),e._v(" "),a("p",[e._v("输出结果的第四行是交换分区 SWAP 的,也就是我们通常所说的虚拟内存。\n区别:第二行(mem)的 used/free 与第三行(-/+ buffers/cache) used/free 的区别。 这两个的区别在于使用的角度来看,第一行是从 OS 的角度来看,因为对于 OS,buffers/cached 都是属于被使用,所以他的可用内存是 2098428KB,已用内存是 30841684KB,其中包括,内核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached.")]),e._v(" "),a("p",[e._v("第三行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为 buffer/cached 是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached 会很快地被回收。")]),e._v(" "),a("p",[e._v("所以从应用程序的角度来说,可用内存=系统 free memory+buffers+cached。\n如本机情况的可用内存为:")]),e._v(" "),a("p",[e._v("18007156=2098428KB+4545340KB+11363424KB")]),e._v(" "),a("p",[e._v("接下来解释什么时候内存会被交换,以及按什么方交换。")]),e._v(" "),a("p",[e._v("当可用内存少于额定值的时候,就会开会进行交换。如何看额定值:")]),e._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" /proc/meminfo\n\nMemTotal: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("16140816")]),e._v(" kB\nMemFree: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("816004")]),e._v(" kB\nMemAvailable: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2913824")]),e._v(" kB\nBuffers: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("17912")]),e._v(" kB\nCached: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2239076")]),e._v(" kB\nSwapCached: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nActive: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("12774804")]),e._v(" kB\nInactive: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1594328")]),e._v(" kB\nActive"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("anon"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(": "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("12085544")]),e._v(" kB\nInactive"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("anon"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(": "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("94572")]),e._v(" kB\nActive"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("file"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(": "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("689260")]),e._v(" kB\nInactive"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("file"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(": "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("1499756")]),e._v(" kB\nUnevictable: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("116888")]),e._v(" kB\nMlocked: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("116888")]),e._v(" kB\nSwapTotal: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("8191996")]),e._v(" kB\nSwapFree: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("8191996")]),e._v(" kB\nDirty: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("56")]),e._v(" kB\nWriteback: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nAnonPages: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("12229228")]),e._v(" kB\nMapped: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("117136")]),e._v(" kB\nShmem: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("58736")]),e._v(" kB\nSlab: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("395568")]),e._v(" kB\nSReclaimable: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("246700")]),e._v(" kB\nSUnreclaim: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("148868")]),e._v(" kB\nKernelStack: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("30496")]),e._v(" kB\nPageTables: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("165104")]),e._v(" kB\nNFS_Unstable: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nBounce: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nWritebackTmp: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nCommitLimit: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("16262404")]),e._v(" kB\nCommitted_AS: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("27698600")]),e._v(" kB\nVmallocTotal: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("34359738367")]),e._v(" kB\nVmallocUsed: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("311072")]),e._v(" kB\nVmallocChunk: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("34350899200")]),e._v(" kB\nHardwareCorrupted: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v(" kB\nAnonHugePages: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("3104768")]),e._v(" kB\nHugePages_Total: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v("\nHugePages_Free: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v("\nHugePages_Rsvd: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v("\nHugePages_Surp: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("0")]),e._v("\nHugepagesize: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("2048")]),e._v(" kB\nDirectMap4k: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("225536")]),e._v(" kB\nDirectMap2M: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("13279232")]),e._v(" kB\nDirectMap1G: "),a("span",{pre:!0,attrs:{class:"token number"}},[e._v("5242880")]),e._v(" kB\n")])])]),a("p",[e._v("交换将通过三个途径来减少系统中使用的物理页面的个数:")]),e._v(" "),a("ol",[a("li",[e._v("减少缓冲与页面 cache 的大小,")]),e._v(" "),a("li",[e._v("将系统 V 类型的内存页面交换出去,")]),e._v(" "),a("li",[e._v("换出或者丢弃页面。(Application 占用的内存页,也就是物理内存不足)。")])]),e._v(" "),a("p",[e._v("事实上,少量地使用 swap 是不是影响到系统性能的。")]),e._v(" "),a("p",[e._v("那 buffers 和 cached 都是缓存,两者有什么区别呢?")]),e._v(" "),a("p",[e._v("为了提高磁盘存取效率, Linux 做了一些精心的设计, 除了对 dentry 进行缓存(用于 VFS,加速文件路径名到 inode 的转换), 还采取了两种主要 Cache 方式:")]),e._v(" "),a("p",[e._v("Buffer Cache 和 Page Cache。前者针对磁盘块的读写,后者针对文件 inode 的读写。这些 Cache 有效缩短了 I/O 系统调用(比如 read,write,getdents)的时间。\n磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种 Cache 就是分别缓存逻辑和物理级数据的。")]),e._v(" "),a("p",[e._v("Page cache 实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到 page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当 page cache 的数据需要刷新时,page cache 中的数据交给 buffer cache,因为 Buffer Cache 就是缓存磁盘块的。但是这种处理在 2.6 版本的内核之后就变的很简单了,没有真正意义上的 cache 操作。")]),e._v(" "),a("p",[e._v("Buffer cache 是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到 buffer cache 中,例如,文件系统的元数据都会缓存到 buffer cache 中。")]),e._v(" "),a("p",[e._v("简单说来,page cache 用来缓存文件数据,buffer cache 用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到 page cache,如果直接采用 dd 等工具对磁盘进行读写,那么数据会缓存到 buffer cache。")]),e._v(" "),a("p",[e._v("所以我们看 linux,只要不用 swap 的交换空间,就不用担心自己的内存太少.如果常常 swap 用很多,可能你就要考虑加物理内存了.这也是 linux 看内存是否够用的标准.")]),e._v(" "),a("p",[e._v("如果是应用服务器的话,一般只看第二行,+buffers/cache,即对应用程序来说 free 的内存太少了,也是该考虑优化程序或加内存了。")])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/21.1c5a41d7.js b/assets/js/21.1c5a41d7.js new file mode 100644 index 0000000..8dd80af --- /dev/null +++ b/assets/js/21.1c5a41d7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{409:function(s,t,a){"use strict";a.r(t);var e=a(15),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"grep"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#grep"}},[s._v("#")]),s._v(" grep")]),s._v(" "),a("p",[s._v("强大的文本搜索工具")]),s._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[s._v("#")]),s._v(" 补充说明")]),s._v(" "),a("p",[a("strong",[s._v("grep")]),s._v(" (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。")]),s._v(" "),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[s._v("#")]),s._v(" 选项")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("-a --text "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 不要忽略二进制数据。")]),s._v("\n-A "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --after-context"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 除了显示符合范本样式的那一行之外,并显示该行之后的内容。")]),s._v("\n-b --byte-offset "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在显示符合范本样式的那一行之外,并显示该行之前的内容。")]),s._v("\n-B"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --before-context"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 除了显示符合样式的那一行之外,并显示该行之前的内容。")]),s._v("\n-c --count "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 计算符合范本样式的列数。")]),s._v("\n-C"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --context"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v("或-"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("显示行数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。")]),s._v("\n-d"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("进行动作"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --directories"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("动作"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。")]),s._v("\n-e"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("范本样式"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --regexp"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("范本样式"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定字符串作为查找文件内容的范本样式。")]),s._v("\n-E --extended-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。")]),s._v("\n-f"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("范本文件"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --file"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("规则文件"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。")]),s._v("\n-F --fixed-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将范本样式视为固定字符串的列表。")]),s._v("\n-G --basic-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将范本样式视为普通的表示法来使用。")]),s._v("\n-h --no-filename "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。")]),s._v("\n-H --with-filename "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在显示符合范本样式的那一列之前,标示该列的文件名称。")]),s._v("\n-i --ignore-case "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 忽略字符大小写的差别。")]),s._v("\n-l --file-with-matches "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出文件内容符合指定的范本样式的文件名称。")]),s._v("\n-L --files-without-match "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出文件内容不符合指定的范本样式的文件名称。")]),s._v("\n-n --line-number "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在显示符合范本样式的那一列之前,标示出该列的编号。")]),s._v("\n-P --perl-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# PATTERN 是一个 Perl 正则表达式")]),s._v("\n-q --quiet或--silent "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 不显示任何信息。")]),s._v("\n-R/-r --recursive "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 此参数的效果和指定“-d recurse”参数相同。")]),s._v("\n-s --no-messages "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 不显示错误信息。")]),s._v("\n-v --revert-match "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 反转查找。")]),s._v("\n-V --version "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示版本信息。")]),s._v("\n-w --word-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 只显示全字符合的列。")]),s._v("\n-x --line-regexp "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 只显示全列符合的列。")]),s._v("\n-y "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 此参数效果跟“-i”相同。")]),s._v("\n-o "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 只输出文件中匹配到的部分。")]),s._v("\n-m "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("num"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" --max-count"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("num"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 找到num行结果后停止查找,用来限制匹配行数")]),s._v("\n")])])]),a("h3",{attrs:{id:"规则表达式"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#规则表达式"}},[s._v("#")]),s._v(" 规则表达式")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("^ "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锚定行的开始 如:'^grep'匹配所有以grep开头的行。")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锚定行的结束 如:'grep$' 匹配所有以grep结尾的行。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。")]),s._v("\n* "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。")]),s._v("\n.* "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 一起用代表任意字符。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("^"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 标记匹配字符,如'\\(love\\)',love被标记为1。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锚定单词的开始,如:'\\")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锚定单词的结束,如'grep\\>'匹配包含以grep结尾的单词的行。")]),s._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("m"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 重复字符x,m次,如:'0\\{5\\}'匹配包含5个o的行。")]),s._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("m,"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 重复字符x,至少m次,如:'o\\{5,\\}'匹配至少有5个o的行。")]),s._v("\nx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("m,n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 重复字符x,至少m次,不多于n次,如:'o\\{5,10\\}'匹配5--10个o的行。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("w "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("W "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# \\w的反置形式,匹配一个或多个非单词字符,如点号句号等。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("\\")]),s._v("b "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 单词锁定符,如: '\\bgrep\\b'只匹配grep。")]),s._v("\n")])])]),a("h2",{attrs:{id:"grep-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#grep-命令常见用法"}},[s._v("#")]),s._v(" grep 命令常见用法")]),s._v(" "),a("p",[s._v("在文件中搜索一个单词,命令会返回一个包含 "),a("strong",[s._v("“match_pattern”")]),s._v(" 的文本行:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" match_pattern file_name\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"match_pattern"')]),s._v(" file_name\n")])])]),a("p",[s._v("在多个文件中查找:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"match_pattern"')]),s._v(" file_1 file_2 file_3 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n")])])]),a("p",[s._v("输出除之外的所有行 "),a("strong",[s._v("-v")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -v "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"match_pattern"')]),s._v(" file_name\n")])])]),a("p",[s._v("标记匹配颜色 "),a("strong",[s._v("--color=auto")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"match_pattern"')]),s._v(" file_name --color"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("auto\n")])])]),a("p",[s._v("使用正则表达式 "),a("strong",[s._v("-E")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -E "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"[1-9]+"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 或")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("egrep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"[1-9]+"')]),s._v("\n")])])]),a("p",[s._v("使用正则表达式 "),a("strong",[s._v("-P")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -P "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"(\\d{3}\\-){2}\\d{4}"')]),s._v(" file_name\n")])])]),a("p",[s._v("只输出文件中匹配到的部分 "),a("strong",[s._v("-o")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" this is a "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("test")]),s._v(" line. "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -o -E "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"[a-z]+\\."')]),s._v("\nline.\n\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" this is a "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("test")]),s._v(" line. "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("egrep")]),s._v(" -o "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"[a-z]+\\."')]),s._v("\nline.\n")])])]),a("p",[s._v("统计文件或者文本中包含匹配字符串的行数 "),a("strong",[s._v("-c")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" file_name\n")])])]),a("p",[s._v("输出包含匹配字符串的行数 "),a("strong",[s._v("-n")]),s._v(" 选项:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" -n file_name\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 或")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("cat")]),s._v(" file_name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" -n\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#多个文件")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" -n file_1 file_2\n")])])]),a("p",[s._v("打印样式匹配所位于的字符或字节偏移:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" gun is not unix "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -b -o "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"not"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v(":not\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#一行中字符串的字符便宜是从该行的第一个字符开始计算,起始值为0。选项 **-b -o** 一般总是配合使用。")]),s._v("\n")])])]),a("p",[s._v("搜索多个文件并查找匹配文本在哪些文件中:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -l "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" file1 file2 file3"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\n")])])]),a("h3",{attrs:{id:"grep-递归搜索文件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#grep-递归搜索文件"}},[s._v("#")]),s._v(" grep 递归搜索文件")]),s._v(" "),a("p",[s._v("在多级目录中对文本进行递归搜索:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"text"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r -n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# .表示当前目录。")]),s._v("\n")])])]),a("p",[s._v("忽略匹配样式中的字符大小写:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"hello world"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -i "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"HELLO"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# hello")]),s._v("\n")])])]),a("p",[s._v("选项 "),a("strong",[s._v("-e")]),s._v(" 制动多个匹配样式:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" this is a text line "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -e "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"is"')]),s._v(" -e "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"line"')]),s._v(" -o\nis\nline\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#也可以使用 **-f** 选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("cat")]),s._v(" patfile\naaa\nbbb\n\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" aaa bbb ccc ddd eee "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -f patfile -o\n")])])]),a("p",[s._v("在 grep 搜索结果中包括或者排除指定文件:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v('# 只在目录中所有的.php和.html文件中递归搜索字符"main()"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --include *."),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("php,html"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在搜索结果中排除所有README文件")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --exclude "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"README"')]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在搜索结果中排除filelist文件列表里的文件")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --exclude-from filelist\n\n")])])]),a("p",[s._v("使用 0 值字节后缀的 grep 与 xargs:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 测试文件:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"aaa"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" file1\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"bbb"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" file2\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"aaa"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" file3\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"aaa"')]),s._v(" file* -lZ "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("xargs")]),s._v(" -0 "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("rm")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 执行后会删除file1和file3,grep输出用-Z选项来指定以0值字节作为终结符文件名(\\0),xargs -0 读取输入并用0值字节终结符分隔文件名,然后删除匹配文件,-Z通常和-l结合使用。")]),s._v("\n")])])]),a("p",[s._v("grep 静默输出:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -q "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"test"')]),s._v(" filename\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 不会输出任何信息,如果命令运行成功返回0,失败则返回非0值。一般用于条件测试。")]),s._v("\n")])])]),a("p",[s._v("打印出匹配文本之前或者之后的行:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示匹配某个结果之后的3行,使用 -A 选项:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("seq")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"5"')]),s._v(" -A "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示匹配某个结果之前的3行,使用 -B 选项:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("seq")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"5"')]),s._v(" -B "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示匹配某个结果的前三行和后三行,使用 -C 选项:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("seq")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"5"')]),s._v(" -C "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" -e "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"a'),a("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v("b"),a("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v("c"),a("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v("a"),a("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v("b"),a("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v('c"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" a -A "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\na\nb\n--\na\nb\n")])])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/22.fbe9fdf1.js b/assets/js/22.fbe9fdf1.js new file mode 100644 index 0000000..649967b --- /dev/null +++ b/assets/js/22.fbe9fdf1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{410:function(t,s,a){"use strict";a.r(s);var v=a(15),_=Object(v.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"iostat"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#iostat"}},[t._v("#")]),t._v(" iostat")]),t._v(" "),a("p",[t._v("监视系统输入输出设备和 CPU 的使用情况")]),t._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[t._v("#")]),t._v(" 补充说明")]),t._v(" "),a("p",[a("strong",[t._v("iostat 命令")]),t._v(" 被用于监视系统输入输出设备和 CPU 的使用情况。它的特点是汇报磁盘活动统计情况,同时也会汇报出 CPU 使用情况。同 vmstat 一样,iostat 也有一个弱点,就是它不能对某个进程进行深入分析,仅对系统的整体情况进行分析。")]),t._v(" "),a("h3",{attrs:{id:"语法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[t._v("#")]),t._v(" 语法")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iostat"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("选项"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("参数"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[t._v("#")]),t._v(" 选项")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("-c:仅显示CPU使用情况;\n-d:仅显示设备利用率;\n-k:显示状态以千字节每秒为单位,而不使用块每秒;\n-m:显示状态以兆字节每秒为单位;\n-p:仅显示块设备和所有被使用的其他分区的状态;\n-t:显示每个报告产生时的时间;\n-V:显示版号并退出;\n-x:显示扩展状态。\n")])])]),a("h3",{attrs:{id:"参数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参数"}},[t._v("#")]),t._v(" 参数")]),t._v(" "),a("ul",[a("li",[t._v("间隔时间:每次报告的间隔时间(秒);")]),t._v(" "),a("li",[t._v("次数:显示报告的次数。")])]),t._v(" "),a("h3",{attrs:{id:"实例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[t._v("#")]),t._v(" 实例")]),t._v(" "),a("p",[t._v("用"),a("code",[t._v("iostat -x /dev/sda1")]),t._v("来观看磁盘 I/O 的详细情况:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iostat -x /dev/sda1\nLinux "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2.6")]),t._v(".18-164.el5xen "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("localhost.localdomain"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2010")]),t._v("年03月26日\n\navg-cpu: %user %nice %system %iowait\n%steal %idle\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.11")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.02")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.18")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.35")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.03")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("99.31")]),t._v("\n\nDevice: tps Blk_read/s Blk_wrtn/s\nBlk_read Blk_wrtn\nsda1 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.02")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.08")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.00")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2014")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v("\n")])])]),a("p",[t._v("详细说明:第二行是系统信息和监测时间,第三行和第四行显示 CPU 使用情况(具体内容和 mpstat 命令相同)。这里主要关注后面 I/O 输出的信息,如下所示:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[t._v("标示")]),t._v(" "),a("th",[t._v("说明")])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("Device")]),t._v(" "),a("td",[t._v("监测设备名称")])]),t._v(" "),a("tr",[a("td",[t._v("rrqm/s")]),t._v(" "),a("td",[t._v("每秒需要读取需求的数量")])]),t._v(" "),a("tr",[a("td",[t._v("wrqm/s")]),t._v(" "),a("td",[t._v("每秒需要写入需求的数量")])]),t._v(" "),a("tr",[a("td",[t._v("r/s")]),t._v(" "),a("td",[t._v("每秒实际读取需求的数量")])]),t._v(" "),a("tr",[a("td",[t._v("w/s")]),t._v(" "),a("td",[t._v("每秒实际写入需求的数量")])]),t._v(" "),a("tr",[a("td",[t._v("rsec/s")]),t._v(" "),a("td",[t._v("每秒读取区段的数量")])]),t._v(" "),a("tr",[a("td",[t._v("wsec/s")]),t._v(" "),a("td",[t._v("每秒写入区段的数量")])]),t._v(" "),a("tr",[a("td",[t._v("rkB/s")]),t._v(" "),a("td",[t._v("每秒实际读取的大小,单位为 KB")])]),t._v(" "),a("tr",[a("td",[t._v("wkB/s")]),t._v(" "),a("td",[t._v("每秒实际写入的大小,单位为 KB")])]),t._v(" "),a("tr",[a("td",[t._v("avgrq-sz")]),t._v(" "),a("td",[t._v("需求的平均大小区段")])]),t._v(" "),a("tr",[a("td",[t._v("avgqu-sz")]),t._v(" "),a("td",[t._v("需求的平均队列长度")])]),t._v(" "),a("tr",[a("td",[t._v("await")]),t._v(" "),a("td",[t._v("等待 I/O 平均的时间(milliseconds)")])]),t._v(" "),a("tr",[a("td",[t._v("svctm")]),t._v(" "),a("td",[t._v("I/O 需求完成的平均时间")])]),t._v(" "),a("tr",[a("td",[t._v("%util")]),t._v(" "),a("td",[t._v("被 I/O 需求消耗的 CPU 百分比")])])])])])}),[],!1,null,null,null);s.default=_.exports}}]); \ No newline at end of file diff --git a/assets/js/23.a4fb0e74.js b/assets/js/23.a4fb0e74.js new file mode 100644 index 0000000..068fd98 --- /dev/null +++ b/assets/js/23.a4fb0e74.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{411:function(s,t,a){"use strict";a.r(t);var n=a(15),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"iotop"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#iotop"}},[s._v("#")]),s._v(" iotop")]),s._v(" "),a("p",[s._v("用来监视磁盘 I/O 使用状况的工具")]),s._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[s._v("#")]),s._v(" 补充说明")]),s._v(" "),a("p",[a("strong",[s._v("iotop 命令")]),s._v(" 是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。")]),s._v(" "),a("p",[s._v("iotop 使用 Python 语言编写而成,要求 Python2.5(及以上版本)和 Linux kernel2.6.20(及以上版本)。iotop 提供有源代码及 rpm 包,可从其官方主页下载。")]),s._v(" "),a("h3",{attrs:{id:"安装"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[s._v("#")]),s._v(" 安装")]),s._v(" "),a("p",[a("strong",[s._v("Ubuntu")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("apt-get")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" iotop\n")])])]),a("p",[a("strong",[s._v("CentOS")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("yum "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" iotop\n")])])]),a("p",[a("strong",[s._v("编译安装")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("wget")]),s._v(" http://guichaz.free.fr/iotop/files/iotop-0.4.4.tar.gz\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("tar")]),s._v(" zxf iotop-0.4.4.tar.gz\npython setup.py build\npython setup.py "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v("\n")])])]),a("h3",{attrs:{id:"语法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[s._v("#")]),s._v(" 语法")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("iotop(选项)\n")])])]),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[s._v("#")]),s._v(" 选项")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("-o:只显示有io操作的进程\n-b:批量显示,无交互,主要用作记录到文件。\n-n NUM:显示NUM次,主要用于非交互式模式。\n-d SEC:间隔SEC秒显示一次。\n-p PID:监控的进程pid。\n-u "),a("span",{pre:!0,attrs:{class:"token environment constant"}},[s._v("USER")]),s._v(":监控的进程用户。\n")])])]),a("p",[a("strong",[s._v("iotop 常用快捷键:")])]),s._v(" "),a("ol",[a("li",[s._v("左右箭头:改变排序方式,默认是按 IO 排序。")]),s._v(" "),a("li",[s._v("r:改变排序顺序。")]),s._v(" "),a("li",[s._v("o:只显示有 IO 输出的进程。")]),s._v(" "),a("li",[s._v("p:进程/线程的显示方式的切换。")]),s._v(" "),a("li",[s._v("a:显示累积使用量。")]),s._v(" "),a("li",[s._v("q:退出。")])]),s._v(" "),a("h3",{attrs:{id:"实例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[s._v("#")]),s._v(" 实例")]),s._v(" "),a("p",[s._v("直接执行 iotop 就可以看到效果了:")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("Total DISK read: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" Total DISK write: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s\n TID PRIO "),a("span",{pre:!0,attrs:{class:"token environment constant"}},[s._v("USER")]),s._v(" DISK READ DISK WRITE SWAPIN IO"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % init "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("kthreadd"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("migration/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("ksoftirqd/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("watchdog/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("migration/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("ksoftirqd/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("watchdog/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("events/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("events/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("khelper"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2572")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("bluetooth"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/24.e3a23b69.js b/assets/js/24.e3a23b69.js new file mode 100644 index 0000000..32afbd9 --- /dev/null +++ b/assets/js/24.e3a23b69.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{412:function(t,s,a){"use strict";a.r(s);var n=a(15),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"linux-文件目录管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linux-文件目录管理"}},[t._v("#")]),t._v(" Linux 文件目录管理")]),t._v(" "),a("blockquote",[a("p",[t._v("关键词:"),a("code",[t._v("cd")]),t._v(", "),a("code",[t._v("ls")]),t._v(", "),a("code",[t._v("pwd")]),t._v(", "),a("code",[t._v("mkdir")]),t._v(", "),a("code",[t._v("rmdir")]),t._v(", "),a("code",[t._v("tree")]),t._v(", "),a("code",[t._v("touch")]),t._v(", "),a("code",[t._v("ln")]),t._v(", "),a("code",[t._v("rename")]),t._v(", "),a("code",[t._v("stat")]),t._v(", "),a("code",[t._v("file")]),t._v(", "),a("code",[t._v("chmod")]),t._v(", "),a("code",[t._v("chown")]),t._v(", "),a("code",[t._v("locate")]),t._v(", "),a("code",[t._v("find")]),t._v(", "),a("code",[t._v("cp")]),t._v(", "),a("code",[t._v("scp")]),t._v(", "),a("code",[t._v("mv")]),t._v(", "),a("code",[t._v("rm")])])]),t._v(" "),a("h2",{attrs:{id:"_1-linux-文件目录工作机制"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-文件目录工作机制"}},[t._v("#")]),t._v(" 1. Linux 文件目录工作机制")]),t._v(" "),a("h3",{attrs:{id:"_1-1-linux-目录结构"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-linux-目录结构"}},[t._v("#")]),t._v(" 1.1. Linux 目录结构")]),t._v(" "),a("p",[t._v("linux 目录结构是树形结构,其根目录是 "),a("code",[t._v("/")]),t._v(" 。一张思维导图说明各个目录的作用:")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/linux-folders.png",alt:"img"}})]),t._v(" "),a("h3",{attrs:{id:"_1-2-linux-文件属性"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-linux-文件属性"}},[t._v("#")]),t._v(" 1.2. Linux 文件属性")]),t._v(" "),a("p",[t._v("Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。\n在 Linux 中我们可以使用 ll 或者 ls –l 命令来显示一个文件的属性以及文件所属的用户和组,如:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -l\ntotal "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v("\ndr-xr-xr-x "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" root root "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4096")]),t._v(" Dec "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2012")]),t._v(" bin\ndr-xr-xr-x "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v(" root root "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4096")]),t._v(" Apr "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2012")]),t._v(" boot\n")])])]),a("p",[t._v("实例中,bin 文件的第一个属性用 "),a("code",[t._v("d")]),t._v(" 表示。"),a("code",[t._v("d")]),t._v(" 在 Linux 中代表该文件是一个目录文件。\n在 Linux 中第一个字符代表这个文件是目录、文件或链接文件等等。")]),t._v(" "),a("ul",[a("li",[t._v("当为 "),a("code",[t._v("d")]),t._v(" 则是目录")]),t._v(" "),a("li",[t._v("当为 "),a("code",[t._v("-")]),t._v(" 则是文件;")]),t._v(" "),a("li",[t._v("若是 "),a("code",[t._v("l")]),t._v(" 则表示为链接文档(link file);")]),t._v(" "),a("li",[t._v("若是 "),a("code",[t._v("b")]),t._v(" 则表示为装置文件里面的可供储存的接口设备(可随机存取装置);")]),t._v(" "),a("li",[t._v("若是 "),a("code",[t._v("c")]),t._v(" 则表示为装置文件里面的串行端口设备,例如键盘、鼠标(一次性读取装置)。")])]),t._v(" "),a("p",[t._v("接下来的字符中,以三个为一组,且均为『rwx』 的三个参数的组合。其中,"),a("code",[t._v("r")]),t._v(" 代表可读(read)、"),a("code",[t._v("w")]),t._v(" 代表可写(write)、"),a("code",[t._v("x")]),t._v(" 代表可执行(execute)。 要注意的是,这三个权限的位置不会改变,如果没有权限,就会出现减号 "),a("code",[t._v("-")]),t._v(" 而已。")]),t._v(" "),a("p",[t._v("每个文件的属性由左边第一部分的 10 个字符来确定(如下图)。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20180920180927171909.png",alt:"img"}})]),t._v(" "),a("p",[t._v("从左至右用 0-9 这些数字来表示。")]),t._v(" "),a("ul",[a("li",[t._v("第 0 位确定文件类型")]),t._v(" "),a("li",[t._v("第 1-3 位确定属主(该文件的拥有者)拥有该文件的权限。")]),t._v(" "),a("li",[t._v("第 4-6 位确定属组(拥有者的同组用户)拥有该文件的权限。")]),t._v(" "),a("li",[t._v("第 7-9 位确定其他用户拥有该文件的权限。")]),t._v(" "),a("li",[t._v('第 1、4、7 位表示读权限,如果用"r"字符表示,则有读权限,如果用"-"字符表示,则没有读权限。')]),t._v(" "),a("li",[t._v('第 2、5、8 位表示写权限,如果用"w"字符表示,则有写权限,如果用"-"字符表示没有写权限。')]),t._v(" "),a("li",[t._v('第 3、6、9 位表示可执行权限,如果用"x"字符表示,则有执行权限,如果用"-"字符表示,则没有执行权限。')])]),t._v(" "),a("h4",{attrs:{id:"_1-2-1-linux-文件属主和属组"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-1-linux-文件属主和属组"}},[t._v("#")]),t._v(" 1.2.1. Linux 文件属主和属组")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -l\ntotal "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v("\ndr-xr-xr-x "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" root root "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4096")]),t._v(" Dec "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2012")]),t._v(" bin\ndr-xr-xr-x "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v(" root root "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("4096")]),t._v(" Apr "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2012")]),t._v(" boot\n")])])]),a("ul",[a("li",[t._v("对于文件来说,它都有一个特定的拥有者,也就是对该文件具有所有权的用户。")]),t._v(" "),a("li",[t._v("同时,在 Linux 系统中,用户是按组分类的,一个用户属于一个或多个组。")]),t._v(" "),a("li",[t._v("文件拥有者以外的用户又可以分为文件拥有者的同组用户和其他用户。")]),t._v(" "),a("li",[t._v("因此,Linux 系统按文件拥有者、文件拥有者同组用户和其他用户来规定了不同的文件访问权限。")]),t._v(" "),a("li",[t._v("在以上实例中,bin 文件是一个目录文件,属主和属组都为 root,属主有可读、可写、可执行的权限;与属主同组的其他用户有可读和可执行的权限;其他用户也有可读和可执行的权限。")])]),t._v(" "),a("h2",{attrs:{id:"_2-linux-文件目录管理要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-linux-文件目录管理要点"}},[t._v("#")]),t._v(" 2. Linux 文件目录管理要点")]),t._v(" "),a("h3",{attrs:{id:"_2-1-目录管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-目录管理"}},[t._v("#")]),t._v(" 2.1. 目录管理")]),t._v(" "),a("ul",[a("li",[t._v("切换目录 - 使用 "),a("a",{attrs:{href:"#cd"}},[t._v("cd")])]),t._v(" "),a("li",[t._v("查看目录信息 - 使用 "),a("a",{attrs:{href:"#ls"}},[t._v("ls")])]),t._v(" "),a("li",[t._v("显示当前目录的绝对路径 - 使用 "),a("a",{attrs:{href:"#pwd"}},[t._v("pwd")])]),t._v(" "),a("li",[t._v("树状显示目录的内容 - 使用 "),a("a",{attrs:{href:"#tree"}},[t._v("tree")])]),t._v(" "),a("li",[t._v("创建目录 - 使用 "),a("a",{attrs:{href:"#mkdir"}},[t._v("mkdir")])]),t._v(" "),a("li",[t._v("删除目录 - 使用 "),a("a",{attrs:{href:"#rmdir"}},[t._v("rmdir")])])]),t._v(" "),a("h3",{attrs:{id:"_2-2-文件管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-文件管理"}},[t._v("#")]),t._v(" 2.2. 文件管理")]),t._v(" "),a("ul",[a("li",[t._v("创建空文件 - 使用 "),a("a",{attrs:{href:"#touch"}},[t._v("touch")])]),t._v(" "),a("li",[t._v("为文件创建连接 - 使用 "),a("a",{attrs:{href:"#ln"}},[t._v("ln")])]),t._v(" "),a("li",[t._v("批量重命名 - 使用 "),a("a",{attrs:{href:"#rename"}},[t._v("rename")])]),t._v(" "),a("li",[t._v("显示文件的详细信息 - 使用 "),a("a",{attrs:{href:"#stat"}},[t._v("stat")])]),t._v(" "),a("li",[t._v("探测文件类型 - 使用 "),a("a",{attrs:{href:"#file"}},[t._v("file")])]),t._v(" "),a("li",[t._v("设置文件或目录的权限 - 使用 "),a("a",{attrs:{href:"#chmod"}},[t._v("chmod")])]),t._v(" "),a("li",[t._v("设置文件或目录的拥有者或所属群组 - 使用 "),a("a",{attrs:{href:"#chown"}},[t._v("chown")])]),t._v(" "),a("li",[t._v("查找文件或目录 - 使用 "),a("a",{attrs:{href:"#locate"}},[t._v("locate")])]),t._v(" "),a("li",[t._v("在指定目录下查找文件 - 使用 "),a("a",{attrs:{href:"#find"}},[t._v("find")])]),t._v(" "),a("li",[t._v("查找命令的绝对路径 - 使用 "),a("a",{attrs:{href:"#which"}},[t._v("which")])]),t._v(" "),a("li",[t._v("查找命令的程序、源代码等相关文件 - 使用 "),a("a",{attrs:{href:"#whereis"}},[t._v("whereis")])])]),t._v(" "),a("h3",{attrs:{id:"_2-3-文件和目录通用管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-文件和目录通用管理"}},[t._v("#")]),t._v(" 2.3. 文件和目录通用管理")]),t._v(" "),a("ul",[a("li",[t._v("复制文件或目录 - 使用 "),a("a",{attrs:{href:"#cp"}},[t._v("cp")])]),t._v(" "),a("li",[t._v("复制文件或目录到远程服务器 - 使用 "),a("a",{attrs:{href:"#scp"}},[t._v("scp")])]),t._v(" "),a("li",[t._v("移动文件或目录 - 使用 "),a("a",{attrs:{href:"#mv"}},[t._v("mv")])]),t._v(" "),a("li",[t._v("删除文件或目录 - 使用 "),a("a",{attrs:{href:"#rm"}},[t._v("rm")])])]),t._v(" "),a("h2",{attrs:{id:"_3-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-命令常见用法"}},[t._v("#")]),t._v(" 3. 命令常见用法")]),t._v(" "),a("h3",{attrs:{id:"_3-1-cd"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-cd"}},[t._v("#")]),t._v(" 3.1. cd")]),t._v(" "),a("blockquote",[a("p",[t._v("cd 命令用来切换工作目录。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/cd")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到用户主目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" ~ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到用户主目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" - "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到上一个工作目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到上级目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v("/"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到上两级目录")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-2-ls"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-ls"}},[t._v("#")]),t._v(" 3.2. ls")]),t._v(" "),a("blockquote",[a("p",[t._v("ls 命令用来显示目录信息。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/ls")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前目录可见文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -l "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前目录可见文件详细信息")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -la "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有文件(包括隐藏)的详细信息")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -lh "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出详细信息并以可读大小显示文件大小")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -lt "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 按时间列出文件和文件夹详细信息")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" -ltr "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 按修改时间列出文件和文件夹详细信息")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ls")]),t._v(" --color"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("auto "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出文件并标记颜色分类")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-3-pwd"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-pwd"}},[t._v("#")]),t._v(" 3.3. pwd")]),t._v(" "),a("blockquote",[a("p",[t._v("pwd 命令用来显示当前目录的绝对路径。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/pwd")])]),t._v(" "),a("h3",{attrs:{id:"_3-4-mkdir"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-mkdir"}},[t._v("#")]),t._v(" 3.4. mkdir")]),t._v(" "),a("blockquote",[a("p",[t._v("mkdir 命令用来创建目录。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/mkdir")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在当前目录中创建 zp 和 zp 的子目录 test")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mkdir")]),t._v(" -p zp/test\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在当前目录中创建 zp 和 zp 的子目录 test;权限设置为文件主可读、写、执行,同组用户可读和执行,其他用户无权访问")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mkdir")]),t._v(" -p -m "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("750")]),t._v(" zp/test\n")])])]),a("h3",{attrs:{id:"_3-5-rmdir"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-5-rmdir"}},[t._v("#")]),t._v(" 3.5. rmdir")]),t._v(" "),a("blockquote",[a("p",[t._v("rmdir 命令用来删除空目录。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/rmdir")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除子目录 test 和其父目录 zp")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rmdir")]),t._v(" -p zp/test\n")])])]),a("h3",{attrs:{id:"_3-6-tree"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-6-tree"}},[t._v("#")]),t._v(" 3.6. tree")]),t._v(" "),a("blockquote",[a("p",[t._v("tree 命令以树状显示目录的内。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/tree")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出目录 /private 第一级文件名")]),t._v("\ntree /private -L "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n/private/\n├── etc\n├── tftpboot\n├── tmp\n└── var\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 忽略文件夹")]),t._v("\ntree -I node_modules "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 忽略当前目录文件夹 node_modules")]),t._v("\ntree -P node_modules "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前目录文件夹 node_modules 的目录结构")]),t._v("\ntree -P node_modules -L "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示目录 node_modules 两层的目录树结构")]),t._v("\ntree -L "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" /home/www/tree.txt "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当前目录结果存到 tree.txt 文件中")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 忽略多个文件夹")]),t._v("\ntree -I "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'node_modules|icon|font'")]),t._v(" -L "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-7-touch"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-7-touch"}},[t._v("#")]),t._v(" 3.7. touch")]),t._v(" "),a("blockquote",[a("p",[t._v("touch 命令有两个功能:一是用于把已存在文件的时间标签更新为系统当前的时间(默认方式),它们的数据将原封不动地保留下来;二是用来创建空文件。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/touch")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("touch ex2\n")])])]),a("h3",{attrs:{id:"_3-8-ln"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-8-ln"}},[t._v("#")]),t._v(" 3.8. ln")]),t._v(" "),a("blockquote",[a("p",[t._v('ln 命令用来为文件创建连接,连接类型分为硬连接和符号连接两种,默认的连接类型是硬连接。如果要创建符号连接必须使用"-s"选项。')]),t._v(" "),a("p",[t._v("🔔 注意:符号链接文件不是一个独立的文件,它的许多属性依赖于源文件,所以给符号链接文件设置存取权限是没有意义的。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/ln")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将目录 /usr/mengqc/mub1 下的文件 m2.c 链接到目录 /usr/liu 下的文件 a2.c")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" /usr/mengqc\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ln")]),t._v(" /mub1/m2.c /usr/liu/a2.c\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在目录 /usr/liu 下建立一个符号链接文件 abc,使它指向目录 /usr/mengqc/mub1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 执行该命令后,/usr/mengqc/mub1 代表的路径将存放在名为 /usr/liu/abc 的文件中")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("ln")]),t._v(" -s /usr/mengqc/mub1 /usr/liu/abc\n")])])]),a("h3",{attrs:{id:"_3-9-rename"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-9-rename"}},[t._v("#")]),t._v(" 3.9. rename")]),t._v(" "),a("blockquote",[a("p",[t._v("rename 命令用字符串替换的方式批量重命名。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/rename")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将 main1.c 重命名为 main.c")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rename")]),t._v(" main1.c main.c main1.c\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rename")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s/AA/aa/"')]),t._v(" * "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把文件名中的 AA 替换成 aa")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rename")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s//.html//.php/"')]),t._v(" * "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把 .html 后缀的改成 .php 后缀")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rename")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s/$//.txt/"')]),t._v(" * "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把所有的文件名都以 txt 结尾")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rename")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"s//.txt//"')]),t._v(" * "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把所有以 .txt 结尾的文件名的.txt 删掉")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-10-stat"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-10-stat"}},[t._v("#")]),t._v(" 3.10. stat")]),t._v(" "),a("blockquote",[a("p",[t._v("stat 命令用于显示文件的状态信息。stat 命令的输出信息比 ls 命令的输出信息要更详细。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/stat")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("stat")]),t._v(" myfile\n")])])]),a("h3",{attrs:{id:"_3-11-file"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-11-file"}},[t._v("#")]),t._v(" 3.11. file")]),t._v(" "),a("blockquote",[a("p",[t._v("file 命令用来探测给定文件的类型。file 命令对文件的检查分为文件系统、魔法幻数检查和语言检查 3 个过程。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/file")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),t._v(" install.log "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示文件类型")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),t._v(" -b install.log "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 不显示文件名称")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),t._v(" -i install.log "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示 MIME 类型")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),t._v(" -L /var/spool/mail "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示符号链接的文件类型")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-12-chmod"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-12-chmod"}},[t._v("#")]),t._v(" 3.12. chmod")]),t._v(" "),a("blockquote",[a("p",[t._v("chmod 命令用来变更文件或目录的权限。在 UNIX 系统家族里,文件或目录权限的控制分别以读取、写入、执行 3 种一般权限来区分,另有 3 种特殊权限可供运用。用户可以使用 chmod 指令去变更文件与目录的权限,设置方式采用文字或数字代号皆可。符号连接的权限无法变更,如果用户对符号连接修改权限,其改变会作用在被连接的原始文件。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/chmod")])]),t._v(" "),a("p",[t._v("知识扩展:")]),t._v(" "),a("p",[t._v("Linux 用 户分为:拥有者、组群(Group)、其他(other),Linux 系统中,预设的情況下,系统中所有的帐号与一般身份使用者,以及 root 的相关信 息, 都是记录在"),a("code",[t._v("/etc/passwd")]),t._v("文件中。每个人的密码则是记录在"),a("code",[t._v("/etc/shadow")]),t._v("文件下。 此外,所有的组群名称记录在"),a("code",[t._v("/etc/group")]),t._v("內!")]),t._v(" "),a("p",[t._v("linux 文件的用户权限的分析图")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v(" -rw-r--r-- "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" user staff "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("651")]),t._v(" Oct "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(":53 .gitmodules\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ↑╰┬╯╰┬╯╰┬╯")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ┆ ┆ ┆ ╰┈ 0 其他人")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ┆ ┆ ╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ g 属组")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ┆ ╰┈┈┈┈ u 属组")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ╰┈┈ 第一个字母 `d` 代表目录,`-` 代表普通文件")]),t._v("\n")])])]),a("p",[t._v("例:rwx   rw-  r--")]),t._v(" "),a("p",[t._v("r=读取属性  //值= 4"),a("br"),t._v("\nw=写入属性  //值= 2"),a("br"),t._v("\nx=执行属性  //值= 1")]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" u+x,g+w f01  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 为文件f01设置自己可以执行,组员可以写入的权限")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("u")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("rwx,g"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("rw,o"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("r f01\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("764")]),t._v(" f01\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" a+x f01   "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 对文件f01的u,g,o都设置可执行属性")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将/home/wwwroot/里的所有文件和文件夹设置为755权限")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" -R "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("755")]),t._v(" /home/wwwroot/*\n")])])]),a("h3",{attrs:{id:"_3-13-chown"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-13-chown"}},[t._v("#")]),t._v(" 3.13. chown")]),t._v(" "),a("blockquote",[a("p",[t._v("chown 命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组。用户可以是用户或者是用户 D,用户组可以是组名或组 id。文件名可以使由空格分开的文件列表,在文件名中可以包含通配符。")]),t._v(" "),a("p",[t._v("只有文件拥有者和超级用户才可以便用该命令。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/chown")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将目录/usr/meng及其下面的所有文件、子目录的文件主改成 liu")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R liu /usr/meng\n")])])]),a("h3",{attrs:{id:"_3-14-locate"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-14-locate"}},[t._v("#")]),t._v(" 3.14. locate")]),t._v(" "),a("blockquote",[a("p",[t._v("locate 命令和 slocate 命令都用来查找文件或目录。")]),t._v(" "),a("p",[t._v("locate 命令其实是 find -name 的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库/var/lib/locatedb,这个数据库中含有本地所有文件信息。Linux 系统自动创建这个数据库,并且每天自动更新一次,所以使用 locate 命令查不到最新变动过的文件。为了避免这种情况,可以在使用 locate 之前,先使用 updatedb 命令,手动更新数据库。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/locate_slocate")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("locate")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("pwd")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查找和 pwd 相关的所有文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("locate")]),t._v(" /etc/sh "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 搜索 etc 目录下所有以 sh 开头的文件")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-15-find"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-15-find"}},[t._v("#")]),t._v(" 3.15. find")]),t._v(" "),a("blockquote",[a("p",[t._v("find 命令用来在指定目录下查找文件。任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则 find 命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/find")])]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当前目录搜索所有文件,文件内容 包含 “140.206.111.111” 的内容")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" -type f -name "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("xargs")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("grep")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"140.206.111.111"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前目录及子目录下所有文件和文件夹")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在 /home 目录下查找以 .txt 结尾的文件名")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" /home -name "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*.txt"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 同上,但忽略大小写")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" /home -iname "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*.txt"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 当前目录及子目录下查找所有以 .txt 和 .pdf 结尾的文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" -name "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*.txt"')]),t._v(" -o -name "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*.pdf"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 匹配文件路径或者文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" /usr/ -path "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*local*"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 基于正则表达式匹配文件路径")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" -regex "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('".*\\(\\.txt\\|\\.pdf\\)$"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 同上,但忽略大小写")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" -iregex "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('".*\\(\\.txt\\|\\.pdf\\)$"')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 找出 /home 下不是以 .txt 结尾的文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),t._v(" /home "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v(" -name "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*.txt"')]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-16-cp"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-16-cp"}},[t._v("#")]),t._v(" 3.16. cp")]),t._v(" "),a("blockquote",[a("p",[t._v("cp 命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录。它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下。cp 命令还支持同时复制多个文件,当一次复制多个文件时,目标文件参数必须是一个已经存在的目录,否则将出现错误。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/cp")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("h4",{attrs:{id:"_3-16-1-参数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-16-1-参数"}},[t._v("#")]),t._v(" 3.16.1. 参数")]),t._v(" "),a("ul",[a("li",[t._v("源文件:制定源文件列表。默认情况下,cp 命令不能复制目录,如果要复制目录,则必须使用"),a("code",[t._v("-R")]),t._v("选项;")]),t._v(" "),a("li",[t._v("目标文件:指定目标文件。当“源文件”为多个文件时,要求“目标文件”为指定的目录。")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将文件 file 复制到目录 /usr/men/tmp 下,并改名为 file1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("file")]),t._v(" /usr/men/tmp/file1\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将目录 /usr/men下的所有文件及其子目录复制到目录 /usr/zh 中")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" -r /usr/men /usr/zh\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 强行将 /usr/men下的所有文件复制到目录 /usr/zh 中,无论是否有文件重复")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" -rf /usr/men/* /usr/zh\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将目录 /usr/men 中的以 m 打头的所有 .c 文件复制到目录 /usr/zh 中")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" -i /usr/men m*.c /usr/zh\n")])])]),a("h3",{attrs:{id:"_3-17-scp"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-17-scp"}},[t._v("#")]),t._v(" 3.17. scp")]),t._v(" "),a("blockquote",[a("p",[t._v("scp 命令用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然 rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 拷贝文件到远程服务器的指定目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scp")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("file"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("@"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ip"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(":"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scp")]),t._v(" test.txt root@192.168.0.1:/opt\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 拷贝目录到远程服务器的指定目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scp")]),t._v(" -r "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("folder"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("user"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("@"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ip"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(":"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("url"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scp")]),t._v(" -r "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" root@192.168.0.1:/opt\n")])])]),a("h4",{attrs:{id:"_3-17-1-免密码传输"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-17-1-免密码传输"}},[t._v("#")]),t._v(" 3.17.1. 免密码传输")]),t._v(" "),a("p",[t._v("(1)生成 ssh 公私钥对")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("ssh-keygen -t rsa\n")])])]),a("p",[t._v("(2)将服务器 A 的 "),a("code",[t._v("\\~/.ssh/id_rsa.pub")]),t._v(" 文件内容复制到服务器 B 的 "),a("code",[t._v("\\~/.ssh/authorized_keys")]),t._v(" 文件中。")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 服务器 A 上执行以下命令")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("scp")]),t._v(" ~/.ssh/id_rsa.pub root@192.168.0.2:~/.ssh/id_rsa.pub.tmp\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 服务器 B 上执行以下命令")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cat")]),t._v(" ~/.ssh/id_rsa.pub.tmp "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" ~/.ssh/authorized_keys\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" ~/.ssh/id_rsa.pub.tmp\n")])])]),a("h3",{attrs:{id:"_3-18-mv"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-18-mv"}},[t._v("#")]),t._v(" 3.18. mv")]),t._v(" "),a("blockquote",[a("p",[t._v("mv 命令用来对文件或目录重新命名,或者将文件从一个目录移到另一个目录中。source 表示源文件或目录,target 表示目标文件或目录。如果将一个文件移到一个已经存在的目标文件中,则目标文件的内容将被覆盖。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/mv")])]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" file1.txt /home/office/ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 移动单个文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" file2.txt file3.txt file4.txt /home/office/ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 移动多个文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" *.txt /home/office/ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 移动所有 txt 文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" dir1/ /home/office/ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 移动目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" /usr/men/* "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将指定目录中的所有文件移到当前目录中")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" file1.txt file2.txt "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重命名文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" dir1/ dir2/ "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重命名目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -v *.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 打印移动信息")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -i file1.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 提示是否覆盖文件")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -uv *.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 源文件比目标文件新时才执行更新")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -vn *.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 不要覆盖任何已存在的文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -f *.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 无条件覆盖已经存在的文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mv")]),t._v(" -bv *.txt /home/office "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 复制时创建备份")]),t._v("\n")])])]),a("h3",{attrs:{id:"_3-19-rm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-19-rm"}},[t._v("#")]),t._v(" 3.19. rm")]),t._v(" "),a("blockquote",[a("p",[t._v("rm 命令可以删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉。对于链接文件,只是删除整个链接文件,而原有文件保持不变。")]),t._v(" "),a("p",[t._v("参考:http://man.linuxde.net/rm")])]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" test.txt "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" -i test.txt test2.txt "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 交互式删除文件")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" -r * "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除当前目录下的所有文件和目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" -r testdir "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除目录下的所有文件和目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" -rf testdir "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 强制删除目录下的所有文件和目录")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rm")]),t._v(" -v testdir "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示当前删除操作的详情")]),t._v("\n")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/25.9896afe9.js b/assets/js/25.9896afe9.js new file mode 100644 index 0000000..085f435 --- /dev/null +++ b/assets/js/25.9896afe9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{413:function(t,a,s){"use strict";s.r(a);var n=s(15),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"linux-文件压缩和解压"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#linux-文件压缩和解压"}},[t._v("#")]),t._v(" Linux 文件压缩和解压")]),t._v(" "),s("blockquote",[s("p",[t._v("关键词:"),s("code",[t._v("tar")]),t._v(", "),s("code",[t._v("gzip")]),t._v(", "),s("code",[t._v("zip")]),t._v(", "),s("code",[t._v("unzip")])])]),t._v(" "),s("h2",{attrs:{id:"_1-linux-文件压缩和解压要点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-文件压缩和解压要点"}},[t._v("#")]),t._v(" 1. Linux 文件压缩和解压要点")]),t._v(" "),s("ul",[s("li",[t._v("压缩和解压 tar 文件 - 使用 "),s("a",{attrs:{href:"#tar"}},[t._v("tar")])]),t._v(" "),s("li",[t._v("压缩和解压 gz 文件 - 使用 "),s("a",{attrs:{href:"#gzip"}},[t._v("gzip")])]),t._v(" "),s("li",[t._v("压缩和解压 zip 文件 - 分别使用 "),s("a",{attrs:{href:"#zip"}},[t._v("zip")]),t._v("、"),s("a",{attrs:{href:"#unzip"}},[t._v("unzip")])])]),t._v(" "),s("h2",{attrs:{id:"_2-命令常见用法"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[t._v("#")]),t._v(" 2. 命令常见用法")]),t._v(" "),s("h3",{attrs:{id:"_2-1-tar"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-tar"}},[t._v("#")]),t._v(" 2.1. tar")]),t._v(" "),s("blockquote",[s("p",[t._v("tar 命令可以为 linux 的文件和目录创建档案。利用 tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件。tar 最初被用来在磁带上创建档案,现在,用户可以在任何设备上创建档案。利用 tar 命令,可以把一大堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的。")]),t._v(" "),s("p",[t._v("参考:http://man.linuxde.net/tar")])]),t._v(" "),s("p",[t._v("示例:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -cvf log.tar log2012.log "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 仅打包,不压缩")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -zcvf log.tar.gz log2012.log "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 打包后,以 gzip 压缩")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -jcvf log.tar.bz2 log2012.log "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 打包后,以 bzip2 压缩")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -ztvf log.tar.gz "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查阅上述 tar 包内有哪些文件")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -zxvf log.tar.gz "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将 tar 包解压缩")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tar")]),t._v(" -zxvf log30.tar.gz log2013.log "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 只将 tar 内的部分文件解压出来")]),t._v("\n")])])]),s("h3",{attrs:{id:"_2-2-gzip"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-gzip"}},[t._v("#")]),t._v(" 2.2. gzip")]),t._v(" "),s("blockquote",[s("p",[t._v("gzip 命令用来压缩文件。gzip 是个使用广泛的压缩程序,文件经它压缩过后,其名称后面会多出“.gz”扩展名。")]),t._v(" "),s("p",[t._v("gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。gzip 不仅可以用来压缩大的、较少使用的文件以节省磁盘空间,还可以和 tar 命令一起构成 Linux 操作系统中比较流行的压缩文件格式。据统计,gzip 命令对文本文件有 60%~ 70%的压缩率。减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。")]),t._v(" "),s("p",[t._v("参考:http://man.linuxde.net/gzip")])]),t._v(" "),s("p",[t._v("示例:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" * "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将所有文件压缩成 .gz 文件")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" -l * "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 详细显示压缩文件的信息,并不解压")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" -dv * "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 解压上例中的所有压缩文件,并列出详细的信息")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" -r log.tar "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 压缩一个 tar 备份文件,此时压缩文件的扩展名为.tar.gz")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" -rv test/ "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 递归的压缩目录")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("gzip")]),t._v(" -dr test/ "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 递归地解压目录")]),t._v("\n")])])]),s("h3",{attrs:{id:"_2-3-zip"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-zip"}},[t._v("#")]),t._v(" 2.3. zip")]),t._v(" "),s("blockquote",[s("p",[t._v("zip 命令可以用来解压缩文件,或者对文件进行打包操作。zip 是个使用广泛的压缩程序,文件经它压缩后会另外产生具有“.zip”扩展名的压缩文件。")]),t._v(" "),s("p",[t._v("参考:http://man.linuxde.net/zip")])]),t._v(" "),s("p",[t._v("示例:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将 /home/Blinux/html/ 这个目录下所有文件和文件夹打包为当前目录下的 html.zip")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("zip")]),t._v(" -q -r html.zip /home/Blinux/html\n")])])]),s("h3",{attrs:{id:"_2-4-unzip"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-unzip"}},[t._v("#")]),t._v(" 2.4. unzip")]),t._v(" "),s("blockquote",[s("p",[t._v("unzip 命令用于解压缩由 zip 命令压缩的“.zip”压缩包。")]),t._v(" "),s("p",[t._v("参考:http://man.linuxde.net/unzip")])]),t._v(" "),s("p",[t._v("示例:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unzip")]),t._v(" test.zip "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 解压 zip 文件")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unzip")]),t._v(" -n test.zip -d /tmp/ "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在指定目录下解压缩")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unzip")]),t._v(" -o test.zip -d /tmp/ "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 在指定目录下解压缩,如果有相同文件存在则覆盖")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unzip")]),t._v(" -v test.zip "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看压缩文件目录,但不解压")]),t._v("\n")])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/26.96164082.js b/assets/js/26.96164082.js new file mode 100644 index 0000000..ae613c7 --- /dev/null +++ b/assets/js/26.96164082.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{414:function(s,t,a){"use strict";a.r(t);var e=a(15),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"linux-文件内容查看编辑"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linux-文件内容查看编辑"}},[s._v("#")]),s._v(" Linux 文件内容查看编辑")]),s._v(" "),a("blockquote",[a("p",[s._v("关键词:"),a("code",[s._v("cat")]),s._v(", "),a("code",[s._v("head")]),s._v(", "),a("code",[s._v("tail")]),s._v(", "),a("code",[s._v("more")]),s._v(", "),a("code",[s._v("less")]),s._v(", "),a("code",[s._v("sed")]),s._v(", "),a("code",[s._v("vi")]),s._v(", "),a("code",[s._v("grep")])])]),s._v(" "),a("h2",{attrs:{id:"_1-linux-文件内容查看编辑要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-文件内容查看编辑要点"}},[s._v("#")]),s._v(" 1. Linux 文件内容查看编辑要点")]),s._v(" "),a("ul",[a("li",[s._v("连接文件并打印到标准输出设备 - 使用 "),a("a",{attrs:{href:"#cat"}},[s._v("cat")])]),s._v(" "),a("li",[s._v("显示指定文件的开头若干行 - 使用 "),a("a",{attrs:{href:"#head"}},[s._v("head")])]),s._v(" "),a("li",[s._v("显示指定文件的末尾若干行,常用于实时打印日志文件内容 - 使用 "),a("a",{attrs:{href:"#tail"}},[s._v("tail")])]),s._v(" "),a("li",[s._v("显示文件内容,每次显示一屏 - 使用 "),a("a",{attrs:{href:"#more"}},[s._v("more")])]),s._v(" "),a("li",[s._v("显示文件内容,每次显示一屏 - 使用 "),a("a",{attrs:{href:"#less"}},[s._v("less")])]),s._v(" "),a("li",[s._v("自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等 - 使用 "),a("a",{attrs:{href:"#sed"}},[s._v("sed")])]),s._v(" "),a("li",[s._v("文本编辑器 - 使用 "),a("a",{attrs:{href:"#vi"}},[s._v("vi")])]),s._v(" "),a("li",[s._v("使用正则表达式搜索文本,并把匹配的行打印出来 - 使用 "),a("a",{attrs:{href:"#grep"}},[s._v("grep")])])]),s._v(" "),a("h2",{attrs:{id:"_2-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[s._v("#")]),s._v(" 2. 命令常见用法")]),s._v(" "),a("h3",{attrs:{id:"_2-1-cat"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-cat"}},[s._v("#")]),s._v(" 2.1. cat")]),s._v(" "),a("blockquote",[a("p",[s._v("cat 命令用于连接文件并打印到标准输出设备上。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/cat")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("cat")]),s._v(" m1 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在屏幕上显示文件 ml 的内容")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("cat")]),s._v(" m1 m2 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 同时显示文件 ml 和 m2 的内容")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("cat")]),s._v(" m1 m2 "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将文件 ml 和 m2 合并后放入文件 file 中")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-2-head"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-head"}},[s._v("#")]),s._v(" 2.2. head")]),s._v(" "),a("blockquote",[a("p",[s._v("head 命令用于显示文件的开头内容。在默认情况下,head 命令显示文件的头部 10 行内容。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/head")])]),s._v(" "),a("h3",{attrs:{id:"_2-3-tail"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-tail"}},[s._v("#")]),s._v(" 2.3. tail")]),s._v(" "),a("blockquote",[a("p",[s._v("tail 命令用于显示文件的尾部内容。在默认情况下,tail 命令显示文件的尾部 10 行内容。如果给定的文件不止一个,则在显示的每个文件前面加一个文件名标题。如果没有指定文件或者文件名为“-”,则读取标准输入。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/tail")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("tail")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示文件file的最后10行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("tail")]),s._v(" -n +20 "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示文件file的内容,从第20行至文件末尾")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("tail")]),s._v(" -c "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示文件file的最后10个字符")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-4-more"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-more"}},[s._v("#")]),s._v(" 2.4. more")]),s._v(" "),a("blockquote",[a("p",[s._v("more 命令是一个基于 vi 编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持 vi 中的关键字定位操作。more 名单中内置了若干快捷键,常用的有 H(获得帮助信息),Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)。")]),s._v(" "),a("p",[s._v("该命令一次显示一屏文本,满屏后停下来,并且在屏幕的底部出现一个提示信息,给出至今己显示的该文件的百分比:--More--(XX%)可以用下列不同的方法对提示做出回答:")]),s._v(" "),a("ul",[a("li",[s._v("按 Space 键:显示文本的下一屏内容。")]),s._v(" "),a("li",[s._v("按 Enier 键:只显示文本的下一行内容。")]),s._v(" "),a("li",[s._v("按斜线符|:接着输入一个模式,可以在文本中寻找下一个相匹配的模式。")]),s._v(" "),a("li",[s._v("按 H 键:显示帮助屏,该屏上有相关的帮助信息。")]),s._v(" "),a("li",[s._v("按 B 键:显示上一屏内容。")]),s._v(" "),a("li",[s._v("按 Q 键:退出 rnore 命令。")])]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/more")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示文件 file 的内容,但在显示之前先清屏,并且在屏幕的最下方显示完核的百分比。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("more")]),s._v(" -dc "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示文件 file 的内容,每 10 行显示一次,而且在显示之前先清屏。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("more")]),s._v(" -c -10 "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-5-less"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-less"}},[s._v("#")]),s._v(" 2.5. less")]),s._v(" "),a("p",[s._v("less 命令的作用与 more 十分相似,都可以用来浏览文字档案的内容,不同的是 less 命令允许用户向前或向后浏览文件,而 more 命令只能向前浏览。用 less 命令显示文件时,用 PageUp 键向上翻页,用 PageDown 键向下翻页。要退出 less 程序,应按 Q 键。")]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("less")]),s._v(" /var/log/shadowsocks.log\n")])])]),a("h3",{attrs:{id:"_2-6-sed"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-sed"}},[s._v("#")]),s._v(" 2.6. sed")]),s._v(" "),a("blockquote",[a("p",[s._v("sed 是一种流编辑器,它是文本处理工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed 主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/sed")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 替换文本中的字符串")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'s/book/books/'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# -n 选项 和 p 命令 一起使用表示只打印那些发生替换的行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" -n "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'s/test/TEST/p'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 直接编辑文件选项 -i ,会匹配 file 文件中每一行的第一个 book 替换为 books")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" -i "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'s/book/books/g'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 使用后缀 /g 标记会替换每一行中的所有匹配")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'s/book/books/g'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除空白行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'/^$/d'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除文件的第2行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'2d'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除文件的第2行到末尾所有行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'2,"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$d")]),s._v("'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除文件最后一行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$d")]),s._v("'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除文件中所有开头是test的行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sed")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'/^test/'")]),s._v("d "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-7-vi"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-vi"}},[s._v("#")]),s._v(" 2.7. vi")]),s._v(" "),a("blockquote",[a("p",[s._v("vi 命令是 UNIX 操作系统和类 UNIX 操作系统中最通用的全屏幕纯文本编辑器。Linux 中的 vi 编辑器叫 vim,它是 vi 的增强版(vi Improved),与 vi 编辑器完全兼容,而且实现了很多增强功能。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/vi")]),s._v(" "),a("p",[s._v("引申阅读:"),a("a",{attrs:{href:"https://github.com/dunwu/OS/blob/master/docs/vim.md",target:"_blank",rel:"noopener noreferrer"}},[s._v("Vim 入门指南"),a("OutboundLink")],1)])]),s._v(" "),a("h3",{attrs:{id:"_2-8-grep"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-grep"}},[s._v("#")]),s._v(" 2.8. grep")]),s._v(" "),a("blockquote",[a("p",[s._v("grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/grep")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在多级目录中对文本递归搜索(程序员搜代码的最爱):")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"class"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -R -n\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 忽略匹配样式中的字符大小写")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"hello world"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -i "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"HELLO"')]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 匹配多个模式:")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" -e "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"class"')]),s._v(" -e "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"vitural"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("file")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v('# 只在目录中所有的.php和.html文件中递归搜索字符"main()"')]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --include *."),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("php,html"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在搜索结果中排除所有README文件")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --exclude "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"README"')]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在搜索结果中排除filelist文件列表里的文件")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"main()"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v(" -r --exclude-from filelist\n")])])]),a("h2",{attrs:{id:"_3-参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-参考资料"}},[s._v("#")]),s._v(" 3. 参考资料")]),s._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"http://man.linuxde.net/",target:"_blank",rel:"noopener noreferrer"}},[s._v("Linux 命令大全"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/27.391033bb.js b/assets/js/27.391033bb.js new file mode 100644 index 0000000..cb82c32 --- /dev/null +++ b/assets/js/27.391033bb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{415:function(s,t,a){"use strict";a.r(t);var n=a(15),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"linux-硬件管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linux-硬件管理"}},[s._v("#")]),s._v(" Linux 硬件管理")]),s._v(" "),a("blockquote",[a("p",[s._v("关键词:"),a("code",[s._v("df")]),s._v(", "),a("code",[s._v("du")]),s._v(", "),a("code",[s._v("top")]),s._v(", "),a("code",[s._v("free")]),s._v(", "),a("code",[s._v("iotop")])])]),s._v(" "),a("h2",{attrs:{id:"_1-linux-硬件管理要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-硬件管理要点"}},[s._v("#")]),s._v(" 1. Linux 硬件管理要点")]),s._v(" "),a("ul",[a("li",[s._v("查看磁盘空间 - 使用 "),a("a",{attrs:{href:"#df"}},[s._v("df")])]),s._v(" "),a("li",[s._v("查看文件或目录的磁盘空间 - 使用 "),a("a",{attrs:{href:"#du"}},[s._v("du")])]),s._v(" "),a("li",[s._v("实时查看系统整体运行状态(如:CPU、内存) - 使用 "),a("a",{attrs:{href:"#top"}},[s._v("top")])]),s._v(" "),a("li",[s._v("查看已使用和未使用的内存 - 使用 "),a("a",{attrs:{href:"#free"}},[s._v("free")])]),s._v(" "),a("li",[s._v("查看磁盘 I/O 使用状况 - 使用 "),a("a",{attrs:{href:"#iotop"}},[s._v("iotop")])])]),s._v(" "),a("h2",{attrs:{id:"_2-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[s._v("#")]),s._v(" 2. 命令常见用法")]),s._v(" "),a("h3",{attrs:{id:"_2-1-df"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-df"}},[s._v("#")]),s._v(" 2.1. df")]),s._v(" "),a("blockquote",[a("p",[s._v("df 命令用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为 KB。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/df")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看系统磁盘设备,默认是 KB 为单位")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@LinServ-1 ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# df")]),s._v("\n文件系统 1K-块 已用 可用 已用% 挂载点\n/dev/sda2 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("146294492")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("28244432")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("110498708")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v("% /\n/dev/sda1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1019208")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("62360")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("904240")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v("% /boot\ntmpfs "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1032204")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1032204")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("% /dev/shm\n/dev/sdb1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2884284108")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("218826068")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2518944764")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("% /data1\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 使用 -h 选项以 KB 以上的单位来显示,可读性高")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@LinServ-1 ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# df -h")]),s._v("\n文件系统 容量 已用 可用 已用% 挂载点\n/dev/sda2 140G 27G 106G "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v("% /\n/dev/sda1 996M 61M 884M "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v("% /boot\ntmpfs 1009M "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" 1009M "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("% /dev/shm\n/dev/sdb1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(".7T 209G "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(".4T "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("% /data1\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看全部文件系统")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@LinServ-1 ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# df -a")]),s._v("\n文件系统 1K-块 已用 可用 已用% 挂载点\n/dev/sda2 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("146294492")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("28244432")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("110498708")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v("% /\nproc "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" - /proc\nsysfs "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" - /sys\ndevpts "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" - /dev/pts\n/dev/sda1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1019208")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("62360")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("904240")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v("% /boot\ntmpfs "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1032204")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1032204")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("% /dev/shm\n/dev/sdb1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2884284108")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("218826068")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2518944764")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("% /data1\nnone "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" - /proc/sys/fs/binfmt_misc\n")])])]),a("h3",{attrs:{id:"_2-2-du"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-du"}},[s._v("#")]),s._v(" 2.2. du")]),s._v(" "),a("blockquote",[a("p",[s._v("du 命令也是查看使用空间的,但是与 df 命令不同的是:du 命令是对文件和目录磁盘使用的空间的查看,还是和 df 命令有一些区别的。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/du")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示目录或者文件所占空间")]),s._v("\nroot@localhost "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("608")]),s._v(" ./test6\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("308")]),s._v(" ./test4\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" ./scf/lib\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" ./scf/service/deploy/product\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" ./scf/service/deploy/info\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("12")]),s._v(" ./scf/service/deploy\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(" ./scf/service\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" ./scf/doc\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" ./scf/bin\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("32")]),s._v(" ./scf\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v(" ./test3\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1288")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示指定文件所占空间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du log2012.log")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("300")]),s._v(" log2012.log\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看指定目录的所占空间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du scf")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" scf/lib\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" scf/service/deploy/product\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" scf/service/deploy/info\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("12")]),s._v(" scf/service/deploy\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(" scf/service\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" scf/doc\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" scf/bin\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("32")]),s._v(" scf\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示多个文件所占空间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du log30.tar.gz log31.tar.gz")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" log30.tar.gz\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" log31.tar.gz\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 只显示总和的大小")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du -s")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1288")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost test"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# du -s scf")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("32")]),s._v(" scf\n")])])]),a("h3",{attrs:{id:"_2-3-top"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-top"}},[s._v("#")]),s._v(" 2.3. top")]),s._v(" "),a("blockquote",[a("p",[s._v("top 命令可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/top")])]),s._v(" "),a("h3",{attrs:{id:"_2-4-free"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-free"}},[s._v("#")]),s._v(" 2.4. free")]),s._v(" "),a("blockquote",[a("p",[s._v("free 命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/free")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("free")]),s._v(" -t "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 以总和的形式显示内存的使用信息")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("free")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 周期性的查询内存使用信息,每10s 执行一次命令")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示内存使用情况")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("free")]),s._v(" -m\n total used "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("free")]),s._v(" shared buffers cached\nMem: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2016")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1973")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("42")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("163")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1497")]),s._v("\n-/+ buffers/cache: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("312")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1703")]),s._v("\nSwap: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4094")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4094")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-5-iotop"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-iotop"}},[s._v("#")]),s._v(" 2.5. iotop")]),s._v(" "),a("blockquote",[a("p",[s._v("iotop 命令是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/iotop")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("Total DISK read: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" Total DISK write: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s\n TID PRIO "),a("span",{pre:!0,attrs:{class:"token environment constant"}},[s._v("USER")]),s._v(" DISK READ DISK WRITE SWAPIN IO"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % init "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("kthreadd"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("migration/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("ksoftirqd/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("watchdog/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("migration/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("ksoftirqd/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v(" rt/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("watchdog/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("events/0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("events/1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("khelper"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2572")]),s._v(" be/4 root "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" B/s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.00")]),s._v(" % "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("bluetooth"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/28.703f74c2.js b/assets/js/28.703f74c2.js new file mode 100644 index 0000000..02b9272 --- /dev/null +++ b/assets/js/28.703f74c2.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{416:function(a,t,s){"use strict";s.r(t);var n=s(15),e=Object(n.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"查看-linux-命令帮助信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查看-linux-命令帮助信息"}},[a._v("#")]),a._v(" 查看 Linux 命令帮助信息")]),a._v(" "),s("blockquote",[s("p",[a._v("Linux 中有非常多的命令,想全部背下来是很困难的事。所以,我认为学习 Linux 的第一步,就是了解如何快速检索命令说明。")]),a._v(" "),s("p",[a._v("关键词:"),s("code",[a._v("help")]),a._v(", "),s("code",[a._v("whatis")]),a._v(", "),s("code",[a._v("info")]),a._v(", "),s("code",[a._v("which")]),a._v(", "),s("code",[a._v("whereis")]),a._v(", "),s("code",[a._v("man")])])]),a._v(" "),s("h2",{attrs:{id:"_1-查看-linux-命令帮助信息的要点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-查看-linux-命令帮助信息的要点"}},[a._v("#")]),a._v(" 1. 查看 Linux 命令帮助信息的要点")]),a._v(" "),s("ul",[s("li",[a._v("查看 Shell 内部命令的帮助信息 - 使用 "),s("a",{attrs:{href:"#help"}},[a._v("help")])]),a._v(" "),s("li",[a._v("查看命令的简要说明 - 使用 "),s("a",{attrs:{href:"#whatis"}},[a._v("whatis")])]),a._v(" "),s("li",[a._v("查看命令的详细说明 - 使用 "),s("a",{attrs:{href:"#info"}},[a._v("info")])]),a._v(" "),s("li",[a._v("查看命令的位置 - 使用 "),s("a",{attrs:{href:"#which"}},[a._v("which")])]),a._v(" "),s("li",[a._v("定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径 - 使用 "),s("a",{attrs:{href:"#whereis"}},[a._v("whereis")])]),a._v(" "),s("li",[a._v("查看命令的帮助手册(包含说明、用法等信息) - 使用 "),s("a",{attrs:{href:"#man"}},[a._v("man")])]),a._v(" "),s("li",[a._v("只记得部分命令关键字 - 使用 man -k")])]),a._v(" "),s("blockquote",[s("p",[a._v("注:推荐一些 Linux 命令中文手册:")]),a._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"http://man.linuxde.net/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Linux 命令大全"),s("OutboundLink")],1)]),a._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/jaywcjlove/linux-command",target:"_blank",rel:"noopener noreferrer"}},[a._v("linux-command"),s("OutboundLink")],1)])])]),a._v(" "),s("h2",{attrs:{id:"_2-命令常见用法"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[a._v("#")]),a._v(" 2. 命令常见用法")]),a._v(" "),s("h3",{attrs:{id:"_2-1-help"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-help"}},[a._v("#")]),a._v(" 2.1. help")]),a._v(" "),s("blockquote",[s("p",[a._v("help 命令用于查看 Shell 内部命令的帮助信息。而对于外部命令的帮助信息只能使用 man 或者 info 命令查看。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/help")])]),a._v(" "),s("h3",{attrs:{id:"_2-2-whatis"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-whatis"}},[a._v("#")]),a._v(" 2.2. whatis")]),a._v(" "),s("blockquote",[s("p",[a._v("whatis 用于查询一个命令执行什么功能。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/whatis")])]),a._v(" "),s("p",[a._v("示例:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查看 man 命令的简要说明")]),a._v("\n$ whatis "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查看以 loca 开拓的命令的简要说明")]),a._v("\n$ whatis -w "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"loca*"')]),a._v("\n")])])]),s("h3",{attrs:{id:"_2-3-info"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-info"}},[a._v("#")]),a._v(" 2.3. info")]),a._v(" "),s("blockquote",[s("p",[a._v("info 是 Linux 下 info 格式的帮助指令。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/info")])]),a._v(" "),s("p",[a._v("示例:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查看 man 命令的详细说明")]),a._v("\n$ info "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v("\n")])])]),s("h3",{attrs:{id:"_2-4-which"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-which"}},[a._v("#")]),a._v(" 2.4. which")]),a._v(" "),s("blockquote",[s("p",[a._v("which 命令用于查找并显示给定命令的绝对路径,环境变量 PATH 中保存了查找命令时需要遍历的目录。which 指令会在环境变量$PATH 设置的目录里查找符合条件的文件。也就是说,使用 which 命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/which")])]),a._v(" "),s("p",[a._v("示例:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("which")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("pwd")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查找命令的路径")]),a._v("\n")])])]),s("p",[a._v("说明:which 是根据使用者所配置的 PATH 变量内的目录去搜寻可运行档的!所以,不同的 PATH 配置内容所找到的命令当然不一样的!")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("root@localhost ~"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# which cd")]),a._v("\ncd: shell built-in "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("command")]),a._v("\n")])])]),s("p",[a._v("cd 这个常用的命令竟然找不到啊!为什么呢?这是因为 cd 是 bash 内建的命令!但是 which 默认是找 PATH 内所规范的目录,所以当然一定找不到的!")]),a._v(" "),s("h3",{attrs:{id:"_2-5-whereis"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-whereis"}},[a._v("#")]),a._v(" 2.5. whereis")]),a._v(" "),s("blockquote",[s("p",[a._v("whereis 命令用来定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径。")]),a._v(" "),s("p",[a._v("whereis 命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man 说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/whereis")])]),a._v(" "),s("p",[a._v("示例:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("whereis")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("git")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 将相关的文件都查找出来")]),a._v("\n")])])]),s("h3",{attrs:{id:"_2-6-man"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-man"}},[a._v("#")]),a._v(" 2.6. man")]),a._v(" "),s("blockquote",[s("p",[a._v("man 命令是 Linux 下的帮助指令,通过 man 指令可以查看 Linux 中的指令帮助、配置文件帮助和编程帮助等信息。")]),a._v(" "),s("p",[a._v("参考:http://man.linuxde.net/man")])]),a._v(" "),s("p",[a._v("示例:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("$ "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("date")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查看 date 命令的帮助手册")]),a._v("\n$ "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查看 printf 命令的帮助手册中的第 3 类")]),a._v("\n$ "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v(" -k keyword "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 根据命令中部分关键字来查询命令")]),a._v("\n")])])]),s("h4",{attrs:{id:"_2-6-1-man-要点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-1-man-要点"}},[a._v("#")]),a._v(" 2.6.1. man 要点")]),a._v(" "),s("p",[a._v("在 man 的帮助手册中,可以使用 page up 和 page down 来上下翻页。")]),a._v(" "),s("p",[a._v("man 的帮助手册中,将帮助文档分为了 9 个类别,对于有的关键字可能存在多个类别中, 我们就需要指定特定的类别来查看;(一般我们查询 bash 命令,归类在 1 类中)。")]),a._v(" "),s("p",[a._v("man 页面的分类(常用的是分类 1 和分类 3):")]),a._v(" "),s("ol",[s("li",[a._v("可执行程序或 shell 命令")]),a._v(" "),s("li",[a._v("系统调用(内核提供的函数)")]),a._v(" "),s("li",[a._v("库调用(程序库中的函数)")]),a._v(" "),s("li",[a._v("特殊文件(通常位于 /dev)")]),a._v(" "),s("li",[a._v("文件格式和规范,如 /etc/passwd")]),a._v(" "),s("li",[a._v("游戏")]),a._v(" "),s("li",[a._v("杂项(包括宏包和规范,如 man(7),groff(7))")]),a._v(" "),s("li",[a._v("系统管理命令(通常只针对 root 用户)")]),a._v(" "),s("li",[a._v("内核例程 [非标准]")])]),a._v(" "),s("p",[a._v("前面说到使用 whatis 会显示命令所在的具体的文档类别,我们学习如何使用它")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("$ whatis "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" - "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("format")]),a._v(" and print data\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("1p"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" - "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("write")]),a._v(" formatted output\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" - formatted output conversion\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("3p"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" - print formatted output\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("builtins"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" - "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("bash")]),a._v(" built-in commands, see bash"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n")])])]),s("p",[a._v("我们看到 printf 在分类 1 和分类 3 中都有;分类 1 中的页面是命令操作及可执行文件的帮助;而 3 是常用函数库说明;如果我们想看的是 C 语言中 printf 的用法,可以指定查看分类 3 的帮助:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("$ "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("man")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("printf")]),a._v("\n")])])]),s("h2",{attrs:{id:"_3-参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-参考资料"}},[a._v("#")]),a._v(" 3. 参考资料")]),a._v(" "),s("p",[a._v("https://linuxtools-rst.readthedocs.io/zh_CN/latest/base/01_use_man.html")])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/29.02a952cb.js b/assets/js/29.02a952cb.js new file mode 100644 index 0000000..39e22ca --- /dev/null +++ b/assets/js/29.02a952cb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{417:function(s,t,a){"use strict";a.r(t);var n=a(15),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"linux-网络管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linux-网络管理"}},[s._v("#")]),s._v(" Linux 网络管理")]),s._v(" "),a("blockquote",[a("p",[s._v("关键词:"),a("code",[s._v("curl")]),s._v(", "),a("code",[s._v("wget")]),s._v(", "),a("code",[s._v("telnet")]),s._v(", "),a("code",[s._v("ip")]),s._v(", "),a("code",[s._v("hostname")]),s._v(", "),a("code",[s._v("ifconfig")]),s._v(", "),a("code",[s._v("route")]),s._v(", "),a("code",[s._v("ssh")]),s._v(", "),a("code",[s._v("ssh-keygen")]),s._v(", "),a("code",[s._v("firewalld")]),s._v(", "),a("code",[s._v("iptables")]),s._v(", "),a("code",[s._v("host")]),s._v(", "),a("code",[s._v("nslookup")]),s._v(", "),a("code",[s._v("nc")]),s._v("/"),a("code",[s._v("netcat")]),s._v(", "),a("code",[s._v("ping")]),s._v(", "),a("code",[s._v("traceroute")]),s._v(", "),a("code",[s._v("netstat")])])]),s._v(" "),a("h2",{attrs:{id:"_1-linux-网络应用要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-网络应用要点"}},[s._v("#")]),s._v(" 1. Linux 网络应用要点")]),s._v(" "),a("ul",[a("li",[s._v("下载文件 - 使用 "),a("a",{attrs:{href:"#curl"}},[s._v("curl")]),s._v("、"),a("a",{attrs:{href:"#wget"}},[s._v("wget")])]),s._v(" "),a("li",[s._v("telnet 方式登录远程主机,对远程主机进行管理 - 使用 "),a("a",{attrs:{href:"#telnet"}},[s._v("telnet")])]),s._v(" "),a("li",[s._v("查看或操纵 Linux 主机的路由、网络设备、策略路由和隧道 - 使用 "),a("a",{attrs:{href:"#ip"}},[s._v("ip")])]),s._v(" "),a("li",[s._v("查看和设置系统的主机名 - 使用 "),a("a",{attrs:{href:"#hostname"}},[s._v("hostname")])]),s._v(" "),a("li",[s._v("查看和配置 Linux 内核中网络接口的网络参数 - 使用 "),a("a",{attrs:{href:"#ifconfig"}},[s._v("ifconfig")])]),s._v(" "),a("li",[s._v("查看和设置 Linux 内核中的网络路由表 - 使用 "),a("a",{attrs:{href:"#route"}},[s._v("route")])]),s._v(" "),a("li",[s._v("ssh 方式连接远程主机 - 使用 ssh")]),s._v(" "),a("li",[s._v("为 ssh 生成、管理和转换认证密钥 - 使用 "),a("a",{attrs:{href:"#ssh-keygen"}},[s._v("ssh-keygen")])]),s._v(" "),a("li",[s._v("查看、设置防火墙(Centos7),使用 "),a("a",{attrs:{href:"#firewalld"}},[s._v("firewalld")])]),s._v(" "),a("li",[s._v("查看、设置防火墙(Centos7 以前),使用 "),a("a",{attrs:{href:"#iptables"}},[s._v("iptables")])]),s._v(" "),a("li",[s._v("查看域名信息 - 使用 "),a("a",{attrs:{href:"#host"}},[s._v("host")]),s._v(", "),a("a",{attrs:{href:"#nslookup"}},[s._v("nslookup")])]),s._v(" "),a("li",[s._v("设置路由 - 使用 "),a("a",{attrs:{href:"#ncnetcat"}},[s._v("nc/netcat")])]),s._v(" "),a("li",[s._v("测试主机之间网络是否连通 - 使用 "),a("a",{attrs:{href:"#ping"}},[s._v("ping")])]),s._v(" "),a("li",[s._v("追踪数据在网络上的传输时的全部路径 - 使用 "),a("a",{attrs:{href:"#traceroute"}},[s._v("traceroute")])]),s._v(" "),a("li",[s._v("查看当前工作的端口信息 - 使用 "),a("a",{attrs:{href:"#netstat"}},[s._v("netstat")])])]),s._v(" "),a("h2",{attrs:{id:"_2-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[s._v("#")]),s._v(" 2. 命令常见用法")]),s._v(" "),a("h3",{attrs:{id:"_2-1-curl"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-curl"}},[s._v("#")]),s._v(" 2.1. curl")]),s._v(" "),a("blockquote",[a("p",[s._v("curl 命令是一个利用 URL 规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称 curl 为下载工具。作为一款强力工具,curl 支持包括 HTTP、HTTPS、ftp 等众多协议,还支持 POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。做网页处理流程和数据检索自动化,curl 可以祝一臂之力。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/curl")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 下载文件")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("curl")]),s._v(" http://man.linuxde.net/text.iso --silent\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 下载文件,指定下载路径,并查看进度")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("curl")]),s._v(" http://man.linuxde.net/test.iso -o filename.iso --progress\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("########################################## 100.0%")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-2-wget"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-wget"}},[s._v("#")]),s._v(" 2.2. wget")]),s._v(" "),a("blockquote",[a("p",[s._v("wget 命令用来从指定的 URL 下载文件。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/wget")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 使用 wget 下载单个文件")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("wget")]),s._v(" http://www.linuxde.net/testfile.zip\n")])])]),a("h3",{attrs:{id:"_2-3-telnet"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-telnet"}},[s._v("#")]),s._v(" 2.3. telnet")]),s._v(" "),a("blockquote",[a("p",[s._v("telnet 命令用于登录远程主机,对远程主机进行管理。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/telnet")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("telnet "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".2.10\nTrying "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".2.10"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".\nConnected to "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".2.10 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".2.10"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(".\nEscape character is "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'^]'")]),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v(".")]),s._v("\n\n localhost "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("Linux release "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2.6")]),s._v(".18-274.18.1.el5 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#1 SMP Thu Feb 9 12:45:44 EST 2012) (1)")]),s._v("\n\nlogin: root\nPassword:\nLogin incorrect\n")])])]),a("h3",{attrs:{id:"_2-4-ip"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-ip"}},[s._v("#")]),s._v(" 2.4. ip")]),s._v(" "),a("blockquote",[a("p",[s._v("ip 命令用来查看或操纵 Linux 主机的路由、网络设备、策略路由和隧道,是 Linux 下较新的功能强大的网络配置工具。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ip")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" show "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看网络接口信息")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 upi "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 开启网卡")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 down "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 关闭网卡")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 promisc on "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 开启网卡的混合模式")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 promisc offi "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 关闭网卡的混个模式")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 txqueuelen "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1200")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置网卡队列长度")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("link")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("set")]),s._v(" eth0 mtu "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1400")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置网卡最大传输单元")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" addr show "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看网卡IP信息")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" addr "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.1/24 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置eth0网卡IP地址192.168.0.1")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" addr del "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.1/24 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除eth0网卡IP地址")]),s._v("\n\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route show "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看系统路由")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" default via "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".1.254 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置系统默认路由")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route list "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看路由信息")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".4.0/24 via "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.254 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置192.168.4.0网段的网关为192.168.0.254,数据走eth0接口")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" default via "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.254 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置默认网关为192.168.0.254")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route del "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".4.0/24 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除192.168.4.0网段的网关")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route del default "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除默认路由")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ip")]),s._v(" route delete "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".1.0/24 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除路由")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-5-hostname"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-hostname"}},[s._v("#")]),s._v(" 2.5. hostname")]),s._v(" "),a("blockquote",[a("p",[s._v("hostname 命令用于查看和设置系统的主机名称。环境变量 HOSTNAME 也保存了当前的主机名。在使用 hostname 命令设置主机名后,系统并不会永久保存新的主机名,重新启动机器之后还是原来的主机名。如果需要永久修改主机名,需要同时修改 "),a("code",[s._v("/etc/hosts")]),s._v(" 和 "),a("code",[s._v("/etc/sysconfig/network")]),s._v(" 的相关内容。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/hostname")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("hostname")]),s._v("\nAY1307311912260196fcZ\n")])])]),a("h3",{attrs:{id:"_2-6-ifconfig"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-ifconfig"}},[s._v("#")]),s._v(" 2.6. ifconfig")]),s._v(" "),a("blockquote",[a("p",[s._v("ifconfig 命令被用于查看和配置 Linux 内核中网络接口的网络参数。用 ifconfig 命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ifconfig")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看网络设备信息(激活状态的)")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ifconfig")]),s._v("\neth0 Link encap:Ethernet HWaddr 00:16:3E:00:1E:51\n inet addr:10.160.7.81 Bcast:10.160.15.255 Mask:255.255.240.0\n UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1\n RX packets:61430830 errors:0 dropped:0 overruns:0 frame:0\n TX packets:88534 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txqueuelen:1000\n RX bytes:3607197869 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3.3")]),s._v(" GiB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" TX bytes:6115042 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5.8")]),s._v(" MiB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n\nlo Link encap:Local Loopback\n inet addr:127.0.0.1 Mask:255.0.0.0\n UP LOOPBACK RUNNING MTU:16436 Metric:1\n RX packets:56103 errors:0 dropped:0 overruns:0 frame:0\n TX packets:56103 errors:0 dropped:0 overruns:0 carrier:0\n collisions:0 txqueuelen:0\n RX bytes:5079451 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4.8")]),s._v(" MiB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" TX bytes:5079451 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4.8")]),s._v(" MiB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-7-route"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-route"}},[s._v("#")]),s._v(" 2.7. route")]),s._v(" "),a("blockquote",[a("p",[s._v("route 命令用来查看和设置 Linux 内核中的网络路由表,route 命令设置的路由主要是静态路由。要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/route")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看当前路由")]),s._v("\nroute\nKernel IP routing table\nDestination Gateway Genmask Flags Metric Ref Use Iface\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("112.124")]),s._v(".12.0 * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("255.255")]),s._v(".252.0 U "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth1\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.160")]),s._v(".0.0 * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("255.255")]),s._v(".240.0 U "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth0\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.160")]),s._v(".15.247 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("255.255")]),s._v(".0.0 UG "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth0\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("172.16")]),s._v(".0.0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.160")]),s._v(".15.247 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("255.240")]),s._v(".0.0 UG "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth0\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.0")]),s._v(".0.0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10.160")]),s._v(".15.247 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("255.0")]),s._v(".0.0 UG "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth0\ndefault "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("112.124")]),s._v(".15.247 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0 UG "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" eth1\n\nroute "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" -net "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("224.0")]),s._v(".0.0 netmask "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("240.0")]),s._v(".0.0 dev eth0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 添加网关/设置网关")]),s._v("\nroute "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" -net "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("224.0")]),s._v(".0.0 netmask "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("240.0")]),s._v(".0.0 reject "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 屏蔽一条路由")]),s._v("\nroute del -net "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("224.0")]),s._v(".0.0 netmask "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("240.0")]),s._v(".0.0 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除路由记录")]),s._v("\nroute "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("add")]),s._v(" default gw "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".120.240 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 添加默认网关")]),s._v("\nroute del default gw "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".120.240 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除默认网关")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-8-ssh"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-ssh"}},[s._v("#")]),s._v(" 2.8. ssh")]),s._v(" "),a("blockquote",[a("p",[s._v("ssh 命令是 openssh 套件中的客户端连接工具,可以给予 ssh 加密协议实现安全的远程登录服务器。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ssh")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ssh 用户名@远程服务器地址")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ssh")]),s._v(" user1@172.24.210.101\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ssh")]),s._v(" -p "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2211")]),s._v(" root@140.206.185.170\n")])])]),a("p",[s._v("引申阅读:"),a("a",{attrs:{href:"https://linux.cn/article-8476-1.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("ssh 背后的故事"),a("OutboundLink")],1)]),s._v(" "),a("h3",{attrs:{id:"_2-9-ssh-keygen"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-ssh-keygen"}},[s._v("#")]),s._v(" 2.9. ssh-keygen")]),s._v(" "),a("blockquote",[a("p",[s._v("ssh-keygen 命令用于为 ssh 生成、管理和转换认证密钥,它支持 RSA 和 DSA 两种认证密钥。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ssh-keygen")])]),s._v(" "),a("h3",{attrs:{id:"_2-10-firewalld"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-firewalld"}},[s._v("#")]),s._v(" 2.10. firewalld")]),s._v(" "),a("blockquote",[a("p",[s._v("firewalld 命令是 Linux 上的防火墙软件(Centos7 默认防火墙)。")]),s._v(" "),a("p",[s._v("参考:https://www.cnblogs.com/moxiaoan/p/5683743.html")])]),s._v(" "),a("h4",{attrs:{id:"_2-10-1-firewalld-的基本使用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-1-firewalld-的基本使用"}},[s._v("#")]),s._v(" 2.10.1. firewalld 的基本使用")]),s._v(" "),a("ul",[a("li",[s._v("启动 - systemctl start firewalld")]),s._v(" "),a("li",[s._v("关闭 - systemctl stop firewalld")]),s._v(" "),a("li",[s._v("查看状态 - systemctl status firewalld")]),s._v(" "),a("li",[s._v("开机禁用 - systemctl disable firewalld")]),s._v(" "),a("li",[s._v("开机启用 - systemctl enable firewalld")])]),s._v(" "),a("h4",{attrs:{id:"_2-10-2-使用-systemctl-管理-firewalld-服务"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-2-使用-systemctl-管理-firewalld-服务"}},[s._v("#")]),s._v(" 2.10.2. 使用 systemctl 管理 firewalld 服务")]),s._v(" "),a("p",[s._v("systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前 service 和 chkconfig 的功能于一体。")]),s._v(" "),a("ul",[a("li",[s._v("启动一个服务 - systemctl start firewalld.service")]),s._v(" "),a("li",[s._v("关闭一个服务 - systemctl stop firewalld.service")]),s._v(" "),a("li",[s._v("重启一个服务 - systemctl restart firewalld.service")]),s._v(" "),a("li",[s._v("显示一个服务的状态 - systemctl status firewalld.service")]),s._v(" "),a("li",[s._v("在开机时启用一个服务 - systemctl enable firewalld.service")]),s._v(" "),a("li",[s._v("在开机时禁用一个服务 - systemctl disable firewalld.service")]),s._v(" "),a("li",[s._v("查看服务是否开机启动 - systemctl is-enabled firewalld.service")]),s._v(" "),a("li",[s._v("查看已启动的服务列表 - systemctl list-unit-files|grep enabled")]),s._v(" "),a("li",[s._v("查看启动失败的服务列表 - systemctl --failed")])]),s._v(" "),a("h4",{attrs:{id:"_2-10-3-配置-firewalld-cmd"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-3-配置-firewalld-cmd"}},[s._v("#")]),s._v(" 2.10.3. 配置 firewalld-cmd")]),s._v(" "),a("ul",[a("li",[s._v("查看版本 - firewall-cmd --version")]),s._v(" "),a("li",[s._v("查看帮助 - firewall-cmd --help")]),s._v(" "),a("li",[s._v("显示状态 - firewall-cmd --state")]),s._v(" "),a("li",[s._v("查看所有打开的端口 - firewall-cmd --zone=public --list-ports")]),s._v(" "),a("li",[s._v("更新防火墙规则 - firewall-cmd --reload")]),s._v(" "),a("li",[s._v("查看区域信息: firewall-cmd --get-active-zones")]),s._v(" "),a("li",[s._v("查看指定接口所属区域 - firewall-cmd --get-zone-of-interface=eth0")]),s._v(" "),a("li",[s._v("拒绝所有包:firewall-cmd --panic-on")]),s._v(" "),a("li",[s._v("取消拒绝状态 - firewall-cmd --panic-off")]),s._v(" "),a("li",[s._v("查看是否拒绝 - firewall-cmd --query-panic")])]),s._v(" "),a("h4",{attrs:{id:"_2-10-4-在防火墙中开放一个端口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-4-在防火墙中开放一个端口"}},[s._v("#")]),s._v(" 2.10.4. 在防火墙中开放一个端口")]),s._v(" "),a("ul",[a("li",[s._v("添加(--permanent 永久生效,没有此参数重启后失效) - firewall-cmd --zone=public --add-port=80/tcp --permanent")]),s._v(" "),a("li",[s._v("重新载入 - firewall-cmd --reload")]),s._v(" "),a("li",[s._v("查看 - firewall-cmd --zone= public --query-port=80/tcp")]),s._v(" "),a("li",[s._v("删除 - firewall-cmd --zone= public --remove-port=80/tcp --permanent")])]),s._v(" "),a("h3",{attrs:{id:"_2-11-iptables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-11-iptables"}},[s._v("#")]),s._v(" 2.11. iptables")]),s._v(" "),a("blockquote",[a("p",[s._v("iptables 命令是 Linux 上常用的防火墙软件,是 netfilter 项目的一部分。可以直接配置,也可以通过许多前端和图形界面配置。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/iptables")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 开放指定的端口")]),s._v("\niptables -A INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("127.0")]),s._v(".0.1 -d "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("127.0")]),s._v(".0.1 -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许本地回环接口(即运行本机访问本机)")]),s._v("\niptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许已建立的或相关连的通行")]),s._v("\niptables -A OUTPUT -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许所有本机向外的访问")]),s._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("22")]),s._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许访问22端口")]),s._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许访问80端口")]),s._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许ftp服务的21端口")]),s._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("20")]),s._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#允许FTP服务的20端口")]),s._v("\niptables -A INPUT -j reject "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#禁止其他未允许的规则访问")]),s._v("\niptables -A FORWARD -j REJECT "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#禁止其他未允许的规则访问")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 屏蔽IP")]),s._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.45")]),s._v(".6.7 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#屏蔽单个IP的命令")]),s._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.0")]),s._v(".0.0/8 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#封整个段即从123.0.0.1到123.255.255.254的命令")]),s._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("124.45")]),s._v(".0.0/16 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#封IP段即从123.45.0.1到123.45.255.254的命令")]),s._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.45")]),s._v(".6.0/24 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#封IP段即从123.45.6.1到123.45.6.254的命令是")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查看已添加的iptables规则")]),s._v("\niptables -L -n -v\nChain INPUT "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("policy DROP "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("48106")]),s._v(" packets, 2690K bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" destination\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5075")]),s._v(" 589K ACCEPT all -- lo * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0\n 191K 90M ACCEPT tcp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 tcp dpt:22\n1499K 133M ACCEPT tcp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 tcp dpt:80\n4364K 6351M ACCEPT all -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 state RELATED,ESTABLISHED\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6256")]),s._v(" 327K ACCEPT icmp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0\n\nChain FORWARD "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("policy ACCEPT "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" packets, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" destination\n\nChain OUTPUT "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("policy ACCEPT 3382K packets, 1819M bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" destination\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5075")]),s._v(" 589K ACCEPT all -- * lo "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v(".0.0/0\n")])])]),a("h3",{attrs:{id:"_2-12-host"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-12-host"}},[s._v("#")]),s._v(" 2.12. host")]),s._v(" "),a("blockquote",[a("p",[s._v("host 命令是常用的分析域名查询工具,可以用来测试域名系统工作是否正常。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/host")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# host www.jsdig.com")]),s._v("\nwww.jsdig.com is an "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" host.1.jsdig.com.\nhost.1.jsdig.com has address "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# host -a www.jsdig.com")]),s._v("\nTrying "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"www.jsdig.com"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" -"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">>")]),s._v("HEADER"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<<-")]),s._v(" opcode: QUERY, status: NOERROR, id: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("34671")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" flags: qr rd ra"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" QUERY: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(", ANSWER: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(", AUTHORITY: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(", ADDITIONAL: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" QUESTION SECTION:\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("www.jsdig.com. IN ANY\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" ANSWER SECTION:\nwww.jsdig.com. "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("463")]),s._v(" IN CNAME host.1.jsdig.com.\n\nReceived "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("54")]),s._v(" bytes from "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("202.96")]),s._v(".104.15"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#53 in 0 ms")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-13-nslookup"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-13-nslookup"}},[s._v("#")]),s._v(" 2.13. nslookup")]),s._v(" "),a("blockquote",[a("p",[s._v("nslookup 命令是常用域名查询工具,就是查 DNS 信息用的命令。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/nslookup")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# nslookup www.jsdig.com")]),s._v("\nServer: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("202.96")]),s._v(".104.15\nAddress: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("202.96")]),s._v(".104.15"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#53")]),s._v("\n\nNon-authoritative answer:\nwww.jsdig.com canonical name "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" host.1.jsdig.com.\nName: host.1.jsdig.com\nAddress: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8\n")])])]),a("h3",{attrs:{id:"_2-14-nc-netcat"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-14-nc-netcat"}},[s._v("#")]),s._v(" 2.14. nc/netcat")]),s._v(" "),a("blockquote",[a("p",[s._v("nc 命令是 netcat 命令的简称,都是用来设置路由器。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/nc_netcat")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# TCP 端口扫描")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# nc -v -z -w2 192.168.0.3 1-100")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.3: inverse "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("host")]),s._v(" lookup failed: Unknown "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("host")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("UNKNOWN"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.3"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("80")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("http"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("open")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("UNKNOWN"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.3"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("23")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("telnet"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("open")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("UNKNOWN"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".0.3"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("22")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("ssh"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("open")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# UDP 端口扫描")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# nc -u -z -w2 192.168.0.1 1-1000 # 扫描192.168.0.3 的端口 范围是 1-1000")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-15-ping"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-15-ping"}},[s._v("#")]),s._v(" 2.15. ping")]),s._v(" "),a("blockquote",[a("p",[s._v("ping 命令用来测试主机之间网络的连通性。执行 ping 指令会使用 ICMP 传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而得知该主机运作正常。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ping")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@AY1307311912260196fcZ ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ping www.jsdig.com")]),s._v("\nPING host.1.jsdig.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("56")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("84")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" bytes of data.\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("64")]),s._v(" bytes from "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v("-42-212-8.static.webnx.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(": "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("icmp_seq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ttl")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("50")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("time")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("177")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("64")]),s._v(" bytes from "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v("-42-212-8.static.webnx.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(": "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("icmp_seq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ttl")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("50")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("time")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("178")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("64")]),s._v(" bytes from "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v("-42-212-8.static.webnx.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(": "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("icmp_seq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ttl")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("50")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("time")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("174")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("64")]),s._v(" bytes from "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v("-42-212-8.static.webnx.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("100.42")]),s._v(".212.8"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(": "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("icmp_seq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ttl")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("50")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("time")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("177")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("..")]),s._v(".按Ctrl+C结束\n\n--- host.1.jsdig.com "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ping")]),s._v(" statistics ---\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" packets transmitted, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" received, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("% packet loss, "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("time")]),s._v(" 2998ms\nrtt min/avg/max/mdev "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("174.068")]),s._v("/176.916/178.182/1.683 ms\n")])])]),a("h3",{attrs:{id:"_2-16-traceroute"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-16-traceroute"}},[s._v("#")]),s._v(" 2.16. traceroute")]),s._v(" "),a("blockquote",[a("p",[s._v("traceroute 命令用于追踪数据包在网络上的传输时的全部路径,它默认发送的数据包大小是 40 字节。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/traceroute")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("traceroute")]),s._v(" www.58.com\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("traceroute")]),s._v(" to www.58.com "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("211.151")]),s._v(".111.30"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(", "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("30")]),s._v(" hops max, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("40")]),s._v(" byte packets\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" unknown "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("192.168")]),s._v(".2.1"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3.453")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3.801")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3.937")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".45.33 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".45.33"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7.768")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7.816")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7.840")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".0.233 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".0.233"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("13.784")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("13.827")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".9.81 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".9.81"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9.758")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".2.169 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".2.169"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11.777")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("122.96")]),s._v(".66.13 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("122.96")]),s._v(".66.13"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("34.952")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".2.53 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("221.6")]),s._v(".2.53"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("41.372")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("219.158")]),s._v(".96.149 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("219.158")]),s._v(".96.149"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.167")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.210")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.238")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.126")]),s._v(".0.194 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.126")]),s._v(".0.194"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("37.270")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.126")]),s._v(".0.66 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("123.126")]),s._v(".0.66"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("37.163")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("37.441")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("124.65")]),s._v(".57.26 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("124.65")]),s._v(".57.26"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("42.787")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("42.799")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("42.809")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("61.148")]),s._v(".146.210 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("61.148")]),s._v(".146.210"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("30.176")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("61.148")]),s._v(".154.98 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("61.148")]),s._v(".154.98"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("32.613")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("32.675")]),s._v(" ms\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("202.106")]),s._v(".42.102 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("202.106")]),s._v(".42.102"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("44.563")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("44.600")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("44.627")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("210.77")]),s._v(".139.150 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("210.77")]),s._v(".139.150"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("53.302")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("53.233")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("53.032")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("211.151")]),s._v(".104.6 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("211.151")]),s._v(".104.6"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.585")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.502")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39.598")]),s._v(" ms\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("12")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("211.151")]),s._v(".111.30 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("211.151")]),s._v(".111.30"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("35.161")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("35.938")]),s._v(" ms "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("36.005")]),s._v(" ms\n")])])]),a("h3",{attrs:{id:"_2-17-netstat"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-17-netstat"}},[s._v("#")]),s._v(" 2.17. netstat")]),s._v(" "),a("blockquote",[a("p",[s._v("netstat 命令用来打印 Linux 中网络系统的状态信息,可让你得知整个 Linux 系统的网络情况。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/netstat")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出所有端口 (包括监听和未监听的)")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -a "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#列出所有端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -at "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#列出所有tcp端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -au "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#列出所有udp端口")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出所有处于监听状态的 Sockets")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -l "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#只显示监听端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -lt "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#只列出所有监听 tcp 端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -lu "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#只列出所有监听 udp 端口")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -lx "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#只列出所有监听 UNIX 端口")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示每个协议的统计信息")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -s 显示所有端口的统计信息\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -st 显示TCP端口的统计信息\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("netstat")]),s._v(" -su 显示UDP端口的统计信息\n")])])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/30.7e13628f.js b/assets/js/30.7e13628f.js new file mode 100644 index 0000000..235d325 --- /dev/null +++ b/assets/js/30.7e13628f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{418:function(t,a,e){"use strict";e.r(a);var s=e(15),n=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"linux-软件管理"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#linux-软件管理"}},[t._v("#")]),t._v(" Linux 软件管理")]),t._v(" "),e("blockquote",[e("p",[t._v("关键词:"),e("code",[t._v("rpm")]),t._v(", "),e("code",[t._v("yum")]),t._v(", "),e("code",[t._v("apt-get")])])]),t._v(" "),e("h2",{attrs:{id:"_1-rpm"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-rpm"}},[t._v("#")]),t._v(" 1. rpm")]),t._v(" "),e("blockquote",[e("p",[t._v("rpm 命令是 RPM 软件包的管理工具。rpm 原本是 Red Hat Linux 发行版专门用来管理 Linux 各项套件的程序,由于它遵循 GPL 规则且功能强大方便,因而广受欢迎。逐渐受到其他发行版的采用。RPM 套件管理方式的出现,让 Linux 易于安装,升级,间接提升了 Linux 的适用度。")]),t._v(" "),e("p",[t._v("参考:http://man.linuxde.net/rpm")])]),t._v(" "),e("p",[t._v("示例:")]),t._v(" "),e("p",[t._v("(1)安装 rpm 包")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("rpm -ivh xxx.rpm\n")])])]),e("p",[t._v("(2)安装.src.rpm 软件包")]),t._v(" "),e("p",[t._v("这类软件包是包含了源代码的 rpm 包,在安装时需要进行编译")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -i xxx.src.rpm\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" /usr/src/redhat/SPECS\nrpmbuild -bp xxx.specs "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#一个和你的软件包同名的specs文件")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" /usr/src/redhat/BUILD/xxx/ "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#一个和你的软件包同名的目录")]),t._v("\n./configure "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#这一步和编译普通的源码软件一样,可以加上参数")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("make")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("make")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v("\n")])])]),e("p",[t._v("(3)卸载 rpm 软件包")]),t._v(" "),e("p",[t._v("使用命令 "),e("code",[t._v("rpm -e 包名")]),t._v(",包名可以包含版本号等信息,但是不可以有后缀.rpm,比如卸载软件包 proftpd-1.2.8-1,可以使用下列格式:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1.2.8-1\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1.2.8\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd\n")])])]),e("p",[t._v("不可以是下列格式:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1.2.8-1.i386.rpm\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1.2.8-1.i386\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1.2\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -e proftpd-1\n")])])]),e("p",[t._v("有时会出现一些错误或者警告:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("... is needed by ...\n")])])]),e("p",[t._v("这说明这个软件被其他软件需要,不能随便卸载,可以用 rpm -e --nodeps 强制卸载")]),t._v(" "),e("p",[t._v("(4)查看与 rpm 包相关的文件和其他信息")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" -qa "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有安装过的包")]),t._v("\n")])])]),e("h2",{attrs:{id:"_2-yum"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-yum"}},[t._v("#")]),t._v(" 2. yum")]),t._v(" "),e("blockquote",[e("p",[t._v("yum 命令是在 Fedora 和 RedHat 以及 SUSE 中基于 rpm 的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理 RPM 软件包,能够从指定的服务器自动下载 RPM 包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载、安装。")]),t._v(" "),e("p",[t._v("参考:http://man.linuxde.net/yum")])]),t._v(" "),e("p",[t._v("示例:")]),t._v(" "),e("p",[t._v("部分常用的命令包括:")]),t._v(" "),e("ul",[e("li",[t._v("自动搜索最快镜像插件:"),e("code",[t._v("yum install yum-fastestmirror")])]),t._v(" "),e("li",[t._v("安装 yum 图形窗口插件:"),e("code",[t._v("yum install yumex")])]),t._v(" "),e("li",[t._v("查看可能批量安装的列表:"),e("code",[t._v("yum grouplist")])])]),t._v(" "),e("p",[e("strong",[t._v("安装")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("yum install #全部安装\nyum install package1 #安装指定的安装包package1\nyum groupinsall group1 #安装程序组group1\n")])])]),e("p",[e("strong",[t._v("更新和升级")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("yum update #全部更新\nyum update package1 #更新指定程序包package1\nyum check-update #检查可更新的程序\nyum upgrade package1 #升级指定程序包package1\nyum groupupdate group1 #升级程序组group1\n")])])]),e("p",[e("strong",[t._v("查找和显示")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("yum info package1 #显示安装包信息package1\nyum list #显示所有已经安装和可以安装的程序包\nyum list package1 #显示指定程序包安装情况package1\nyum groupinfo group1 #显示程序组group1信息yum search string 根据关键字string查找安装包\nyum search #查找软件包\n")])])]),e("p",[e("strong",[t._v("删除程序")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("yum remove #删除程序包package_name\nyum groupremove group1 #删除程序组group1\nyum deplist package1 #查看程序package1依赖情况\n")])])]),e("p",[e("strong",[t._v("清除缓存")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("yum clean packages #清除缓存目录下的软件包\nyum clean headers #清除缓存目录下的 headers\nyum clean oldheaders #清除缓存目录下旧的 headers\n")])])]),e("h3",{attrs:{id:"_2-1-yum-源"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-yum-源"}},[t._v("#")]),t._v(" 2.1. yum 源")]),t._v(" "),e("p",[t._v("yum 的默认源是国外的,下载速度比较慢,所以最好替换为一个国内的 yum 源。")]),t._v(" "),e("table",[e("thead",[e("tr",[e("th",[t._v("推荐 yum 国内源")]),t._v(" "),e("th",[t._v("源地址")])])]),t._v(" "),e("tbody",[e("tr",[e("td",[e("a",{attrs:{href:"http://mirrors.163.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://mirrors.163.com/"),e("OutboundLink")],1)]),t._v(" "),e("td",[t._v("Centos6:http://mirrors.aliyun.com/repo/Centos-6.repo"),e("br"),t._v("Centos7:http://mirrors.aliyun.com/repo/Centos-7.repo")])]),t._v(" "),e("tr",[e("td",[e("a",{attrs:{href:"http://mirrors.aliyun.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://mirrors.aliyun.com/"),e("OutboundLink")],1)]),t._v(" "),e("td",[t._v("Centos6:http://mirrors.163.com/.help/CentOS6-Base-163.repo"),e("br"),t._v("Centos7:http://mirrors.163.com/.help/CentOS7-Base-163.repo")])])])]),t._v(" "),e("blockquote",[e("p",[t._v("🔔 注意:Cento5 已废弃,只能使用 http://vault.centos.org/ 替换,但由于是国外镜像,速度较慢。")])]),t._v(" "),e("p",[t._v("替换方法,以 aliyun CentOS7 为例:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak\nwget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo\nyum clean all\nyum makecache\n")])])]),e("h2",{attrs:{id:"_3-apt-get"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-apt-get"}},[t._v("#")]),t._v(" 3. apt-get")]),t._v(" "),e("blockquote",[e("p",[t._v("apt-get 命令是 Debian Linux 发行版中的 APT 软件包管理工具。所有基于 Debian 的发行都使用这个包管理系统。deb 包可以把一个应用的文件包在一起,大体就如同 Windows 上的安装文件。")]),t._v(" "),e("p",[t._v("参考:http://man.linuxde.net/apt-get")])]),t._v(" "),e("p",[t._v("示例:")]),t._v(" "),e("p",[t._v("使用 apt-get 命令的第一步就是引入必需的软件库,Debian 的软件库也就是所有 Debian 软件包的集合,它们存在互联网上的一些公共站点上。把它们的地址加入,apt-get 就能搜索到我们想要的软件。/etc/apt/sources.list 是存放这些地址列表的配置文件,其格式如下:")]),t._v(" "),e("p",[t._v("deb [web 或 ftp 地址][发行版名字] [main/contrib/non-free]\n我们常用的 Ubuntu 就是一个基于 Debian 的发行,我们使用 apt-get 命令获取这个列表,以下是我整理的常用命令:")]),t._v(" "),e("p",[t._v("在修改 /etc/apt/sources.list 或者 /etc/apt/preferences 之后运行该命令。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 更新 apt-get")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" update\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 安装一个软件包")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" packagename\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 卸载一个已安装的软件包(保留配置文件)")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" remove packagename\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 卸载一个已安装的软件包(删除配置文件)")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" –purge remove packagename\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 如果需要空间的话,可以让这个命令来删除你已经删掉的软件")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" autoclean "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把安装的软件的备份也删除,不过这样不会影响软件的使用的")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" clean\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 更新所有已安装的软件包")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" upgrade\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 将系统升级到新版本")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("apt-get")]),t._v(" dist-upgrade\n")])])]),e("h2",{attrs:{id:"_4-参考资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-参考资料"}},[t._v("#")]),t._v(" 4. 参考资料")]),t._v(" "),e("ul",[e("li",[t._v("http://man.linuxde.net/rpm")]),t._v(" "),e("li",[t._v("http://man.linuxde.net/yum")]),t._v(" "),e("li",[t._v("http://man.linuxde.net/apt-get")]),t._v(" "),e("li",[t._v("http://www.runoob.com/linux/linux-yum.html")])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/31.c4652f75.js b/assets/js/31.c4652f75.js new file mode 100644 index 0000000..5160e0e --- /dev/null +++ b/assets/js/31.c4652f75.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{419:function(s,t,a){"use strict";a.r(t);var n=a(15),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"linux-系统管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#linux-系统管理"}},[s._v("#")]),s._v(" Linux 系统管理")]),s._v(" "),a("blockquote",[a("p",[s._v("关键词:"),a("code",[s._v("lsb_release")]),s._v(", "),a("code",[s._v("reboot")]),s._v(", "),a("code",[s._v("exit")]),s._v(", "),a("code",[s._v("shutdown")]),s._v(", "),a("code",[s._v("date")]),s._v(", "),a("code",[s._v("mount")]),s._v(", "),a("code",[s._v("umount")]),s._v(", "),a("code",[s._v("ps")]),s._v(", "),a("code",[s._v("kill")]),s._v(", "),a("code",[s._v("systemctl")]),s._v(", "),a("code",[s._v("service")]),s._v(", "),a("code",[s._v("crontab")])])]),s._v(" "),a("h2",{attrs:{id:"_1-linux-系统管理要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-系统管理要点"}},[s._v("#")]),s._v(" 1. Linux 系统管理要点")]),s._v(" "),a("ul",[a("li",[s._v("查看 Linux 系统发行版本\n"),a("ul",[a("li",[s._v("使用 "),a("a",{attrs:{href:"#lsb_release"}},[s._v("lsb_release")]),s._v("(此命令适用于所有的 Linux 发行版本)")]),s._v(" "),a("li",[s._v("使用 "),a("code",[s._v("cat /etc/redhat-release")]),s._v("(此方法只适合 Redhat 系的 Linux)")])])]),s._v(" "),a("li",[s._v("查看 CPU 信息 - 使用 "),a("code",[s._v("cat /proc/cpuinfo")])]),s._v(" "),a("li",[s._v("重新启动 Linux 操作系统 - 使用 "),a("a",{attrs:{href:"#reboot"}},[s._v("reboot")])]),s._v(" "),a("li",[s._v("退出 shell,并返回给定值 - 使用 "),a("a",{attrs:{href:"#exit"}},[s._v("exit")])]),s._v(" "),a("li",[s._v("关闭系统 - 使用 "),a("a",{attrs:{href:"#shutdown"}},[s._v("shutdown")])]),s._v(" "),a("li",[s._v("查看或设置系统时间与日期 - 使用 "),a("a",{attrs:{href:"#date"}},[s._v("date")])]),s._v(" "),a("li",[s._v("挂载文件系统 - 使用 "),a("a",{attrs:{href:"#mount"}},[s._v("mount")])]),s._v(" "),a("li",[s._v("取消挂载文件系统 - 使用 "),a("a",{attrs:{href:"#umount"}},[s._v("umount")])]),s._v(" "),a("li",[s._v("查看系统当前进程状态 - 使用 "),a("a",{attrs:{href:"#ps"}},[s._v("ps")])]),s._v(" "),a("li",[s._v("删除当前正在运行的进程 - 使用 "),a("a",{attrs:{href:"#kill"}},[s._v("kill")])]),s._v(" "),a("li",[s._v("启动、停止、重启、关闭、显示系统服务(Centos7),使用 "),a("a",{attrs:{href:"#systemctl"}},[s._v("systemctl")])]),s._v(" "),a("li",[s._v("启动、停止、重启、关闭、显示系统服务(Centos7 以前),使用 "),a("a",{attrs:{href:"#service"}},[s._v("service")])]),s._v(" "),a("li",[s._v("管理需要周期性执行的任务,使用 "),a("a",{attrs:{href:"#crontab"}},[s._v("crontab")])])]),s._v(" "),a("h2",{attrs:{id:"_2-命令常见用法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[s._v("#")]),s._v(" 2. 命令常见用法")]),s._v(" "),a("h3",{attrs:{id:"_2-1-lsb-release"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-lsb-release"}},[s._v("#")]),s._v(" 2.1. lsb_release")]),s._v(" "),a("p",[s._v("lsb_release 不是 bash 默认命令,如果要使用,需要先安装。")]),s._v(" "),a("p",[s._v("安装方法:")]),s._v(" "),a("ol",[a("li",[s._v("执行 "),a("code",[s._v("yum provides lsb_release")]),s._v(",查看支持 lsb_release 命令的包。")]),s._v(" "),a("li",[s._v("选择合适版本,执行类似这样的安装命令:"),a("code",[s._v("yum install -y redhat-lsb-core-4.1-27.el7.centos.1.x86_64")])])]),s._v(" "),a("h3",{attrs:{id:"_2-2-reboot"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-reboot"}},[s._v("#")]),s._v(" 2.2. reboot")]),s._v(" "),a("blockquote",[a("p",[s._v("reboot 命令用来重新启动正在运行的 Linux 操作系统。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/reboot")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("reboot")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 重开机。")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("reboot")]),s._v(" -w "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 做个重开机的模拟(只有纪录并不会真的重开机)。")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-3-exit"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-exit"}},[s._v("#")]),s._v(" 2.3. exit")]),s._v(" "),a("blockquote",[a("p",[s._v("exit 命令同于退出 shell,并返回给定值。在 shell 脚本中可以终止当前脚本执行。执行 exit 可使 shell 以指定的状态值退出。若不设置状态值参数,则 shell 以预设值退出。状态值 0 代表执行成功,其他值代表执行失败。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/exit")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 退出当前 shell")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("root@localhost ~"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# exit")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("logout")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在脚本中,进入脚本所在目录,否则退出")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("cd")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$(")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("dirname")]),s._v(" $0"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v(")")])]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("||")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("exit")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在脚本中,判断参数数量,不匹配就打印使用方式,退出")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("if")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"'),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$#")]),s._v('"')]),s._v(" -ne "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"2"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("then")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"usage: '),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$0")]),s._v(' "')]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("exit")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("fi")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在脚本中,退出时删除临时文件")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("trap")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"rm -f tmpfile; echo Bye."')]),s._v(" EXIT\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 检查上一命令的退出码")]),s._v("\n./mycommand.sh\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("EXCODE")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$?")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("if")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"'),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$EXCODE")]),s._v('"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("==")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"0"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("then")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"O.K"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("fi")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-4-shutdown"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-shutdown"}},[s._v("#")]),s._v(" 2.4. shutdown")]),s._v(" "),a("blockquote",[a("p",[s._v("shutdown 命令用来系统关机命令。shutdown 指令可以关闭所有程序,并依用户的需要,进行重新开机或关机的动作。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/shutdown")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定现在立即关机")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("shutdown")]),s._v(" -h now\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定 5 分钟后关机,同时送出警告信息给登入用户")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("shutdown")]),s._v(" +5 "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"System will shutdown after 5 minutes"')]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-5-date"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-date"}},[s._v("#")]),s._v(" 2.5. date")]),s._v(" "),a("blockquote",[a("p",[s._v("date 命令是显示或设置系统时间与日期。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/date")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 格式化输出")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2009")]),s._v("-12-07\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 输出昨天日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"1 day ago"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2012")]),s._v("-11-19\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 2 秒后输出")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"2 second"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d %H:%M.%S"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2012")]),s._v("-11-20 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("14")]),s._v(":21.31\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 传说中的 1234567890 秒")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"1970-01-01 1234567890 seconds"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d %H:%m:%S"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2009")]),s._v("-02-13 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("23")]),s._v(":02:30\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 普通转格式")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"2009-12-12"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y/%m/%d %H:%M.%S"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2009")]),s._v("/12/12 00:00.00\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# apache 格式转换")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Dec 5, 2009 12:00:37 AM"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d %H:%M.%S"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2009")]),s._v("-12-05 00:00.37\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 格式转换后时间游走")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"Dec 5, 2009 12:00:37 AM 2 year ago"')]),s._v(" +"),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"%Y-%m-%d %H:%M.%S"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2007")]),s._v("-12-05 00:00.37\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 加减操作")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示前天年月日")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"+1 day"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示前一天的日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"-1 day"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示后一天的日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"-1 month"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示上一月的日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"+1 month"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示下一月的日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"-1 year"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示前一年的日期")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -d "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"+1 year"')]),s._v(" +%Y%m%d "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示下一年的日期")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设定时间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置当前时间,只有root权限才能设置,其他只能查看")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("20120523")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置成20120523,这样会把具体时间设置成空00:00:00")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s 01:01:01 "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 设置具体时间,不会对日期做更改")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"01:01:01 2012-05-23"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 这样可以设置全部时间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"01:01:01 20120523"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 这样可以设置全部时间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"2012-05-23 01:01:01"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 这样可以设置全部时间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"20120523 01:01:01"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 这样可以设置全部时间")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 有时需要检查一组命令花费的时间")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#!/bin/bash")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("start")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$(")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" +%s"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v(")")])]),s._v("\nnmap man.linuxde.net "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("&>")]),s._v(" /dev/null\n\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("end")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$(")]),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("date")]),s._v(" +%s"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v(")")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("difference")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$((")]),s._v(" end "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("-")]),s._v(" start "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("))")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$difference")]),s._v(" seconds.\n")])])]),a("h3",{attrs:{id:"_2-6-mount"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-mount"}},[s._v("#")]),s._v(" 2.6. mount")]),s._v(" "),a("blockquote",[a("p",[s._v("mount 命令用于挂载文件系统到指定的挂载点。此命令的最常用于挂载 cdrom,使我们可以访问 cdrom 中的数据,因为你将光盘插入 cdrom 中,Linux 并不会自动挂载,必须使用 Linux mount 命令来手动完成挂载。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/mount > https://blog.csdn.net/weishujie000/article/details/76531924")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将 /dev/hda1 挂在 /mnt 之下")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mount")]),s._v(" /dev/hda1 /mnt\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将 /dev/hda1 用唯读模式挂在 /mnt 之下")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mount")]),s._v(" -o ro /dev/hda1 /mnt\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将 /tmp/image.iso 这个光碟的 image 档使用 loop 模式挂在 /mnt/cdrom 之下")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 用这种方法可以将一般网络上可以找到的 Linux ISO 在不烧录成光碟的情况下检视其内容")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("mount")]),s._v(" -o loop /tmp/image.iso /mnt/cdrom\n")])])]),a("h3",{attrs:{id:"_2-7-umount"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-umount"}},[s._v("#")]),s._v(" 2.7. umount")]),s._v(" "),a("blockquote",[a("p",[s._v("umount 命令用于卸载已经挂载的文件系统。利用设备名或挂载点都能 umount 文件系统,不过最好还是通过挂载点卸载,以免使用绑定挂载(一个设备,多个挂载点)时产生混乱。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/umount")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 通过设备名卸载")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("umount")]),s._v(" -v /dev/sda1\n/dev/sda1 umounted\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 通过挂载点卸载")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("umount")]),s._v(" -v /mnt/mymount/\n/tmp/diskboot.img umounted\n")])])]),a("h3",{attrs:{id:"_2-8-ps"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-ps"}},[s._v("#")]),s._v(" 2.8. ps")]),s._v(" "),a("blockquote",[a("p",[s._v("ps 命令用于报告当前系统的进程状态。可以搭配 kill 指令随时中断、删除不必要的程序。ps 命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/ps")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 按内存资源的使用量对进程进行排序")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ps")]),s._v(" aux "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sort")]),s._v(" -rnk "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 按 CPU 资源的使用量对进程进行排序")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ps")]),s._v(" aux "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sort")]),s._v(" -nk "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-9-kill"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-kill"}},[s._v("#")]),s._v(" 2.9. kill")]),s._v(" "),a("blockquote",[a("p",[s._v("kill 命令用来删除执行中的程序或工作。kill 可将指定的信息送至程序。预设的信息为 SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用 SIGKILL(9) 信息尝试强制删除程序。程序或工作的编号可利用 ps 指令或 job 指令查看。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/kill")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出所有信号名称")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("kill")]),s._v(" -l\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGHUP "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGINT "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGQUIT "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGILL\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("5")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGTRAP "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGABRT "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGBUS "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGFPE\n "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGKILL "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGUSR1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGSEGV "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("12")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGUSR2\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("13")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGPIPE "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("14")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGALRM "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("15")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGTERM "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGSTKFLT\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("17")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGCHLD "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("18")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGCONT "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("19")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGSTOP "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("20")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGTSTP\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGTTIN "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("22")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGTTOU "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("23")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGURG "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("24")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGXCPU\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("25")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGXFSZ "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("26")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGVTALRM "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("27")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGPROF "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("28")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGWINCH\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("29")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGIO "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("30")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGPWR "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("31")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGSYS "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("34")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("35")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("36")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+2 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("37")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+3 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("38")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+4\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("39")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+5 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("40")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+6 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("41")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+7 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("42")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+8\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("43")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+9 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("44")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+10 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("45")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+11 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("46")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+12\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("47")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+13 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("48")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+14 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("49")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMIN+15 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("50")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-14\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("51")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-13 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("52")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-12 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("53")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-11 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("54")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-10\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("55")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-9 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("56")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-8 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("57")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-7 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("58")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-6\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("59")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-5 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("60")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-4 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("61")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-3 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("62")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-2\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("63")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX-1 "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("64")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" SIGRTMAX\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 先用 ps 查找进程,然后用 kill 杀掉")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("ps")]),s._v(" -ef "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v("\nroot "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3268")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2884")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":21 pts/1 00:00:00 "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v(" install.log\nroot "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3370")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2822")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(":21 pts/0 00:00:00 "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("grep")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("kill")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3268")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("kill")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3268")]),s._v("\n-bash: kill: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3268")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" - 没有那个进程\n")])])]),a("h3",{attrs:{id:"_2-10-systemctl"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-10-systemctl"}},[s._v("#")]),s._v(" 2.10. systemctl")]),s._v(" "),a("blockquote",[a("p",[s._v("systemctl 命令是系统服务管理器指令,它实际上将 service 和 chkconfig 这两个命令组合到一起。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/systemctl")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 1.启动 nfs 服务")]),s._v("\nsystemctl start nfs-server.service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 2.设置开机自启动")]),s._v("\nsystemctl "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("enable")]),s._v(" nfs-server.service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 3.停止开机自启动")]),s._v("\nsystemctl disable nfs-server.service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 4.查看服务当前状态")]),s._v("\nsystemctl status nfs-server.service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 5.重新启动某服务")]),s._v("\nsystemctl restart nfs-server.service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 6.查看所有已启动的服务")]),s._v("\nsystemctl list -units --type"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),s._v("service\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 7. 开启防火墙 22 端口")]),s._v("\niptables -I INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("22")]),s._v(" -j accept\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 8. 彻底关闭防火墙")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" systemctl status firewalld.service\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" systemctl stop firewalld.service\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" systemctl disable firewalld.service\n")])])]),a("h3",{attrs:{id:"_2-11-service"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-11-service"}},[s._v("#")]),s._v(" 2.11. service")]),s._v(" "),a("blockquote",[a("p",[s._v("service 命令是 Redhat Linux 兼容的发行版中用来控制系统服务的实用工具,它以启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/service")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" network status\n配置设备:\nlo eth0\n当前的活跃设备:\nlo eth0\n\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("service")]),s._v(" network restart\n正在关闭接口 eth0: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" 确定 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n关闭环回接口: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" 确定 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n设置网络参数: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" 确定 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n弹出环回接口: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" 确定 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n弹出界面 eth0: "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" 确定 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-12-crontab"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-12-crontab"}},[s._v("#")]),s._v(" 2.12. crontab")]),s._v(" "),a("blockquote",[a("p",[s._v("crontab 命令被用来提交和管理用户的需要周期性执行的任务,与 windows 下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动 crond 进程,crond 进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。")]),s._v(" "),a("p",[s._v("参考:http://man.linuxde.net/crontab")])]),s._v(" "),a("p",[s._v("示例:")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每 1 分钟执行一次 command")]),s._v("\n* * * * * "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每小时的第 3 和第 15 分钟执行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3,15")]),s._v(" * * * * "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在上午 8 点到 11 点的第 3 和第 15 分钟执行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3,15")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("-11 * * * "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每隔两天的上午 8 点到 11 点的第 3 和第 15 分钟执行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3,15")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("-11 */2 * * "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每个星期一的上午 8 点到 11 点的第 3 和第 15 分钟执行")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("3,15")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("8")]),s._v("-11 * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("command")]),s._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每晚的 21:30 重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("30")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v(" * * * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每月 1、10、22 日的 4 : 45 重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("45")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1,10")]),s._v(",22 * * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每周六、周日的 1:10 重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("10")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6,0")]),s._v(" /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每天 18 : 00 至 23 : 00 之间每隔 30 分钟重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0,30")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("18")]),s._v("-23 * * * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每星期六的晚上 11:00 pm 重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("23")]),s._v(" * * "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("6")]),s._v(" /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每一小时重启 smb")]),s._v("\n* */1 * * * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 晚上 11 点到早上 7 点之间,每隔一小时重启 smb")]),s._v("\n* "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("23")]),s._v("-7/1 * * * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每月的 4 号与每周一到周三的 11 点重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("11")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" * mon-wed /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 一月一号的 4 点重启 smb")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" jan * /etc/init.d/smb restart\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 每小时执行`/etc/cron.hourly`目录内的脚本")]),s._v("\n01 * * * * root run-parts /etc/cron.hourly\n")])])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/32.05d2cbec.js b/assets/js/32.05d2cbec.js new file mode 100644 index 0000000..f42f4d1 --- /dev/null +++ b/assets/js/32.05d2cbec.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{420:function(s,a,t){"use strict";t.r(a);var e=t(15),n=Object(e.a)({},(function(){var s=this,a=s.$createElement,t=s._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"linux-用户管理"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#linux-用户管理"}},[s._v("#")]),s._v(" Linux 用户管理")]),s._v(" "),t("blockquote",[t("p",[s._v("关键词:"),t("code",[s._v("groupadd")]),s._v(", "),t("code",[s._v("groupdel")]),s._v(", "),t("code",[s._v("groupmod")]),s._v(", "),t("code",[s._v("useradd")]),s._v(", "),t("code",[s._v("userdel")]),s._v(", "),t("code",[s._v("usermod")]),s._v(", "),t("code",[s._v("passwd")]),s._v(", "),t("code",[s._v("su")]),s._v(", "),t("code",[s._v("sudo")])])]),s._v(" "),t("h2",{attrs:{id:"_1-linux-用户管理要点"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-linux-用户管理要点"}},[s._v("#")]),s._v(" 1. Linux 用户管理要点")]),s._v(" "),t("ul",[t("li",[s._v("创建用户组 - 使用 "),t("a",{attrs:{href:"#groupadd"}},[s._v("groupadd")])]),s._v(" "),t("li",[s._v("删除用户组 - 使用 "),t("a",{attrs:{href:"#groupdel"}},[s._v("groupdel")])]),s._v(" "),t("li",[s._v("修改用户组信息 - 使用 "),t("a",{attrs:{href:"#groupmod"}},[s._v("groupmod")])]),s._v(" "),t("li",[s._v("创建用户 - 使用 "),t("a",{attrs:{href:"#useradd"}},[s._v("useradd")])]),s._v(" "),t("li",[s._v("删除用户 - 使用 "),t("a",{attrs:{href:"#userdel"}},[s._v("userdel")])]),s._v(" "),t("li",[s._v("修改用户信息 - 使用 "),t("a",{attrs:{href:"#usermod"}},[s._v("usermod")])]),s._v(" "),t("li",[s._v("设置用户认证信息 - 使用 "),t("a",{attrs:{href:"#passwd"}},[s._v("passwd")])]),s._v(" "),t("li",[s._v("切换用户 - 使用 "),t("a",{attrs:{href:"#su"}},[s._v("su")])]),s._v(" "),t("li",[s._v("当前用户想执行没有权限执行的命令时,使用其他用户身份去执行 - 使用 "),t("a",{attrs:{href:"#sudo"}},[s._v("sudo")])])]),s._v(" "),t("h2",{attrs:{id:"_2-命令常见用法"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-命令常见用法"}},[s._v("#")]),s._v(" 2. 命令常见用法")]),s._v(" "),t("h3",{attrs:{id:"_2-1-groupadd"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-groupadd"}},[s._v("#")]),s._v(" 2.1. groupadd")]),s._v(" "),t("blockquote",[t("p",[s._v("groupadd 命令用于创建一个新的用户组,新用户组的信息将被添加到系统文件中。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/groupadd")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 建立一个新组,并设置组 ID 加入系统")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("groupadd")]),s._v(" -g "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("344")]),s._v(" jsdigname\n")])])]),t("h3",{attrs:{id:"_2-2-groupdel"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-groupdel"}},[s._v("#")]),s._v(" 2.2. groupdel")]),s._v(" "),t("blockquote",[t("p",[s._v("groupdel 命令用于删除指定的用户组,本命令要修改的系统文件包括 "),t("code",[s._v("/ect/group")]),s._v(" 和 "),t("code",[s._v("/ect/gshadow")]),s._v("。若该群组中仍包括某些用户,则必须先删除这些用户后,方能删除群组。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/groupdel")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("groupadd")]),s._v(" damon "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 创建damon用户组")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("groupdel")]),s._v(" damon "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除这个用户组")]),s._v("\n")])])]),t("h3",{attrs:{id:"_2-3-groupmod"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-groupmod"}},[s._v("#")]),s._v(" 2.3. groupmod")]),s._v(" "),t("blockquote",[t("p",[s._v("groupmod 命令更改群组识别码或名称。需要更改群组的识别码或名称时,可用 groupmod 指令来完成这项工作。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/groupmod")])]),s._v(" "),t("h3",{attrs:{id:"_2-4-useradd"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-useradd"}},[s._v("#")]),s._v(" 2.4. useradd")]),s._v(" "),t("blockquote",[t("p",[s._v("useradd 命令用于 Linux 中创建的新的系统用户。useradd 可用来建立用户帐号。帐号建好之后,再用 passwd 设定帐号的密码.而可用 userdel 删除帐号。使用 useradd 指令所建立的帐号,实际上是保存在 "),t("code",[s._v("/etc/passwd")]),s._v(" 文本文件中。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/useradd")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 新建用户加入组")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("useradd")]),s._v(" –g sales jack –G company,employees "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# -g:加入主要组、-G:加入次要组")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 建立一个新用户账户,并设置 ID")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("useradd")]),s._v(" caojh -u "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("544")]),s._v("\n")])])]),t("h3",{attrs:{id:"_2-5-userdel"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-5-userdel"}},[s._v("#")]),s._v(" 2.5. userdel")]),s._v(" "),t("blockquote",[t("p",[s._v("userdel 命令用于删除给定的用户,以及与用户相关的文件。若不加选项,则仅删除用户帐号,而不删除相关文件。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/userdel")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("p",[s._v("userdel 命令很简单,比如我们现在有个用户 linuxde,其 home 目录位于"),t("code",[s._v("/var")]),s._v("目录中,现在我们来删除这个用户:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("userdel")]),s._v(" linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除用户linuxde,但不删除其家目录及文件;")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("userdel")]),s._v(" -r linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 删除用户linuxde,其 home 目录及文件一并删除;")]),s._v("\n")])])]),t("h3",{attrs:{id:"_2-6-usermod"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-6-usermod"}},[s._v("#")]),s._v(" 2.6. usermod")]),s._v(" "),t("blockquote",[t("p",[s._v("usermod 命令用于修改用户的基本信息。usermod 命令不允许你改变正在线上的使用者帐号名称。当 usermod 命令用来改变 user id,必须确认这名 user 没在电脑上执行任何程序。你需手动更改使用者的 crontab 档。也需手动更改使用者的 at 工作档。采用 NIS server 须在 server 上更动相关的 NIS 设定。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/usermod")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 将 newuser2 添加到组 staff 中")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("usermod")]),s._v(" -G staff newuser2\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 修改 newuser 的用户名为 newuser1")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("usermod")]),s._v(" -l newuser1 newuser\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锁定账号 newuser1")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("usermod")]),s._v(" -L newuser1\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 解除对 newuser1 的锁定")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("usermod")]),s._v(" -U newuser1\n")])])]),t("h3",{attrs:{id:"_2-7-passwd"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-7-passwd"}},[s._v("#")]),s._v(" 2.7. passwd")]),s._v(" "),t("blockquote",[t("p",[s._v("passwd 命令用于设置用户的认证信息,包括用户密码、密码过期时间等。系统管理者则能用它管理系统用户的密码。只有管理者可以指定用户名称,一般用户只能变更自己的密码。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/passwd")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 如果是普通用户执行 passwd 只能修改自己的密码。")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 如果新建用户后,要为新用户创建密码,则用 passwd 用户名,注意要以 root 用户的权限来创建。")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v(" linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 更改或创建linuxde用户的密码;")]),s._v("\nChanging password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user linuxde.\nNew UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 请输入新密码;")]),s._v("\nRetype new UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 再输入一次;")]),s._v("\npasswd: all authentication tokens updated successfully. "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 成功;")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 普通用户如果想更改自己的密码,直接运行 passwd 即可,比如当前操作的用户是 linuxde。")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v("\nChanging password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user linuxde. "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 更改linuxde用户的密码;")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("current"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 请输入当前密码;")]),s._v("\nNew UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 请输入新密码;")]),s._v("\nRetype new UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 确认新密码;")]),s._v("\npasswd: all authentication tokens updated successfully. "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 更改成功;")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 比如我们让某个用户不能修改密码,可以用`-l`选项来锁定:")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v(" -l linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锁定用户linuxde不能更改密码;")]),s._v("\nLocking password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user linuxde.\npasswd: Success "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 锁定成功;")]),s._v("\n\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("su")]),s._v(" linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 通过su切换到linuxde用户;")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# linuxde来更改密码;")]),s._v("\nChanging password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user linuxde.\nChanging password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" linuxde\n"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("current"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" UNIX password: "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 输入linuxde的当前密码;")]),s._v("\npasswd: Authentication token manipulation error "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 失败,不能更改密码;")]),s._v("\n\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v(" -d linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 清除linuxde用户密码;")]),s._v("\nRemoving password "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("for")]),s._v(" user linuxde.\npasswd: Success "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 清除成功;")]),s._v("\n\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("passwd")]),s._v(" -S linuxde "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 查询linuxde用户密码状态;")]),s._v("\nEmpty password. "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 空密码,也就是没有密码;")]),s._v("\n")])])]),t("h3",{attrs:{id:"_2-8-su"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-8-su"}},[s._v("#")]),s._v(" 2.8. su")]),s._v(" "),t("blockquote",[t("p",[s._v("su 命令用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/su")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 变更帐号为 root 并在执行 ls 指令后退出变回原使用者:")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("su")]),s._v(" -c "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" root\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 变更帐号为 root 并传入`-f`选项给新执行的 shell:")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("su")]),s._v(" root -f\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 变更帐号为 test 并改变工作目录至 test 的家目录:")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("su")]),s._v(" -test\n")])])]),t("h3",{attrs:{id:"_2-9-sudo"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-sudo"}},[s._v("#")]),s._v(" 2.9. sudo")]),s._v(" "),t("blockquote",[t("p",[s._v("sudo 命令用来以其他身份来执行命令,预设的身份为 root。在 "),t("code",[s._v("/etc/sudoers")]),s._v(" 中设置了可执行 sudo 指令的用户。若其未经授权的用户企图使用 sudo,则会发出警告的邮件给管理员。用户使用 sudo 时,必须先输入密码,之后有 5 分钟的有效期限,超过期限则必须重新输入密码。")]),s._v(" "),t("p",[s._v("参考:http://man.linuxde.net/sudo")])]),s._v(" "),t("p",[s._v("示例:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定用户执行命令")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" -u userb "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" -l\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 列出目前的权限")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" -l\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 显示sudo设置")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" -L\n")])])]),t("h4",{attrs:{id:"_2-9-1-给普通用户授权-sudo"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-1-给普通用户授权-sudo"}},[s._v("#")]),s._v(" 2.9.1. 给普通用户授权 sudo")]),s._v(" "),t("p",[s._v("假设要给普通用户 mary 配置 sudo 权限:")]),s._v(" "),t("ol",[t("li",[t("code",[s._v("/etc/sudoers")]),s._v(" 文件存放了 sudo 的相关用户,但是默认是没有写权限的,所以需要设为可写:"),t("code",[s._v("chmod u+w /etc/sudoers")])]),s._v(" "),t("li",[s._v("在该文件中添加 "),t("code",[s._v("mary ALL=(ALL) ALL")]),s._v(" ,保存并退出,让 mary 具有 sudo 的所有权限")]),s._v(" "),t("li",[s._v("再将 "),t("code",[s._v("/etc/sudoers")]),s._v(" 的权限恢复到默认状态:"),t("code",[s._v("chmod u-w /etc/sudoers")])])]),s._v(" "),t("h4",{attrs:{id:"_2-9-2-免密码授权-sudo"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-9-2-免密码授权-sudo"}},[s._v("#")]),s._v(" 2.9.2. 免密码授权 sudo")]),s._v(" "),t("p",[s._v("与给普通用户授权 sudo 类似,区别仅在于第 2 步:"),t("code",[s._v("mary ALL=(ALL) NOPASSWD: ALL")]),s._v("。")])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/33.3b265df8.js b/assets/js/33.3b265df8.js new file mode 100644 index 0000000..d0f9840 --- /dev/null +++ b/assets/js/33.3b265df8.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[33],{421:function(s,t,a){"use strict";a.r(t);var e=a(15),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"scp"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#scp"}},[s._v("#")]),s._v(" scp")]),s._v(" "),a("p",[s._v("加密的方式在本地主机和远程主机之间复制文件")]),s._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[s._v("#")]),s._v(" 补充说明")]),s._v(" "),a("p",[a("strong",[s._v("scp 命令")]),s._v(" 用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然  rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。")]),s._v(" "),a("h3",{attrs:{id:"语法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[s._v("#")]),s._v(" 语法")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("scp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("选项"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("参数"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[s._v("#")]),s._v(" 选项")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("-1:使用ssh协议版本1;\n-2:使用ssh协议版本2;\n-4:使用ipv4;\n-6:使用ipv6;\n-B:以批处理模式运行;\n-C:使用压缩;\n-F:指定ssh配置文件;\n-i:identity_file 从指定文件中读取传输时使用的密钥文件(例如亚马逊云pem),此参数直接传递给ssh;\n-l:指定宽带限制;\n-o:指定使用的ssh选项;\n-P:指定远程主机的端口号;\n-p:保留文件的最后修改时间,最后访问时间和权限模式;\n-q:不显示复制进度;\n-r:以递归方式复制。\n")])])]),a("h3",{attrs:{id:"参数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参数"}},[s._v("#")]),s._v(" 参数")]),s._v(" "),a("ul",[a("li",[s._v("源文件:指定要复制的源文件。")]),s._v(" "),a("li",[s._v("目标文件:目标文件。格式为"),a("code",[s._v("user@host:filename")]),s._v("(文件名为目标文件的名称)。")])]),s._v(" "),a("h3",{attrs:{id:"实例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[s._v("#")]),s._v(" 实例")]),s._v(" "),a("p",[s._v("从远程复制到本地的 scp 命令与上面的命令雷同,只要将从本地复制到远程的命令后面 2 个参数互换顺序就行了。")]),s._v(" "),a("p",[a("strong",[s._v("从远处复制文件到本地目录")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" root@10.10.10.10:/opt/soft/nginx-0.5.38.tar.gz /opt/soft/\n")])])]),a("p",[s._v("从 10.10.10.10 机器上的"),a("code",[s._v("/opt/soft/")]),s._v("的目录中下载 nginx-0.5.38.tar.gz  文件到本地"),a("code",[s._v("/opt/soft/")]),s._v("目录中。")]),s._v(" "),a("p",[a("strong",[s._v("从亚马逊云复制 OpenVPN 到本地目录")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" -i amazon.pem ubuntu@10.10.10.10:/usr/local/openvpn_as/etc/exe/openvpn-connect-2.1.3.110.dmg openvpn-connect-2.1.3.110.dmg\n")])])]),a("p",[s._v("从 10.10.10.10 机器上下载 openvpn 安装文件到本地当前目录来。")]),s._v(" "),a("p",[a("strong",[s._v("从远处复制到本地")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" -r root@10.10.10.10:/opt/soft/mongodb /opt/soft/\n")])])]),a("p",[s._v("从 10.10.10.10 机器上的"),a("code",[s._v("/opt/soft/")]),s._v("中下载 mongodb 目录到本地的"),a("code",[s._v("/opt/soft/")]),s._v("目录来。")]),s._v(" "),a("p",[a("strong",[s._v("上传本地文件到远程机器指定目录")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 指定端口 2222")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" -rp -P "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2222")]),s._v(" /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest\n")])])]),a("p",[s._v("复制本地"),a("code",[s._v("/opt/soft/")]),s._v("目录下的文件 nginx-0.5.38.tar.gz 到远程机器 10.10.10.10 的"),a("code",[s._v("opt/soft/scptest")]),s._v("目录。")]),s._v(" "),a("p",[a("strong",[s._v("上传本地目录到远程机器指定目录")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("scp")]),s._v(" -r /opt/soft/mongodb root@10.10.10.10:/opt/soft/scptest\n")])])]),a("p",[s._v("上传本地目录"),a("code",[s._v("/opt/soft/mongodb")]),s._v("到远程机器 10.10.10.10 上"),a("code",[s._v("/opt/soft/scptest")]),s._v("的目录中去。")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/34.26330a03.js b/assets/js/34.26330a03.js new file mode 100644 index 0000000..719e77a --- /dev/null +++ b/assets/js/34.26330a03.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[34],{422:function(s,t,a){"use strict";a.r(t);var e=a(15),r=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"top"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#top"}},[s._v("#")]),s._v(" top")]),s._v(" "),a("p",[s._v("显示或管理执行中的程序")]),s._v(" "),a("h2",{attrs:{id:"补充说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[s._v("#")]),s._v(" 补充说明")]),s._v(" "),a("p",[a("strong",[s._v("top 命令")]),s._v(" 可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。")]),s._v(" "),a("h3",{attrs:{id:"语法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[s._v("#")]),s._v(" 语法")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("top"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("选项"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),a("h3",{attrs:{id:"选项"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[s._v("#")]),s._v(" 选项")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("-b:以批处理模式操作;\n-c:显示完整的治命令;\n-d:屏幕刷新间隔时间;\n-I:忽略失效过程;\n-s:保密模式;\n-S:累积模式;\n-i"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("时间"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(":设置间隔时间;\n-u"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("用户名"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(":指定用户名;\n-p"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("进程号"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(":指定进程;\n-n"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v("次数"),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(":循环显示的次数。\n")])])]),a("h3",{attrs:{id:"top-交互命令"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#top-交互命令"}},[s._v("#")]),s._v(" top 交互命令")]),s._v(" "),a("p",[s._v("在 top 命令执行过程中可以使用的一些交互命令。这些命令都是单字母的,如果在命令行中使用了-s 选项,  其中一些命令可能会被屏蔽。")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v("h:显示帮助画面,给出一些简短的命令总结说明;\nk:终止一个进程;\ni:忽略闲置和僵死进程,这是一个开关式命令;\nq:退出程序;\nr:重新安排一个进程的优先级别;\nS:切换到累计模式;\ns:改变两次刷新之间的延迟时间(单位为s),如果有小数,就换算成ms。输入0值则系统将不断刷新,默认值是5s;\nf或者F:从当前显示中添加或者删除项目;\no或者O:改变显示项目的顺序;\nl:切换显示平均负载和启动时间信息;\nm:切换显示内存信息;\nt:切换显示进程和CPU状态信息;\nc:切换显示命令名称和完整命令行;\nM:根据驻留内存大小进行排序;\nP:根据CPU使用百分比大小进行排序;\nT:根据时间/累计时间进行排序;\nw:将当前设置写入~/.toprc文件中。\n")])])]),a("h3",{attrs:{id:"实例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[s._v("#")]),s._v(" 实例")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[s._v("top")]),s._v(" - 09:44:56 up "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("16")]),s._v(" days, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("21")]),s._v(":23, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" user, load average: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("9.59")]),s._v(", "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("4.75")]),s._v(", "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1.92")]),s._v("\nTasks: "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("145")]),s._v(" total, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),s._v(" running, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("143")]),s._v(" sleeping, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" stopped, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" zombie\nCpu"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("s"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(": "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("99.8")]),s._v("%us, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.1")]),s._v("%sy, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v("%ni, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.2")]),s._v("%id, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v("%wa, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v("%hi, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v("%si, "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("0.0")]),s._v("%st\nMem: 4147888k total, 2493092k used, 1654796k free, 158188k buffers\nSwap: 5144568k total, 56k used, 5144512k free, 2013180k cached\n")])])]),a("p",[a("strong",[s._v("解释:")])]),s._v(" "),a("ul",[a("li",[s._v("top - 09:44:56[当前系统时间],")]),s._v(" "),a("li",[s._v("16 days[系统已经运行了 16 天],")]),s._v(" "),a("li",[s._v("1 user[个用户当前登录],")]),s._v(" "),a("li",[s._v("load average: 9.59, 4.75, 1.92[系统负载,即任务队列的平均长度]")]),s._v(" "),a("li",[s._v("Tasks: 145 total[总进程数],")]),s._v(" "),a("li",[s._v("2 running[正在运行的进程数],")]),s._v(" "),a("li",[s._v("143 sleeping[睡眠的进程数],")]),s._v(" "),a("li",[s._v("0 stopped[停止的进程数],")]),s._v(" "),a("li",[s._v("0 zombie[冻结进程数],")]),s._v(" "),a("li",[s._v("Cpu(s): 99.8%us[用户空间占用 CPU 百分比],")]),s._v(" "),a("li",[s._v("0.1%sy[内核空间占用 CPU 百分比],")]),s._v(" "),a("li",[s._v("0.0%ni[用户进程空间内改变过优先级的进程占用 CPU 百分比],")]),s._v(" "),a("li",[s._v("0.2%id[空闲 CPU 百分比], 0.0%wa[等待输入输出的 CPU 时间百分比],")]),s._v(" "),a("li",[s._v("0.0%hi[],")]),s._v(" "),a("li",[s._v("0.0%st[],")]),s._v(" "),a("li",[s._v("Mem: 4147888k total[物理内存总量],")]),s._v(" "),a("li",[s._v("2493092k used[使用的物理内存总量],")]),s._v(" "),a("li",[s._v("1654796k free[空闲内存总量],")]),s._v(" "),a("li",[s._v("158188k buffers[用作内核缓存的内存量]")]),s._v(" "),a("li",[s._v("Swap:  5144568k total[交换区总量],")]),s._v(" "),a("li",[s._v("56k used[使用的交换区总量],")]),s._v(" "),a("li",[s._v("5144512k free[空闲交换区总量],")]),s._v(" "),a("li",[s._v("2013180k cached[缓冲的交换区总量],")])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/35.417d706d.js b/assets/js/35.417d706d.js new file mode 100644 index 0000000..954e7d7 --- /dev/null +++ b/assets/js/35.417d706d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{423:function(s,a,t){"use strict";t.r(a);var e=t(15),r=Object(e.a)({},(function(){var s=this,a=s.$createElement,t=s._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"vmstat"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#vmstat"}},[s._v("#")]),s._v(" vmstat")]),s._v(" "),t("p",[s._v("显示虚拟内存状态")]),s._v(" "),t("h2",{attrs:{id:"补充说明"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#补充说明"}},[s._v("#")]),s._v(" 补充说明")]),s._v(" "),t("p",[t("strong",[s._v("vmstat 命令")]),s._v(" 的含义为显示虚拟内存状态(“Viryual Memor Statics”),但是它可以报告关于进程、内存、I/O 等系统整体运行状态。")]),s._v(" "),t("h3",{attrs:{id:"语法"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#语法"}},[s._v("#")]),s._v(" 语法")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[s._v("vmstat"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("选项"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("参数"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v("\n")])])]),t("h3",{attrs:{id:"选项"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#选项"}},[s._v("#")]),s._v(" 选项")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[s._v("-a:显示活动内页;\n-f:显示启动后创建的进程总数;\n-m:显示slab信息;\n-n:头信息仅显示一次;\n-s:以表格方式显示事件计数器和内存状态;\n-d:报告磁盘状态;\n-p:显示指定的硬盘分区状态;\n-S:输出信息的单位。\n")])])]),t("h3",{attrs:{id:"参数"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#参数"}},[s._v("#")]),s._v(" 参数")]),s._v(" "),t("ul",[t("li",[s._v("事件间隔:状态信息刷新的时间间隔;")]),s._v(" "),t("li",[s._v("次数:显示报告的次数。")])]),s._v(" "),t("h3",{attrs:{id:"实例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#实例"}},[s._v("#")]),s._v(" 实例")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vmstat")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),s._v("\nprocs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------\n r b swpd "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("free")]),s._v(" buff cache si so bi bo "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" cs us sy "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("id")]),s._v(" wa st\n "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("320")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("42188")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("167332")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1534368")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("4")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("7")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("99")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("320")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("42188")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("167332")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1534392")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1002")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("39")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("320")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("42188")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("167336")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1534392")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("19")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1002")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("44")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("320")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("42188")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("167336")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1534392")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1002")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("41")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("320")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("42188")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("167336")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1534392")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1002")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("41")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("100")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("0")]),s._v("\n")])])]),t("p",[t("strong",[s._v("字段说明:")])]),s._v(" "),t("p",[s._v("Procs(进程)")]),s._v(" "),t("ul",[t("li",[s._v("r: 运行队列中进程数量,这个值也可以判断是否需要增加 CPU。(长期大于 1)")]),s._v(" "),t("li",[s._v("b: 等待 IO 的进程数量。")])]),s._v(" "),t("p",[s._v("Memory(内存)")]),s._v(" "),t("ul",[t("li",[s._v("swpd: 使用虚拟内存大小,如果 swpd 的值不为 0,但是 SI,SO 的值长期为 0,这种情况不会影响系统性能。")]),s._v(" "),t("li",[s._v("free: 空闲物理内存大小。")]),s._v(" "),t("li",[s._v("buff: 用作缓冲的内存大小。")]),s._v(" "),t("li",[s._v("cache: 用作缓存的内存大小,如果 cache 的值大的时候,说明 cache 处的文件数多,如果频繁访问到的文件都能被 cache 处,那么磁盘的读 IO bi 会非常小。")])]),s._v(" "),t("p",[s._v("Swap")]),s._v(" "),t("ul",[t("li",[s._v("si: 每秒从交换区写到内存的大小,由磁盘调入内存。")]),s._v(" "),t("li",[s._v("so: 每秒写入交换区的内存大小,由内存调入磁盘。")])]),s._v(" "),t("p",[s._v("注意:内存够用的时候,这 2 个值都是 0,如果这 2 个值长期大于 0 时,系统性能会受到影响,磁盘 IO 和 CPU 资源都会被消耗。有些朋友看到空闲内存(free)很少的或接近于 0 时,就认为内存不够用了,不能光看这一点,还要结合 si 和 so,如果 free 很少,但是 si 和 so 也很少(大多时候是 0),那么不用担心,系统性能这时不会受到影响的。")]),s._v(" "),t("p",[s._v("IO(现在的 Linux 版本块的大小为 1kb)")]),s._v(" "),t("ul",[t("li",[s._v("bi: 每秒读取的块数")]),s._v(" "),t("li",[s._v("bo: 每秒写入的块数")])]),s._v(" "),t("p",[s._v("注意:随机磁盘读写的时候,这 2 个值越大(如超出 1024k),能看到 CPU 在 IO 等待的值也会越大。")]),s._v(" "),t("p",[s._v("system(系统)")]),s._v(" "),t("ul",[t("li",[s._v("in: 每秒中断数,包括时钟中断。")]),s._v(" "),t("li",[s._v("cs: 每秒上下文切换数。")])]),s._v(" "),t("p",[s._v("注意:上面 2 个值越大,会看到由内核消耗的 CPU 时间会越大。")]),s._v(" "),t("p",[s._v("CPU(以百分比表示)")]),s._v(" "),t("ul",[t("li",[s._v("us: 用户进程执行时间百分比(user time)")])]),s._v(" "),t("p",[s._v("us 的值比较高时,说明用户进程消耗的 CPU 时间多,但是如果长期超 50%的使用,那么我们就该考虑优化程序算法或者进行加速。")]),s._v(" "),t("ul",[t("li",[s._v("sy: 内核系统进程执行时间百分比(system time)")])]),s._v(" "),t("p",[s._v("sy 的值高时,说明系统内核消耗的 CPU 资源多,这并不是良性表现,我们应该检查原因。")]),s._v(" "),t("ul",[t("li",[s._v("wa: IO 等待时间百分比")])]),s._v(" "),t("p",[s._v("wa 的值高时,说明 IO 等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。")]),s._v(" "),t("ul",[t("li",[s._v("id: 空闲时间百分比")])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/36.0ed775e0.js b/assets/js/36.0ed775e0.js new file mode 100644 index 0000000..1623223 --- /dev/null +++ b/assets/js/36.0ed775e0.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[36],{424:function(e,_,v){"use strict";v.r(_);var t=v(15),o=Object(t.a)({},(function(){var e=this,_=e.$createElement,v=e._self._c||_;return v("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[v("blockquote",[v("p",[e._v("转载自 https://github.com/jlevy/the-art-of-command-line")])]),e._v(" "),v("p",[v("em",[v("RouterLink",{attrs:{to:"/linux/cli/README-cs.html"}},[e._v("Čeština")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-de.html"}},[e._v("Deutsch")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-el.html"}},[e._v("Ελληνικά")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/"}},[e._v("English")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-es.html"}},[e._v("Español")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-fr.html"}},[e._v("Français")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-id.html"}},[e._v("Indonesia")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-it.html"}},[e._v("Italiano")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-ja.html"}},[e._v("日本語")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-ko.html"}},[e._v("한국어")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-pt.html"}},[e._v("Português")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-ro.html"}},[e._v("Română")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-ru.html"}},[e._v("Русский")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-sl.html"}},[e._v("Slovenščina")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-uk.html"}},[e._v("Українська")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-zh.html"}},[e._v("简体中文")]),e._v(" ∙ "),v("RouterLink",{attrs:{to:"/linux/cli/README-zh-Hant.html"}},[e._v("繁體中文")])],1)]),e._v(" "),v("h1",{attrs:{id:"命令行的艺术"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#命令行的艺术"}},[e._v("#")]),e._v(" 命令行的艺术")]),e._v(" "),v("p",[v("img",{attrs:{src:"https://gitter.im/jlevy/the-art-of-command-line?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge",alt:"img"}})]),e._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"#%E5%89%8D%E8%A8%80"}},[e._v("前言")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E5%9F%BA%E7%A1%80"}},[e._v("基础")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E6%97%A5%E5%B8%B8%E4%BD%BF%E7%94%A8"}},[e._v("日常使用")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E6%96%87%E4%BB%B6%E5%8F%8A%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86"}},[e._v("文件及数据处理")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E7%B3%BB%E7%BB%9F%E8%B0%83%E8%AF%95"}},[e._v("系统调试")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E5%8D%95%E8%A1%8C%E8%84%9A%E6%9C%AC"}},[e._v("单行脚本")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E5%86%B7%E9%97%A8%E4%BD%86%E6%9C%89%E7%94%A8"}},[e._v("冷门但有用")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E4%BB%85%E9%99%90-os-x-%E7%B3%BB%E7%BB%9F"}},[e._v("仅限 OS X 系统")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E4%BB%85%E9%99%90-windows-%E7%B3%BB%E7%BB%9F"}},[e._v("仅限 Windows 系统")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E6%9B%B4%E5%A4%9A%E8%B5%84%E6%BA%90"}},[e._v("更多资源")])]),e._v(" "),v("li",[v("a",{attrs:{href:"#%E5%85%8D%E8%B4%A3%E5%A3%B0%E6%98%8E"}},[e._v("免责声明")])])]),e._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/cowsay.png",alt:"img"}})]),e._v(" "),v("p",[e._v("熟练使用命令行是一种常常被忽视,或被认为难以掌握的技能,但实际上,它会提高你作为工程师的灵活性以及生产力。本文是一份我在 Linux 上工作时,发现的一些命令行使用技巧的摘要。有些技巧非常基础,而另一些则相当复杂,甚至晦涩难懂。这篇文章并不长,但当你能够熟练掌握这里列出的所有技巧时,你就学会了很多关于命令行的东西了。")]),e._v(" "),v("p",[e._v("这篇文章是"),v("RouterLink",{attrs:{to:"/linux/cli/AUTHORS.html"}},[e._v("许多作者和译者")]),e._v("共同的成果。\n这里的部分内容\n"),v("a",{attrs:{href:"http://www.quora.com/What-are-some-lesser-known-but-useful-Unix-commands",target:"_blank",rel:"noopener noreferrer"}},[e._v("首次"),v("OutboundLink")],1),e._v(" "),v("a",{attrs:{href:"http://www.quora.com/What-are-the-most-useful-Swiss-army-knife-one-liners-on-Unix",target:"_blank",rel:"noopener noreferrer"}},[e._v("出现"),v("OutboundLink")],1),e._v("\n于 "),v("a",{attrs:{href:"http://www.quora.com/What-are-some-time-saving-tips-that-every-Linux-user-should-know",target:"_blank",rel:"noopener noreferrer"}},[e._v("Quora"),v("OutboundLink")],1),e._v(",\n但已经迁移到了 Github,并由众多高手做出了许多改进。\n如果你在本文中发现了错误或者存在可以改善的地方,请"),v("RouterLink",{attrs:{to:"/CONTRIBUTING.html"}},[v("strong",[e._v("贡献你的一份力量")])]),e._v("。")],1),e._v(" "),v("h2",{attrs:{id:"前言"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#前言"}},[e._v("#")]),e._v(" 前言")]),e._v(" "),v("p",[e._v("涵盖范围:")]),e._v(" "),v("ul",[v("li",[e._v("这篇文章不仅能帮助刚接触命令行的新手,而且对具有经验的人也大有裨益。本文致力于做到"),v("em",[e._v("覆盖面广")]),e._v("(涉及所有重要的内容),"),v("em",[e._v("具体")]),e._v("(给出具体的最常用的例子),以及"),v("em",[e._v("简洁")]),e._v("(避免冗余的内容,或是可以在其他地方轻松查到的细枝末节)。在特定应用场景下,本文的内容属于基本功或者能帮助您节约大量的时间。")]),e._v(" "),v("li",[e._v("本文主要为 Linux 所写,但在"),v("a",{attrs:{href:"#%E4%BB%85%E9%99%90-os-x-%E7%B3%BB%E7%BB%9F"}},[e._v("仅限 OS X 系统")]),e._v("章节和"),v("a",{attrs:{href:"#%E4%BB%85%E9%99%90-windows-%E7%B3%BB%E7%BB%9F"}},[e._v("仅限 Windows 系统")]),e._v("章节中也包含有对应操作系统的内容。除去这两个章节外,其它的内容大部分均可在其他类 Unix 系统或 OS X,甚至 Cygwin 中得到应用。")]),e._v(" "),v("li",[e._v("本文主要关注于交互式 Bash,但也有很多技巧可以应用于其他 shell 和 Bash 脚本当中。")]),e._v(" "),v("li",[e._v("除去“标准的”Unix 命令,本文还包括了一些依赖于特定软件包的命令(前提是它们具有足够的价值)。")])]),e._v(" "),v("p",[e._v("注意事项:")]),e._v(" "),v("ul",[v("li",[e._v("为了能在一页内展示尽量多的东西,一些具体的信息可以在引用的页面中找到。我们相信机智的你知道如何使用 Google 或者其他搜索引擎来查阅到更多的详细信息。文中部分命令需要您使用 "),v("code",[e._v("apt-get")]),e._v(","),v("code",[e._v("yum")]),e._v(","),v("code",[e._v("dnf")]),e._v(","),v("code",[e._v("pacman")]),e._v(",\n"),v("code",[e._v("pip")]),e._v(" 或 "),v("code",[e._v("brew")]),e._v("(以及其它合适的包管理器)来安装依赖的程序。")]),e._v(" "),v("li",[e._v("遇到问题的话,请尝试使用 "),v("a",{attrs:{href:"http://explainshell.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Explainshell"),v("OutboundLink")],1),e._v(" 去获取相关命令、参数、管道等内容的解释。")])]),e._v(" "),v("h2",{attrs:{id:"基础"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#基础"}},[e._v("#")]),e._v(" 基础")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("学习 Bash 的基础知识。具体地,在命令行中输入 "),v("code",[e._v("man bash")]),e._v(" 并至少全文浏览一遍; 它理解起来很简单并且不冗长。其他的 shell 可能很好用,但 Bash 的功能已经足够强大并且到几乎总是可用的( 如果你"),v("em",[e._v("只")]),e._v("学习 zsh,fish 或其他的 shell 的话,在你自己的设备上会显得很方便,但过度依赖这些功能会给您带来不便,例如当你需要在服务器上工作时)。")])]),e._v(" "),v("li",[v("p",[e._v("熟悉至少一个基于文本的编辑器。通常而言 Vim ("),v("code",[e._v("vi")]),e._v(") 会是你最好的选择,毕竟在终端中编辑文本时 Vim 是最好用的工具(甚至大部分情况下 Vim 要比 Emacs、大型 IDE 或是炫酷的编辑器更好用)。")])]),e._v(" "),v("li",[v("p",[e._v("学会如何使用 "),v("code",[e._v("man")]),e._v(" 命令去阅读文档。学会使用 "),v("code",[e._v("apropos")]),e._v(" 去查找文档。知道有些命令并不对应可执行文件,而是在 Bash 内置好的,此时可以使用 "),v("code",[e._v("help")]),e._v(" 和 "),v("code",[e._v("help -d")]),e._v(" 命令获取帮助信息。你可以用 "),v("code",[e._v("type 命令")]),e._v(" 来判断这个命令到底是可执行文件、shell 内置命令还是别名。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用 "),v("code",[e._v(">")]),e._v(" 和 "),v("code",[e._v("<")]),e._v(" 来重定向输出和输入,学会使用 "),v("code",[e._v("|")]),e._v(" 来重定向管道。明白 "),v("code",[e._v(">")]),e._v(" 会覆盖了输出文件而 "),v("code",[e._v(">>")]),e._v(" 是在文件末添加。了解标准输出 stdout 和标准错误 stderr。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用通配符 "),v("code",[e._v("*")]),e._v(" (或许再算上 "),v("code",[e._v("?")]),e._v(" 和 "),v("code",[e._v("[")]),e._v("..."),v("code",[e._v("]")]),e._v(") 和引用以及引用中 "),v("code",[e._v("'")]),e._v(" 和 "),v("code",[e._v('"')]),e._v(" 的区别(后文中有一些具体的例子)。")])]),e._v(" "),v("li",[v("p",[e._v("熟悉 Bash 中的任务管理工具:"),v("code",[e._v("&")]),e._v(","),v("strong",[e._v("ctrl-z")]),e._v(","),v("strong",[e._v("ctrl-c")]),e._v(","),v("code",[e._v("jobs")]),e._v(","),v("code",[e._v("fg")]),e._v(","),v("code",[e._v("bg")]),e._v(","),v("code",[e._v("kill")]),e._v(" 等。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用 "),v("code",[e._v("ssh")]),e._v(" 进行远程命令行登录,最好知道如何使用 "),v("code",[e._v("ssh-agent")]),e._v(","),v("code",[e._v("ssh-add")]),e._v(" 等命令来实现基础的无密码认证登录。")])]),e._v(" "),v("li",[v("p",[e._v("学会基本的文件管理工具:"),v("code",[e._v("ls")]),e._v(" 和 "),v("code",[e._v("ls -l")]),e._v(" (了解 "),v("code",[e._v("ls -l")]),e._v(" 中每一列代表的意义),"),v("code",[e._v("less")]),e._v(","),v("code",[e._v("head")]),e._v(","),v("code",[e._v("tail")]),e._v(" 和 "),v("code",[e._v("tail -f")]),e._v(" (甚至 "),v("code",[e._v("less +F")]),e._v("),"),v("code",[e._v("ln")]),e._v(" 和 "),v("code",[e._v("ln -s")]),e._v(" (了解硬链接与软链接的区别),"),v("code",[e._v("chown")]),e._v(","),v("code",[e._v("chmod")]),e._v(","),v("code",[e._v("du")]),e._v(" (硬盘使用情况概述:"),v("code",[e._v("du -hs *")]),e._v(")。 关于文件系统的管理,学习 "),v("code",[e._v("df")]),e._v(","),v("code",[e._v("mount")]),e._v(","),v("code",[e._v("fdisk")]),e._v(","),v("code",[e._v("mkfs")]),e._v(","),v("code",[e._v("lsblk")]),e._v("。知道 inode 是什么(与 "),v("code",[e._v("ls -i")]),e._v(" 和 "),v("code",[e._v("df -i")]),e._v(" 等命令相关)。")])]),e._v(" "),v("li",[v("p",[e._v("学习基本的网络管理工具:"),v("code",[e._v("ip")]),e._v(" 或 "),v("code",[e._v("ifconfig")]),e._v(","),v("code",[e._v("dig")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("学习并使用一种版本控制管理系统,例如 "),v("code",[e._v("git")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("熟悉正则表达式,学会使用 "),v("code",[e._v("grep")]),e._v("/"),v("code",[e._v("egrep")]),e._v(",它们的参数中 "),v("code",[e._v("-i")]),e._v(","),v("code",[e._v("-o")]),e._v(","),v("code",[e._v("-v")]),e._v(","),v("code",[e._v("-A")]),e._v(","),v("code",[e._v("-B")]),e._v(" 和 "),v("code",[e._v("-C")]),e._v(" 这些是很常用并值得认真学习的。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用 "),v("code",[e._v("apt-get")]),e._v(","),v("code",[e._v("yum")]),e._v(","),v("code",[e._v("dnf")]),e._v(" 或 "),v("code",[e._v("pacman")]),e._v(" (具体使用哪个取决于你使用的 Linux 发行版)来查找和安装软件包。并确保你的环境中有 "),v("code",[e._v("pip")]),e._v(" 来安装基于 Python 的命令行工具 (接下来提到的部分程序使用 "),v("code",[e._v("pip")]),e._v(" 来安装会很方便)。")])])]),e._v(" "),v("h2",{attrs:{id:"日常使用"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#日常使用"}},[e._v("#")]),e._v(" 日常使用")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("在 Bash 中,可以通过按 "),v("strong",[e._v("Tab")]),e._v(" 键实现自动补全参数,使用 "),v("strong",[e._v("ctrl-r")]),e._v(" 搜索命令行历史记录(按下按键之后,输入关键字便可以搜索,重复按下 "),v("strong",[e._v("ctrl-r")]),e._v(" 会向后查找匹配项,按下 "),v("strong",[e._v("Enter")]),e._v(" 键会执行当前匹配的命令,而按下右方向键会将匹配项放入当前行中,不会直接执行,以便做出修改)。")])]),e._v(" "),v("li",[v("p",[e._v("在 Bash 中,可以按下 "),v("strong",[e._v("ctrl-w")]),e._v(" 删除你键入的最后一个单词,"),v("strong",[e._v("ctrl-u")]),e._v(" 可以删除行内光标所在位置之前的内容,"),v("strong",[e._v("alt-b")]),e._v(" 和 "),v("strong",[e._v("alt-f")]),e._v(" 可以以单词为单位移动光标,"),v("strong",[e._v("ctrl-a")]),e._v(" 可以将光标移至行首,"),v("strong",[e._v("ctrl-e")]),e._v(" 可以将光标移至行尾,"),v("strong",[e._v("ctrl-k")]),e._v(" 可以删除光标至行尾的所有内容,"),v("strong",[e._v("ctrl-l")]),e._v(" 可以清屏。键入 "),v("code",[e._v("man readline")]),e._v(" 可以查看 Bash 中的默认快捷键。内容有很多,例如 "),v("strong",[e._v("alt-.")]),e._v(" 循环地移向前一个参数,而 "),v("strong",[e._v("alt-*")]),e._v(" 可以展开通配符。")])])]),e._v(" "),v("ul",[v("li",[v("p",[e._v("你喜欢的话,可以执行 "),v("code",[e._v("set -o vi")]),e._v(" 来使用 vi 风格的快捷键,而执行 "),v("code",[e._v("set -o emacs")]),e._v(" 可以把它改回来。")])]),e._v(" "),v("li",[v("p",[e._v("为了便于编辑长命令,在设置你的默认编辑器后(例如 "),v("code",[e._v("export EDITOR=vim")]),e._v("),"),v("strong",[e._v("ctrl-x")]),e._v(" "),v("strong",[e._v("ctrl-e")]),e._v(" 会打开一个编辑器来编辑当前输入的命令。在 vi 风格下快捷键则是 "),v("strong",[e._v("escape-v")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("键入 "),v("code",[e._v("history")]),e._v(" 查看命令行历史记录,再用 "),v("code",[e._v("!n")]),e._v("("),v("code",[e._v("n")]),e._v(" 是命令编号)就可以再次执行。其中有许多缩写,最有用的大概就是 "),v("code",[e._v("!$")]),e._v(", 它用于指代上次键入的参数,而 "),v("code",[e._v("!!")]),e._v(" 可以指代上次键入的命令了(参考 man 页面中的“HISTORY EXPANSION”)。不过这些功能,你也可以通过快捷键 "),v("strong",[e._v("ctrl-r")]),e._v(" 和 "),v("strong",[e._v("alt-.")]),e._v(" 来实现。")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("cd")]),e._v(" 命令可以切换工作路径,输入 "),v("code",[e._v("cd \\~")]),e._v(" 可以进入 home 目录。要访问你的 home 目录中的文件,可以使用前缀 "),v("code",[e._v("\\~")]),e._v("(例如 "),v("code",[e._v("\\~/.bashrc")]),e._v(")。在 "),v("code",[e._v("sh")]),e._v(" 脚本里则用环境变量 "),v("code",[e._v("$HOME")]),e._v(" 指代 home 目录的路径。")])]),e._v(" "),v("li",[v("p",[e._v("回到前一个工作路径:"),v("code",[e._v("cd -")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("如果你输入命令的时候中途改了主意,按下 "),v("strong",[e._v("alt-#")]),e._v(" 在行首添加 "),v("code",[e._v("#")]),e._v(" 把它当做注释再按下回车执行(或者依次按下 "),v("strong",[e._v("ctrl-a")]),e._v(", "),v("strong",[e._v("#")]),e._v(", "),v("strong",[e._v("enter")]),e._v(")。这样做的话,之后借助命令行历史记录,你可以很方便恢复你刚才输入到一半的命令。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("xargs")]),e._v(" ( 或 "),v("code",[e._v("parallel")]),e._v(")。他们非常给力。注意到你可以控制每行参数个数("),v("code",[e._v("-L")]),e._v(")和最大并行数("),v("code",[e._v("-P")]),e._v(")。如果你不确定它们是否会按你想的那样工作,先使用 "),v("code",[e._v("xargs echo")]),e._v(" 查看一下。此外,使用 "),v("code",[e._v("-I{}")]),e._v(" 会很方便。例如:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("find")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v(" -name "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'*.py'")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("xargs")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("grep")]),e._v(" some_function\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" hosts "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("xargs")]),e._v(" -I"),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("ssh")]),e._v(" root@"),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("hostname")]),e._v("\n")])])]),v("ul",[v("li",[v("p",[v("code",[e._v("pstree -p")]),e._v(" 以一种优雅的方式展示进程树。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("pgrep")]),e._v(" 和 "),v("code",[e._v("pkill")]),e._v(" 根据名字查找进程或发送信号("),v("code",[e._v("-f")]),e._v(" 参数通常有用)。")])]),e._v(" "),v("li",[v("p",[e._v("了解你可以发往进程的信号的种类。比如,使用 "),v("code",[e._v("kill -STOP [pid]")]),e._v(" 停止一个进程。使用 "),v("code",[e._v("man 7 signal")]),e._v(" 查看详细列表。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("nohup")]),e._v(" 或 "),v("code",[e._v("disown")]),e._v(" 使一个后台进程持续运行。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("netstat -lntp")]),e._v(" 或 "),v("code",[e._v("ss -plat")]),e._v(" 检查哪些进程在监听端口(默认是检查 TCP 端口; 添加参数 "),v("code",[e._v("-u")]),e._v(" 则检查 UDP 端口)或者 "),v("code",[e._v("lsof -iTCP -sTCP:LISTEN -P -n")]),e._v(" (这也可以在 OS X 上运行)。")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lsof")]),e._v(" 来查看开启的套接字和文件。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("uptime")]),e._v(" 或 "),v("code",[e._v("w")]),e._v(" 来查看系统已经运行多长时间。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("alias")]),e._v(" 来创建常用命令的快捷形式。例如:"),v("code",[e._v("alias ll='ls -latr'")]),e._v(" 创建了一个新的命令别名 "),v("code",[e._v("ll")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("可以把别名、shell 选项和常用函数保存在 "),v("code",[e._v("\\~/.bashrc")]),e._v(",具体看下这篇"),v("a",{attrs:{href:"http://superuser.com/a/183980/7106",target:"_blank",rel:"noopener noreferrer"}},[e._v("文章"),v("OutboundLink")],1),e._v("。这样做的话你就可以在所有 shell 会话中使用你的设定。")])]),e._v(" "),v("li",[v("p",[e._v("把环境变量的设定以及登陆时要执行的命令保存在 "),v("code",[e._v("\\~/.bash_profile")]),e._v("。而对于从图形界面启动的 shell 和 "),v("code",[e._v("cron")]),e._v(" 启动的 shell,则需要单独配置文件。")])]),e._v(" "),v("li",[v("p",[e._v("要想在几台电脑中同步你的配置文件(例如 "),v("code",[e._v(".bashrc")]),e._v(" 和 "),v("code",[e._v(".bash_profile")]),e._v("),可以借助 Git。")])]),e._v(" "),v("li",[v("p",[e._v("当变量和文件名中包含空格的时候要格外小心。Bash 变量要用引号括起来,比如 "),v("code",[e._v('"$FOO"')]),e._v("。尽量使用 "),v("code",[e._v("-0")]),e._v(" 或 "),v("code",[e._v("-print0")]),e._v(" 选项以便用 NULL 来分隔文件名,例如 "),v("code",[e._v("locate -0 pattern | xargs -0 ls -al")]),e._v(" 或 "),v("code",[e._v("find / -print0 -type d | xargs -0 ls -al")]),e._v("。如果 for 循环中循环访问的文件名含有空字符(空格、tab 等字符),只需用 "),v("code",[e._v("IFS=$'\\n'")]),e._v(" 把内部字段分隔符设为换行符。")])]),e._v(" "),v("li",[v("p",[e._v("在 Bash 脚本中,使用 "),v("code",[e._v("set -x")]),e._v(" 去调试输出(或者使用它的变体 "),v("code",[e._v("set -v")]),e._v(",它会记录原始输入,包括多余的参数和注释)。尽可能地使用严格模式:使用 "),v("code",[e._v("set -e")]),e._v(" 令脚本在发生错误时退出而不是继续运行;使用 "),v("code",[e._v("set -u")]),e._v(" 来检查是否使用了未赋值的变量;试试 "),v("code",[e._v("set -o pipefail")]),e._v(",它可以监测管道中的错误。当牵扯到很多脚本时,使用 "),v("code",[e._v("trap")]),e._v(" 来检测 ERR 和 EXIT。一个好的习惯是在脚本文件开头这样写,这会使它能够检测一些错误,并在错误发生时中断程序并输出信息:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("set")]),e._v(" -euo pipefail\n "),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("trap")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("\"echo 'error: Script failed: see failed command above'\"")]),e._v(" ERR\n")])])]),v("ul",[v("li",[e._v("在 Bash 脚本中,子 shell(使用括号 "),v("code",[e._v("(...)")]),e._v(")是一种组织参数的便捷方式。一个常见的例子是临时地移动工作路径,代码如下:")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# do something in current dir")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),e._v("cd /some/other/dir "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("&&")]),e._v(" other-command"),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# continue in original dir")]),e._v("\n")])])]),v("ul",[v("li",[v("p",[e._v("在 Bash 中,变量有许多的扩展方式。"),v("code",[e._v("${name:?error message}")]),e._v(" 用于检查变量是否存在。此外,当 Bash 脚本只需要一个参数时,可以使用这样的代码 "),v("code",[e._v("input_file=${1:?usage: $0 input_file}")]),e._v("。在变量为空时使用默认值:"),v("code",[e._v("${name:-default}")]),e._v("。如果你要在之前的例子中再加一个(可选的)参数,可以使用类似这样的代码 "),v("code",[e._v("output_file=${2:-logfile}")]),e._v(",如果省略了 $2,它的值就为空,于是 "),v("code",[e._v("output_file")]),e._v(" 就会被设为 "),v("code",[e._v("logfile")]),e._v("。数学表达式:"),v("code",[e._v("i=$(( (i + 1) % 5 ))")]),e._v("。序列:"),v("code",[e._v("{1..10}")]),e._v("。截断字符串:"),v("code",[e._v("${var%suffix}")]),e._v(" 和 "),v("code",[e._v("${var#prefix}")]),e._v("。例如,假设 "),v("code",[e._v("var=foo.pdf")]),e._v(",那么 "),v("code",[e._v("echo ${var%.pdf}.txt")]),e._v(" 将输出 "),v("code",[e._v("foo.txt")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("使用括号扩展("),v("code",[e._v("{")]),e._v("..."),v("code",[e._v("}")]),e._v(")来减少输入相似文本,并自动化文本组合。这在某些情况下会很有用,例如 "),v("code",[e._v("mv foo.{txt,pdf} some-dir")]),e._v("(同时移动两个文件),"),v("code",[e._v("cp somefile{,.bak}")]),e._v("(会被扩展成 "),v("code",[e._v("cp somefile somefile.bak")]),e._v(")或者 "),v("code",[e._v("mkdir -p test-{a,b,c}/subtest-{1,2,3}")]),e._v("(会被扩展成所有可能的组合,并创建一个目录树)。")])]),e._v(" "),v("li",[v("p",[e._v("通过使用 "),v("code",[e._v("<(some command)")]),e._v(" 可以将输出视为文件。例如,对比本地文件 "),v("code",[e._v("/etc/hosts")]),e._v(" 和一个远程文件:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("diff")]),e._v(" /etc/hosts "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<")]),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("ssh")]),e._v(" somehost "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("cat")]),e._v(" /etc/hosts"),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v("\n")])])]),v("ul",[v("li",[e._v("编写脚本时,你可能会想要把代码都放在大括号里。缺少右括号的话,代码就会因为语法错误而无法执行。如果你的脚本是要放在网上分享供他人使用的,这样的写法就体现出它的好处了,因为这样可以防止下载不完全代码被执行。")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 在这里写代码")]),e._v("\n"),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),v("ul",[v("li",[v("p",[e._v("了解 Bash 中的“here documents”,例如 "),v("code",[e._v("cat <logfile 2>&1")]),e._v(" 或者 "),v("code",[e._v("some-command &>logfile")]),e._v("。通常,为了保证命令不会在标准输入里残留一个未关闭的文件句柄捆绑在你当前所在的终端上,在命令后添加 "),v("code",[e._v(">> 2+3\n5\n")])])]),v("h2",{attrs:{id:"文件及数据处理"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#文件及数据处理"}},[e._v("#")]),e._v(" 文件及数据处理")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("在当前目录下通过文件名查找一个文件,使用类似于这样的命令:"),v("code",[e._v("find . -iname '*something*'")]),e._v("。在所有路径下通过文件名查找文件,使用 "),v("code",[e._v("locate something")]),e._v(" (但注意到 "),v("code",[e._v("updatedb")]),e._v(" 可能没有对最近新建的文件建立索引,所以你可能无法定位到这些未被索引的文件)。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("a",{attrs:{href:"https://github.com/ggreer/the_silver_searcher",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("ag")]),v("OutboundLink")],1),e._v(" 在源代码或数据文件里检索("),v("code",[e._v("grep -r")]),e._v(" 同样可以做到,但相比之下 "),v("code",[e._v("ag")]),e._v(" 更加先进)。")])]),e._v(" "),v("li",[v("p",[e._v("将 HTML 转为文本:"),v("code",[e._v("lynx -dump -stdin")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("Markdown,HTML,以及所有文档格式之间的转换,试试 "),v("a",{attrs:{href:"http://pandoc.org/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("pandoc")]),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("当你要处理棘手的 XML 时候,"),v("code",[e._v("xmlstarlet")]),e._v(" 算是上古时代流传下来的神器。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("a",{attrs:{href:"http://stedolan.github.io/jq/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("jq")]),v("OutboundLink")],1),e._v(" 处理 JSON。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("a",{attrs:{href:"https://github.com/0k/shyaml",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("shyaml")]),v("OutboundLink")],1),e._v(" 处理 YAML。")])]),e._v(" "),v("li",[v("p",[e._v("要处理 Excel 或 CSV 文件的话,"),v("a",{attrs:{href:"https://github.com/onyxfish/csvkit",target:"_blank",rel:"noopener noreferrer"}},[e._v("csvkit"),v("OutboundLink")],1),e._v(" 提供了 "),v("code",[e._v("in2csv")]),e._v(","),v("code",[e._v("csvcut")]),e._v(","),v("code",[e._v("csvjoin")]),e._v(","),v("code",[e._v("csvgrep")]),e._v(" 等方便易用的工具。")])]),e._v(" "),v("li",[v("p",[e._v("当你要处理 Amazon S3 相关的工作的时候,"),v("a",{attrs:{href:"https://github.com/s3tools/s3cmd",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("s3cmd")]),v("OutboundLink")],1),e._v(" 是一个很方便的工具而 "),v("a",{attrs:{href:"https://github.com/bloomreach/s4cmd",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("s4cmd")]),v("OutboundLink")],1),e._v(" 的效率更高。Amazon 官方提供的 "),v("a",{attrs:{href:"https://github.com/aws/aws-cli",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("aws")]),v("OutboundLink")],1),e._v(" 以及 "),v("a",{attrs:{href:"https://github.com/donnemartin/saws",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("saws")]),v("OutboundLink")],1),e._v(" 是其他 AWS 相关工作的基础,值得学习。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何使用 "),v("code",[e._v("sort")]),e._v(" 和 "),v("code",[e._v("uniq")]),e._v(",包括 uniq 的 "),v("code",[e._v("-u")]),e._v(" 参数和 "),v("code",[e._v("-d")]),e._v(" 参数,具体内容在后文单行脚本节中。另外可以了解一下 "),v("code",[e._v("comm")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何使用 "),v("code",[e._v("cut")]),e._v(","),v("code",[e._v("paste")]),e._v(" 和 "),v("code",[e._v("join")]),e._v(" 来更改文件。很多人都会使用 "),v("code",[e._v("cut")]),e._v(",但遗忘了 "),v("code",[e._v("join")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何运用 "),v("code",[e._v("wc")]),e._v(" 去计算新行数("),v("code",[e._v("-l")]),e._v("),字符数("),v("code",[e._v("-m")]),e._v("),单词数("),v("code",[e._v("-w")]),e._v(")以及字节数("),v("code",[e._v("-c")]),e._v(")。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何使用 "),v("code",[e._v("tee")]),e._v(" 将标准输入复制到文件甚至标准输出,例如 "),v("code",[e._v("ls -al | tee file.txt")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("要进行一些复杂的计算,比如分组、逆序和一些其他的统计分析,可以考虑使用 "),v("a",{attrs:{href:"https://www.gnu.org/software/datamash/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("datamash")]),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("注意到语言设置(中文或英文等)对许多命令行工具有一些微妙的影响,比如排序的顺序和性能。大多数 Linux 的安装过程会将 "),v("code",[e._v("LANG")]),e._v(" 或其他有关的变量设置为符合本地的设置。要意识到当你改变语言设置时,排序的结果可能会改变。明白国际化可能会使 sort 或其他命令运行效率下降"),v("em",[e._v("许多倍")]),e._v("。某些情况下(例如集合运算)你可以放心的使用 "),v("code",[e._v("export LC_ALL=C")]),e._v(" 来忽略掉国际化并按照字节来判断顺序。")])]),e._v(" "),v("li",[v("p",[e._v("你可以单独指定某一条命令的环境,只需在调用时把环境变量设定放在命令的前面,例如 "),v("code",[e._v("TZ=Pacific/Fiji date")]),e._v(" 可以获取斐济的时间。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何使用 "),v("code",[e._v("awk")]),e._v(" 和 "),v("code",[e._v("sed")]),e._v(" 来进行简单的数据处理。 参阅 "),v("a",{attrs:{href:"#one-liners"}},[e._v("One-liners")]),e._v(" 获取示例。")])]),e._v(" "),v("li",[v("p",[e._v("替换一个或多个文件中出现的字符串:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" perl -pi.bak -e "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/old-string/new-string/g'")]),e._v(" my-files-*.txt\n")])])]),v("ul",[v("li",[e._v("使用 "),v("a",{attrs:{href:"https://github.com/jlevy/repren",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("repren")]),v("OutboundLink")],1),e._v(" 来批量重命名文件,或是在多个文件中搜索替换内容。(有些时候 "),v("code",[e._v("rename")]),e._v(" 命令也可以批量重命名,但要注意,它在不同 Linux 发行版中的功能并不完全一样。)")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 将文件、目录和内容全部重命名 foo -> bar:")]),e._v("\n repren --full --preserve-case --from foo --to bar "),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 还原所有备份文件 whatever.bak -> whatever:")]),e._v("\n repren --renames --from "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'(.*)\\.bak'")]),e._v(" --to "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'"),v("span",{pre:!0,attrs:{class:"token entity",title:"\\1"}},[e._v("\\1")]),e._v("'")]),e._v(" *.bak\n "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 用 rename 实现上述功能(若可用):")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("rename")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/\\.bak$//'")]),e._v(" *.bak\n")])])]),v("ul",[v("li",[e._v("根据 man 页面的描述,"),v("code",[e._v("rsync")]),e._v(" 是一个快速且非常灵活的文件复制工具。它闻名于设备之间的文件同步,但其实它在本地情况下也同样有用。在安全设置允许下,用 "),v("code",[e._v("rsync")]),e._v(" 代替 "),v("code",[e._v("scp")]),e._v(" 可以实现文件续传,而不用重新从头开始。它同时也是删除大量文件的"),v("a",{attrs:{href:"https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("最快方法"),v("OutboundLink")],1),e._v("之一:")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[v("span",{pre:!0,attrs:{class:"token function"}},[e._v("mkdir")]),e._v(" empty "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("&&")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("rsync")]),e._v(" -r --delete empty/ some-dir "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("&&")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("rmdir")]),e._v(" some-dir\n")])])]),v("ul",[v("li",[v("p",[e._v("若要在复制文件时获取当前进度,可使用 "),v("code",[e._v("pv")]),e._v(","),v("a",{attrs:{href:"https://github.com/dmerejkowsky/pycp",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("pycp")]),v("OutboundLink")],1),e._v(","),v("a",{attrs:{href:"https://github.com/Xfennec/progress",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("progress")]),v("OutboundLink")],1),e._v(","),v("code",[e._v("rsync --progress")]),e._v("。若所执行的复制为 block 块拷贝,可以使用 "),v("code",[e._v("dd status=progress")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("shuf")]),e._v(" 可以以行为单位来打乱文件的内容或从一个文件中随机选取多行。")])]),e._v(" "),v("li",[v("p",[e._v("了解 "),v("code",[e._v("sort")]),e._v(" 的参数。显示数字时,使用 "),v("code",[e._v("-n")]),e._v(" 或者 "),v("code",[e._v("-h")]),e._v(" 来显示更易读的数(例如 "),v("code",[e._v("du -h")]),e._v(" 的输出)。明白排序时关键字的工作原理("),v("code",[e._v("-t")]),e._v(" 和 "),v("code",[e._v("-k")]),e._v(")。例如,注意到你需要 "),v("code",[e._v("-k1,1")]),e._v(" 来仅按第一个域来排序,而 "),v("code",[e._v("-k1")]),e._v(" 意味着按整行排序。稳定排序("),v("code",[e._v("sort -s")]),e._v(")在某些情况下很有用。例如,以第二个域为主关键字,第一个域为次关键字进行排序,你可以使用 "),v("code",[e._v("sort -k1,1 | sort -s -k2,2")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("如果你想在 Bash 命令行中写 tab 制表符,按下 "),v("strong",[e._v("ctrl-v")]),e._v(" "),v("strong",[e._v("[Tab]")]),e._v(" 或键入 "),v("code",[e._v("$'\\t'")]),e._v(" (后者可能更好,因为你可以复制粘贴它)。")])]),e._v(" "),v("li",[v("p",[e._v("标准的源代码对比及合并工具是 "),v("code",[e._v("diff")]),e._v(" 和 "),v("code",[e._v("patch")]),e._v("。使用 "),v("code",[e._v("diffstat")]),e._v(" 查看变更总览数据。注意到 "),v("code",[e._v("diff -r")]),e._v(" 对整个文件夹有效。使用 "),v("code",[e._v("diff -r tree1 tree2 | diffstat")]),e._v(" 查看变更的统计数据。"),v("code",[e._v("vimdiff")]),e._v(" 用于比对并编辑文件。")])]),e._v(" "),v("li",[v("p",[e._v("对于二进制文件,使用 "),v("code",[e._v("hd")]),e._v(","),v("code",[e._v("hexdump")]),e._v(" 或者 "),v("code",[e._v("xxd")]),e._v(" 使其以十六进制显示,使用 "),v("code",[e._v("bvi")]),e._v(","),v("code",[e._v("hexedit")]),e._v(" 或者 "),v("code",[e._v("biew")]),e._v(" 来进行二进制编辑。")])]),e._v(" "),v("li",[v("p",[e._v("同样对于二进制文件,"),v("code",[e._v("strings")]),e._v("(包括 "),v("code",[e._v("grep")]),e._v(" 等工具)可以帮助在二进制文件中查找特定比特。")])]),e._v(" "),v("li",[v("p",[e._v("制作二进制差分文件(Delta 压缩),使用 "),v("code",[e._v("xdelta3")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("iconv")]),e._v(" 更改文本编码。需要更高级的功能,可以使用 "),v("code",[e._v("uconv")]),e._v(",它支持一些高级的 Unicode 功能。例如,这条命令移除了所有重音符号:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" uconv -f utf-8 -t utf-8 -x "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'::Any-Lower; ::Any-NFD; [:Nonspacing Mark:] >; ::Any-NFC; '")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<")]),e._v(" input.txt "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" output.txt\n")])])]),v("ul",[v("li",[v("p",[e._v("拆分文件可以使用 "),v("code",[e._v("split")]),e._v("(按大小拆分)和 "),v("code",[e._v("csplit")]),e._v("(按模式拆分)。")])]),e._v(" "),v("li",[v("p",[e._v("操作日期和时间表达式,可以用 "),v("a",{attrs:{href:"http://www.fresse.org/dateutils/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("dateutils")]),v("OutboundLink")],1),e._v(" 中的 "),v("code",[e._v("dateadd")]),e._v("、"),v("code",[e._v("datediff")]),e._v("、"),v("code",[e._v("strptime")]),e._v(" 等工具。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("zless")]),e._v("、"),v("code",[e._v("zmore")]),e._v("、"),v("code",[e._v("zcat")]),e._v(" 和 "),v("code",[e._v("zgrep")]),e._v(" 对压缩过的文件进行操作。")])]),e._v(" "),v("li",[v("p",[e._v("文件属性可以通过 "),v("code",[e._v("chattr")]),e._v(" 进行设置,它比文件权限更加底层。例如,为了保护文件不被意外删除,可以使用不可修改标记:"),v("code",[e._v("sudo chattr +i /critical/directory/or/file")])])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("getfacl")]),e._v(" 和 "),v("code",[e._v("setfacl")]),e._v(" 以保存和恢复文件权限。例如:")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" getfacl -R /some/path "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" permissions.txt\n setfacl --restore"),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("permissions.txt\n")])])]),v("ul",[v("li",[e._v("为了高效地创建空文件,请使用 "),v("code",[e._v("truncate")]),e._v("(创建"),v("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E7%A8%80%E7%96%8F%E6%96%87%E4%BB%B6",target:"_blank",rel:"noopener noreferrer"}},[e._v("稀疏文件"),v("OutboundLink")],1),e._v("),"),v("code",[e._v("fallocate")]),e._v("(用于 ext4,xfs,btrf 和 ocfs2 文件系统),"),v("code",[e._v("xfs_mkfile")]),e._v("(适用于几乎所有的文件系统,包含在 xfsprogs 包中),"),v("code",[e._v("mkfile")]),e._v("(用于类 Unix 操作系统,比如 Solaris 和 Mac OS)。")])]),e._v(" "),v("h2",{attrs:{id:"系统调试"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#系统调试"}},[e._v("#")]),e._v(" 系统调试")]),e._v(" "),v("ul",[v("li",[v("p",[v("code",[e._v("curl")]),e._v(" 和 "),v("code",[e._v("curl -I")]),e._v(" 可以被轻松地应用于 web 调试中,它们的好兄弟 "),v("code",[e._v("wget")]),e._v(" 也是如此,或者也可以试试更潮的 "),v("a",{attrs:{href:"https://github.com/jkbrzt/httpie",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("httpie")]),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("获取 CPU 和硬盘的使用状态,通常使用使用 "),v("code",[e._v("top")]),e._v("("),v("code",[e._v("htop")]),e._v(" 更佳),"),v("code",[e._v("iostat")]),e._v(" 和 "),v("code",[e._v("iotop")]),e._v("。而 "),v("code",[e._v("iostat -mxz 15")]),e._v(" 可以让你获悉 CPU 和每个硬盘分区的基本信息和性能表现。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("netstat")]),e._v(" 和 "),v("code",[e._v("ss")]),e._v(" 查看网络连接的细节。")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("dstat")]),e._v(" 在你想要对系统的现状有一个粗略的认识时是非常有用的。然而若要对系统有一个深度的总体认识,使用 "),v("a",{attrs:{href:"https://github.com/nicolargo/glances",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("glances")]),v("OutboundLink")],1),e._v(",它会在一个终端窗口中向你提供一些系统级的数据。")])]),e._v(" "),v("li",[v("p",[e._v("若要了解内存状态,运行并理解 "),v("code",[e._v("free")]),e._v(" 和 "),v("code",[e._v("vmstat")]),e._v(" 的输出。值得留意的是“cached”的值,它指的是 Linux 内核用来作为文件缓存的内存大小,而与空闲内存无关。")])]),e._v(" "),v("li",[v("p",[e._v("Java 系统调试则是一件截然不同的事,一个可以用于 Oracle 的 JVM 或其他 JVM 上的调试的技巧是你可以运行 "),v("code",[e._v("kill -3 ")]),e._v(" 同时一个完整的栈轨迹和堆概述(包括 GC 的细节)会被保存到标准错误或是日志文件。JDK 中的 "),v("code",[e._v("jps")]),e._v(","),v("code",[e._v("jstat")]),e._v(","),v("code",[e._v("jstack")]),e._v(","),v("code",[e._v("jmap")]),e._v(" 很有用。"),v("a",{attrs:{href:"https://github.com/aragozin/jvm-tools",target:"_blank",rel:"noopener noreferrer"}},[e._v("SJK tools"),v("OutboundLink")],1),e._v(" 更高级。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("a",{attrs:{href:"http://www.bitwizard.nl/mtr/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("mtr")]),v("OutboundLink")],1),e._v(" 去跟踪路由,用于确定网络问题。")])]),e._v(" "),v("li",[v("p",[e._v("用 "),v("a",{attrs:{href:"https://dev.yorhel.nl/ncdu",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("ncdu")]),v("OutboundLink")],1),e._v(" 来查看磁盘使用情况,它比寻常的命令,如 "),v("code",[e._v("du -sh *")]),e._v(",更节省时间。")])]),e._v(" "),v("li",[v("p",[e._v("查找正在使用带宽的套接字连接或进程,使用 "),v("a",{attrs:{href:"http://www.ex-parrot.com/~pdw/iftop/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("iftop")]),v("OutboundLink")],1),e._v(" 或 "),v("a",{attrs:{href:"https://github.com/raboof/nethogs",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("nethogs")]),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("ab")]),e._v(" 工具(Apache 中自带)可以简单粗暴地检查 web 服务器的性能。对于更复杂的负载测试,使用 "),v("code",[e._v("siege")]),e._v("。")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://wireshark.org/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("wireshark")]),v("OutboundLink")],1),e._v(","),v("a",{attrs:{href:"https://www.wireshark.org/docs/wsug_html_chunked/AppToolstshark.html",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("tshark")]),v("OutboundLink")],1),e._v(" 和 "),v("a",{attrs:{href:"http://ngrep.sourceforge.net/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("ngrep")]),v("OutboundLink")],1),e._v(" 可用于复杂的网络调试。")])]),e._v(" "),v("li",[v("p",[e._v("了解 "),v("code",[e._v("strace")]),e._v(" 和 "),v("code",[e._v("ltrace")]),e._v("。这俩工具在你的程序运行失败、挂起甚至崩溃,而你却不知道为什么或你想对性能有个总体的认识的时候是非常有用的。注意 profile 参数("),v("code",[e._v("-c")]),e._v(")和附加到一个运行的进程参数 ("),v("code",[e._v("-p")]),e._v(")。")])]),e._v(" "),v("li",[v("p",[e._v("了解使用 "),v("code",[e._v("ldd")]),e._v(" 来检查共享库。但是"),v("a",{attrs:{href:"http://www.catonmat.net/blog/ldd-arbitrary-code-execution/",target:"_blank",rel:"noopener noreferrer"}},[e._v("永远不要在不信任的文件上运行"),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("了解如何运用 "),v("code",[e._v("gdb")]),e._v(" 连接到一个运行着的进程并获取它的堆栈轨迹。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用 "),v("code",[e._v("/proc")]),e._v("。它在调试正在出现的问题的时候有时会效果惊人。比如:"),v("code",[e._v("/proc/cpuinfo")]),e._v(","),v("code",[e._v("/proc/meminfo")]),e._v(","),v("code",[e._v("/proc/cmdline")]),e._v(","),v("code",[e._v("/proc/xxx/cwd")]),e._v(","),v("code",[e._v("/proc/xxx/exe")]),e._v(","),v("code",[e._v("/proc/xxx/fd/")]),e._v(","),v("code",[e._v("/proc/xxx/smaps")]),e._v("(这里的 "),v("code",[e._v("xxx")]),e._v(" 表示进程的 id 或 pid)。")])]),e._v(" "),v("li",[v("p",[e._v("当调试一些之前出现的问题的时候,"),v("a",{attrs:{href:"http://sebastien.godard.pagesperso-orange.fr/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("sar")]),v("OutboundLink")],1),e._v(" 非常有用。它展示了 cpu、内存以及网络等的历史数据。")])]),e._v(" "),v("li",[v("p",[e._v("关于更深层次的系统分析以及性能分析,看看 "),v("code",[e._v("stap")]),e._v("("),v("a",{attrs:{href:"https://sourceware.org/systemtap/wiki",target:"_blank",rel:"noopener noreferrer"}},[e._v("SystemTap"),v("OutboundLink")],1),e._v("),"),v("a",{attrs:{href:"https://en.wikipedia.org/wiki/Perf_(Linux)",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("perf")]),v("OutboundLink")],1),e._v(",以及"),v("a",{attrs:{href:"https://github.com/draios/sysdig",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("sysdig")]),v("OutboundLink")],1),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("查看你当前使用的系统,使用 "),v("code",[e._v("uname")]),e._v(","),v("code",[e._v("uname -a")]),e._v("(Unix/kernel 信息)或者 "),v("code",[e._v("lsb_release -a")]),e._v("(Linux 发行版信息)。")])]),e._v(" "),v("li",[v("p",[e._v("无论什么东西工作得很欢乐(可能是硬件或驱动问题)时可以试试 "),v("code",[e._v("dmesg")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("如果你删除了一个文件,但通过 "),v("code",[e._v("du")]),e._v(" 发现没有释放预期的磁盘空间,请检查文件是否被进程占用:\n"),v("code",[e._v('lsof | grep deleted | grep "filename-of-my-big-file"')])])])]),e._v(" "),v("h2",{attrs:{id:"单行脚本"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#单行脚本"}},[e._v("#")]),e._v(" 单行脚本")]),e._v(" "),v("p",[e._v("一些命令组合的例子:")]),e._v(" "),v("ul",[v("li",[e._v("当你需要对文本文件做集合交、并、差运算时,"),v("code",[e._v("sort")]),e._v(" 和 "),v("code",[e._v("uniq")]),e._v(" 会是你的好帮手。具体例子请参照代码后面的,此处假设 "),v("code",[e._v("a")]),e._v(" 与 "),v("code",[e._v("b")]),e._v(" 是两内容不同的文件。这种方式效率很高,并且在小文件和上 G 的文件上都能运用(注意尽管在 "),v("code",[e._v("/tmp")]),e._v(" 在一个小的根分区上时你可能需要 "),v("code",[e._v("-T")]),e._v(" 参数,但是实际上 "),v("code",[e._v("sort")]),e._v(" 并不被内存大小约束),参阅前文中关于 "),v("code",[e._v("LC_ALL")]),e._v(" 和 "),v("code",[e._v("sort")]),e._v(" 的 "),v("code",[e._v("-u")]),e._v(" 参数的部分。")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("sort")]),e._v(" a b "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("uniq")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" c "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# c 是 a 并 b")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("sort")]),e._v(" a b "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("uniq")]),e._v(" -d "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" c "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# c 是 a 交 b")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("sort")]),e._v(" a b b "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("uniq")]),e._v(" -u "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v(" c "),v("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# c 是 a - b")]),e._v("\n")])])]),v("ul",[v("li",[e._v("使用 "),v("code",[e._v("grep . *")]),e._v("(每行都会附上文件名)或者 "),v("code",[e._v("head -100 *")]),e._v("(每个文件有一个标题)来阅读检查目录下所有文件的内容。这在检查一个充满配置文件的目录(如 "),v("code",[e._v("/sys")]),e._v("、"),v("code",[e._v("/proc")]),e._v("、"),v("code",[e._v("/etc")]),e._v(")时特别好用。")])]),e._v(" "),v("ul",[v("li",[e._v("计算文本文件第三列中所有数的和(可能比同等作用的 Python 代码快三倍且代码量少三倍):")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("awk")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'{ x += "),v("span",{pre:!0,attrs:{class:"token variable"}},[e._v("$3")]),e._v(" } END { print x }'")]),e._v(" myfile\n")])])]),v("ul",[v("li",[e._v("如果你想在文件树上查看大小/日期,这可能看起来像递归版的 "),v("code",[e._v("ls -l")]),e._v(" 但比 "),v("code",[e._v("ls -lR")]),e._v(" 更易于理解:")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("find")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v(".")]),e._v(" -type f -ls\n")])])]),v("ul",[v("li",[e._v("假设你有一个类似于 web 服务器日志文件的文本文件,并且一个确定的值只会出现在某些行上,假设一个 "),v("code",[e._v("acct_id")]),e._v(" 参数在 URI 中。如果你想计算出每个 "),v("code",[e._v("acct_id")]),e._v(" 值有多少次请求,使用如下代码:")])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("egrep")]),e._v(" -o "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'acct_id=[0-9]+'")]),e._v(" access.log "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("cut")]),e._v(" -d"),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v(" -f2 "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("sort")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("uniq")]),e._v(" -c "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("sort")]),e._v(" -rn\n")])])]),v("ul",[v("li",[v("p",[e._v("要持续监测文件改动,可以使用 "),v("code",[e._v("watch")]),e._v(",例如检查某个文件夹中文件的改变,可以用 "),v("code",[e._v("watch -d -n 2 'ls -rtlh | tail'")]),e._v(";或者在排查 WiFi 设置故障时要监测网络设置的更改,可以用 "),v("code",[e._v("watch -d -n 2 ifconfig")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("运行这个函数从这篇文档中随机获取一条技巧(解析 Markdown 文件并抽取项目):")])])]),e._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[e._v(" "),v("span",{pre:!0,attrs:{class:"token keyword"}},[e._v("function")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function-name function"}},[e._v("taocl")]),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("(")]),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("curl")]),e._v(" -s https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/README-zh.md"),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v("\n pandoc -f markdown -t html "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v("\n "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("iconv")]),e._v(" -f "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'utf-8'")]),e._v(" -t "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v("'unicode'")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v("\n xmlstarlet fo --html --dropdtd "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v("\n xmlstarlet sel -t -v "),v("span",{pre:!0,attrs:{class:"token string"}},[e._v('"(html/body/ul/li[count(p)>0])['),v("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("$RANDOM")]),e._v(' mod last()+1]"')]),e._v(" "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v("\n xmlstarlet unesc "),v("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),v("span",{pre:!0,attrs:{class:"token function"}},[e._v("fmt")]),e._v(" -80\n "),v("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),v("h2",{attrs:{id:"冷门但有用"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#冷门但有用"}},[e._v("#")]),e._v(" 冷门但有用")]),e._v(" "),v("ul",[v("li",[v("p",[v("code",[e._v("expr")]),e._v(":计算表达式或正则匹配")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("m4")]),e._v(":简单的宏处理器")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("yes")]),e._v(":多次打印字符串")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("cal")]),e._v(":漂亮的日历")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("env")]),e._v(":执行一个命令(脚本文件中很有用)")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("printenv")]),e._v(":打印环境变量(调试时或在写脚本文件时很有用)")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("look")]),e._v(":查找以特定字符串开头的单词或行")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("cut")]),e._v(","),v("code",[e._v("paste")]),e._v(" 和 "),v("code",[e._v("join")]),e._v(":数据修改")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("fmt")]),e._v(":格式化文本段落")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("pr")]),e._v(":将文本格式化成页/列形式")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("fold")]),e._v(":包裹文本中的几行")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("column")]),e._v(":将文本格式化成多个对齐、定宽的列或表格")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("expand")]),e._v(" 和 "),v("code",[e._v("unexpand")]),e._v(":制表符与空格之间转换")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("nl")]),e._v(":添加行号")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("seq")]),e._v(":打印数字")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("bc")]),e._v(":计算器")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("factor")]),e._v(":分解因数")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://gnupg.org/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("gpg")]),v("OutboundLink")],1),e._v(":加密并签名文件")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("toe")]),e._v(":terminfo 入口列表")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("nc")]),e._v(":网络调试及数据传输")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("socat")]),e._v(":套接字代理,与 "),v("code",[e._v("netcat")]),e._v(" 类似")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://github.com/mattthias/slurm",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("slurm")]),v("OutboundLink")],1),e._v(":网络流量可视化")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("dd")]),e._v(":文件或设备间传输数据")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("file")]),e._v(":确定文件类型")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("tree")]),e._v(":以树的形式显示路径和文件,类似于递归的 "),v("code",[e._v("ls")])])]),e._v(" "),v("li",[v("p",[v("code",[e._v("stat")]),e._v(":文件信息")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("time")]),e._v(":执行命令,并计算执行时间")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("timeout")]),e._v(":在指定时长范围内执行命令,并在规定时间结束后停止进程")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lockfile")]),e._v(":使文件只能通过 "),v("code",[e._v("rm -f")]),e._v(" 移除")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("logrotate")]),e._v(": 切换、压缩以及发送日志文件")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("watch")]),e._v(":重复运行同一个命令,展示结果并/或高亮有更改的部分")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://github.com/joh/when-changed",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("when-changed")]),v("OutboundLink")],1),e._v(":当检测到文件更改时执行指定命令。参阅 "),v("code",[e._v("inotifywait")]),e._v(" 和 "),v("code",[e._v("entr")]),e._v("。")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("tac")]),e._v(":反向输出文件")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("shuf")]),e._v(":文件中随机选取几行")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("comm")]),e._v(":一行一行的比较排序过的文件")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("strings")]),e._v(":从二进制文件中抽取文本")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("tr")]),e._v(":转换字母")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("iconv")]),e._v(" 或 "),v("code",[e._v("uconv")]),e._v(":文本编码转换")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("split")]),e._v(" 和 "),v("code",[e._v("csplit")]),e._v(":分割文件")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("sponge")]),e._v(":在写入前读取所有输入,在读取文件后再向同一文件写入时比较有用,例如 "),v("code",[e._v("grep -v something some-file | sponge some-file")])])]),e._v(" "),v("li",[v("p",[v("code",[e._v("units")]),e._v(":将一种计量单位转换为另一种等效的计量单位(参阅 "),v("code",[e._v("/usr/share/units/definitions.units")]),e._v(")")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("apg")]),e._v(":随机生成密码")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("xz")]),e._v(":高比例的文件压缩")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("ldd")]),e._v(":动态库信息")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("nm")]),e._v(":提取 obj 文件中的符号")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("ab")]),e._v(" 或 "),v("a",{attrs:{href:"https://github.com/wg/wrk",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("wrk")]),v("OutboundLink")],1),e._v(":web 服务器性能分析")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("strace")]),e._v(":调试系统调用")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"http://www.bitwizard.nl/mtr/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("mtr")]),v("OutboundLink")],1),e._v(":更好的网络调试跟踪工具")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("cssh")]),e._v(":可视化的并发 shell")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("rsync")]),e._v(":通过 ssh 或本地文件系统同步文件和文件夹")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://wireshark.org/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("wireshark")]),v("OutboundLink")],1),e._v(" 和 "),v("a",{attrs:{href:"https://www.wireshark.org/docs/wsug_html_chunked/AppToolstshark.html",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("tshark")]),v("OutboundLink")],1),e._v(":抓包和网络调试工具")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"http://ngrep.sourceforge.net/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("ngrep")]),v("OutboundLink")],1),e._v(":网络层的 grep")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("host")]),e._v(" 和 "),v("code",[e._v("dig")]),e._v(":DNS 查找")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lsof")]),e._v(":列出当前系统打开文件的工具以及查看端口信息")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("dstat")]),e._v(":系统状态查看")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"https://github.com/nicolargo/glances",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("glances")]),v("OutboundLink")],1),e._v(":高层次的多子系统总览")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("iostat")]),e._v(":硬盘使用状态")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("mpstat")]),e._v(": CPU 使用状态")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("vmstat")]),e._v(": 内存使用状态")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("htop")]),e._v(":top 的加强版")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("last")]),e._v(":登入记录")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("w")]),e._v(":查看处于登录状态的用户")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("id")]),e._v(":用户/组 ID 信息")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"http://sebastien.godard.pagesperso-orange.fr/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("sar")]),v("OutboundLink")],1),e._v(":系统历史数据")])]),e._v(" "),v("li",[v("p",[v("a",{attrs:{href:"http://www.ex-parrot.com/~pdw/iftop/",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("iftop")]),v("OutboundLink")],1),e._v(" 或 "),v("a",{attrs:{href:"https://github.com/raboof/nethogs",target:"_blank",rel:"noopener noreferrer"}},[v("code",[e._v("nethogs")]),v("OutboundLink")],1),e._v(":套接字及进程的网络利用情况")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("ss")]),e._v(":套接字数据")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("dmesg")]),e._v(":引导及系统错误信息")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("sysctl")]),e._v(": 在内核运行时动态地查看和修改内核的运行参数")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("hdparm")]),e._v(":SATA/ATA 磁盘更改及性能分析")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lsblk")]),e._v(":列出块设备信息:以树形展示你的磁盘以及磁盘分区信息")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lshw")]),e._v(","),v("code",[e._v("lscpu")]),e._v(","),v("code",[e._v("lspci")]),e._v(","),v("code",[e._v("lsusb")]),e._v(" 和 "),v("code",[e._v("dmidecode")]),e._v(":查看硬件信息,包括 CPU、BIOS、RAID、显卡、USB 设备等")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("lsmod")]),e._v(" 和 "),v("code",[e._v("modinfo")]),e._v(":列出内核模块,并显示其细节")])]),e._v(" "),v("li",[v("p",[v("code",[e._v("fortune")]),e._v(","),v("code",[e._v("ddate")]),e._v(" 和 "),v("code",[e._v("sl")]),e._v(":额,这主要取决于你是否认为蒸汽火车和莫名其妙的名人名言是否“有用”")])])]),e._v(" "),v("h2",{attrs:{id:"仅限-os-x-系统"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#仅限-os-x-系统"}},[e._v("#")]),e._v(" 仅限 OS X 系统")]),e._v(" "),v("p",[e._v("以下是"),v("em",[e._v("仅限于")]),e._v(" OS X 系统的技巧。")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("用 "),v("code",[e._v("brew")]),e._v(" (Homebrew)或者 "),v("code",[e._v("port")]),e._v(" (MacPorts)进行包管理。这些可以用来在 OS X 系统上安装以上的大多数命令。")])]),e._v(" "),v("li",[v("p",[e._v("用 "),v("code",[e._v("pbcopy")]),e._v(" 复制任何命令的输出到桌面应用,用 "),v("code",[e._v("pbpaste")]),e._v(" 粘贴输入。")])]),e._v(" "),v("li",[v("p",[e._v("若要在 OS X 终端中将 Option 键视为 alt 键(例如在上面介绍的 "),v("strong",[e._v("alt-b")]),e._v("、"),v("strong",[e._v("alt-f")]),e._v(" 等命令中用到),打开 偏好设置 -> 描述文件 -> 键盘 并勾选“使用 Option 键作为 Meta 键”。")])]),e._v(" "),v("li",[v("p",[e._v("用 "),v("code",[e._v("open")]),e._v(" 或者 "),v("code",[e._v("open -a /Applications/Whatever.app")]),e._v(" 使用桌面应用打开文件。")])]),e._v(" "),v("li",[v("p",[e._v("Spotlight:用 "),v("code",[e._v("mdfind")]),e._v(" 搜索文件,用 "),v("code",[e._v("mdls")]),e._v(" 列出元数据(例如照片的 EXIF 信息)。")])]),e._v(" "),v("li",[v("p",[e._v("注意 OS X 系统是基于 BSD UNIX 的,许多命令(例如 "),v("code",[e._v("ps")]),e._v(","),v("code",[e._v("ls")]),e._v(","),v("code",[e._v("tail")]),e._v(","),v("code",[e._v("awk")]),e._v(","),v("code",[e._v("sed")]),e._v(')都和 Linux 中有微妙的不同( Linux 很大程度上受到了 System V-style Unix 和 GNU 工具影响)。你可以通过标题为 "BSD General Commands Manual" 的 man 页面发现这些不同。在有些情况下 GNU 版本的命令也可能被安装(例如 '),v("code",[e._v("gawk")]),e._v(" 和 "),v("code",[e._v("gsed")]),e._v(" 对应 GNU 中的 awk 和 sed )。如果要写跨平台的 Bash 脚本,避免使用这些命令(例如,考虑 Python 或者 "),v("code",[e._v("perl")]),e._v(" )或者经过仔细的测试。")])]),e._v(" "),v("li",[v("p",[e._v("用 "),v("code",[e._v("sw_vers")]),e._v(" 获取 OS X 的版本信息。")])])]),e._v(" "),v("h2",{attrs:{id:"仅限-windows-系统"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#仅限-windows-系统"}},[e._v("#")]),e._v(" 仅限 Windows 系统")]),e._v(" "),v("p",[e._v("以下是"),v("em",[e._v("仅限于")]),e._v(" Windows 系统的技巧。")]),e._v(" "),v("h3",{attrs:{id:"在-winodws-下获取-unix-工具"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#在-winodws-下获取-unix-工具"}},[e._v("#")]),e._v(" 在 Winodws 下获取 Unix 工具")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("可以安装 "),v("a",{attrs:{href:"https://cygwin.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Cygwin"),v("OutboundLink")],1),e._v(" 允许你在 Microsoft Windows 中体验 Unix shell 的威力。这样的话,本文中介绍的大多数内容都将适用。")])]),e._v(" "),v("li",[v("p",[e._v("在 Windows 10 上,你可以使用 "),v("a",{attrs:{href:"https://msdn.microsoft.com/commandline/wsl/about",target:"_blank",rel:"noopener noreferrer"}},[e._v("Bash on Ubuntu on Windows"),v("OutboundLink")],1),e._v(",它提供了一个熟悉的 Bash 环境,包含了不少 Unix 命令行工具。好处是它允许 Linux 上编写的程序在 Windows 上运行,而另一方面,Windows 上编写的程序却无法在 Bash 命令行中运行。")])]),e._v(" "),v("li",[v("p",[e._v("如果你在 Windows 上主要想用 GNU 开发者工具(例如 GCC),可以考虑 "),v("a",{attrs:{href:"http://www.mingw.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("MinGW"),v("OutboundLink")],1),e._v(" 以及它的 "),v("a",{attrs:{href:"http://www.mingw.org/wiki/msys",target:"_blank",rel:"noopener noreferrer"}},[e._v("MSYS"),v("OutboundLink")],1),e._v(" 包,这个包提供了例如 bash,gawk,make 和 grep 的工具。MSYS 并不包含所有可以与 Cygwin 媲美的特性。当制作 Unix 工具的原生 Windows 端口时 MinGW 将特别地有用。")])]),e._v(" "),v("li",[v("p",[e._v("另一个在 Windows 下实现接近 Unix 环境外观效果的选项是 "),v("a",{attrs:{href:"https://github.com/dthree/cash",target:"_blank",rel:"noopener noreferrer"}},[e._v("Cash"),v("OutboundLink")],1),e._v("。注意在此环境下只有很少的 Unix 命令和命令行可用。")])])]),e._v(" "),v("h3",{attrs:{id:"实用-windows-命令行工具"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#实用-windows-命令行工具"}},[e._v("#")]),e._v(" 实用 Windows 命令行工具")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("可以使用 "),v("code",[e._v("wmic")]),e._v(" 在命令行环境下给大部分 Windows 系统管理任务编写脚本以及执行这些任务。")])]),e._v(" "),v("li",[v("p",[e._v("Windows 实用的原生命令行网络工具包括 "),v("code",[e._v("ping")]),e._v(","),v("code",[e._v("ipconfig")]),e._v(","),v("code",[e._v("tracert")]),e._v(",和 "),v("code",[e._v("netstat")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("可以使用 "),v("code",[e._v("Rundll32")]),e._v(" 命令来实现"),v("a",{attrs:{href:"http://www.thewindowsclub.com/rundll32-shortcut-commands-windows",target:"_blank",rel:"noopener noreferrer"}},[e._v("许多有用的 Windows 任务"),v("OutboundLink")],1),e._v(" 。")])])]),e._v(" "),v("h3",{attrs:{id:"cygwin-技巧"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#cygwin-技巧"}},[e._v("#")]),e._v(" Cygwin 技巧")]),e._v(" "),v("ul",[v("li",[v("p",[e._v("通过 Cygwin 的包管理器来安装额外的 Unix 程序。")])]),e._v(" "),v("li",[v("p",[e._v("使用 "),v("code",[e._v("mintty")]),e._v(" 作为你的命令行窗口。")])]),e._v(" "),v("li",[v("p",[e._v("要访问 Windows 剪贴板,可以通过 "),v("code",[e._v("/dev/clipboard")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("运行 "),v("code",[e._v("cygstart")]),e._v(" 以通过默认程序打开一个文件。")])]),e._v(" "),v("li",[v("p",[e._v("要访问 Windows 注册表,可以使用 "),v("code",[e._v("regtool")]),e._v("。")])]),e._v(" "),v("li",[v("p",[e._v("注意 Windows 驱动器路径 "),v("code",[e._v("C:\\")]),e._v(" 在 Cygwin 中用 "),v("code",[e._v("/cygdrive/c")]),e._v(" 代表,而 Cygwin 的 "),v("code",[e._v("/")]),e._v(" 代表 Windows 中的 "),v("code",[e._v("C:\\cygwin")]),e._v("。要转换 Cygwin 和 Windows 风格的路径可以用 "),v("code",[e._v("cygpath")]),e._v("。这在需要调用 Windows 程序的脚本里很有用。")])]),e._v(" "),v("li",[v("p",[e._v("学会使用 "),v("code",[e._v("wmic")]),e._v(",你就可以从命令行执行大多数 Windows 系统管理任务,并编成脚本。")])]),e._v(" "),v("li",[v("p",[e._v("要在 Windows 下获得 Unix 的界面和体验,另一个办法是使用 "),v("a",{attrs:{href:"https://github.com/dthree/cash",target:"_blank",rel:"noopener noreferrer"}},[e._v("Cash"),v("OutboundLink")],1),e._v("。需要注意的是,这个环境支持的 Unix 命令和命令行参数非常少。")])]),e._v(" "),v("li",[v("p",[e._v("要在 Windows 上获取 GNU 开发者工具(比如 GCC)的另一个办法是使用 "),v("a",{attrs:{href:"http://www.mingw.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("MinGW"),v("OutboundLink")],1),e._v(" 以及它的 "),v("a",{attrs:{href:"http://www.mingw.org/wiki/msys",target:"_blank",rel:"noopener noreferrer"}},[e._v("MSYS"),v("OutboundLink")],1),e._v(" 软件包,该软件包提供了 bash、gawk、make、grep 等工具。然而 MSYS 提供的功能没有 Cygwin 完善。MinGW 在创建 Unix 工具的 Windows 原生移植方面非常有用。")])])]),e._v(" "),v("h2",{attrs:{id:"更多资源"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#更多资源"}},[e._v("#")]),e._v(" 更多资源")]),e._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"https://github.com/alebcay/awesome-shell",target:"_blank",rel:"noopener noreferrer"}},[e._v("awesome-shell"),v("OutboundLink")],1),e._v(":一份精心组织的命令行工具及资源的列表。")]),e._v(" "),v("li",[v("a",{attrs:{href:"https://github.com/herrbischoff/awesome-osx-command-line",target:"_blank",rel:"noopener noreferrer"}},[e._v("awesome-osx-command-line"),v("OutboundLink")],1),e._v(":一份针对 OS X 命令行的更深入的指南。")]),e._v(" "),v("li",[v("a",{attrs:{href:"http://redsymbol.net/articles/unofficial-bash-strict-mode/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Strict mode"),v("OutboundLink")],1),e._v(":为了编写更好的脚本文件。")]),e._v(" "),v("li",[v("a",{attrs:{href:"https://github.com/koalaman/shellcheck",target:"_blank",rel:"noopener noreferrer"}},[e._v("shellcheck"),v("OutboundLink")],1),e._v(":一个静态 shell 脚本分析工具,本质上是 bash/sh/zsh 的 lint。")]),e._v(" "),v("li",[v("a",{attrs:{href:"http://www.dwheeler.com/essays/filenames-in-shell.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Filenames and Pathnames in Shell"),v("OutboundLink")],1),e._v(":有关如何在 shell 脚本里正确处理文件名的细枝末节。")]),e._v(" "),v("li",[v("a",{attrs:{href:"http://datascienceatthecommandline.com/#tools",target:"_blank",rel:"noopener noreferrer"}},[e._v("Data Science at the Command Line"),v("OutboundLink")],1),e._v(":用于数据科学的一些命令和工具,摘自同名书籍。")])]),e._v(" "),v("h2",{attrs:{id:"免责声明"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#免责声明"}},[e._v("#")]),e._v(" 免责声明")]),e._v(" "),v("p",[e._v("除去特别小的工作,你编写的代码应当方便他人阅读。能力往往伴随着责任,你 "),v("em",[e._v("有能力")]),e._v(" 在 Bash 中玩一些奇技淫巧并不意味着你应该去做!😉")]),e._v(" "),v("h2",{attrs:{id:"授权条款"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#授权条款"}},[e._v("#")]),e._v(" 授权条款")]),e._v(" "),v("p",[v("img",{attrs:{src:"http://creativecommons.org/licenses/by-sa/4.0/",alt:"img"}})]),e._v(" "),v("p",[e._v("本文使用授权协议 "),v("a",{attrs:{href:"http://creativecommons.org/licenses/by-sa/4.0/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Creative Commons Attribution-ShareAlike 4.0 International License"),v("OutboundLink")],1),e._v("。")])])}),[],!1,null,null,null);_.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/37.34430c74.js b/assets/js/37.34430c74.js new file mode 100644 index 0000000..230d9f6 --- /dev/null +++ b/assets/js/37.34430c74.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[37],{425:function(s,e,t){"use strict";t.r(e);var a=t(15),n=Object(a.a)({},(function(){var s=this,e=s.$createElement,t=s._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"expect-shell-脚本"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#expect-shell-脚本"}},[s._v("#")]),s._v(" expect shell 脚本")]),s._v(" "),t("h2",{attrs:{id:"expect-简介"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#expect-简介"}},[s._v("#")]),s._v(" expect 简介")]),s._v(" "),t("p",[t("code",[s._v("expect")]),s._v(" 是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。")]),s._v(" "),t("p",[s._v("在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用 "),t("code",[s._v("expect")]),s._v(",则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是 "),t("code",[s._v("expect")]),s._v(" 。")]),s._v(" "),t("p",[s._v("expect 自动交互流程:")]),s._v(" "),t("ol",[t("li",[s._v("spawn 启动指定进程")]),s._v(" "),t("li",[s._v("expect 获取指定关键字")]),s._v(" "),t("li",[s._v("send 向指定程序发送指定字符")]),s._v(" "),t("li",[s._v("执行完成退出")])]),s._v(" "),t("h2",{attrs:{id:"expect-安装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#expect-安装"}},[s._v("#")]),s._v(" expect 安装")]),s._v(" "),t("h3",{attrs:{id:"yum-安装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#yum-安装"}},[s._v("#")]),s._v(" yum 安装")]),s._v(" "),t("p",[s._v("执行命令:")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[s._v("yum -y "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("expect")]),s._v("\n")])])]),t("h3",{attrs:{id:"手动安装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#手动安装"}},[s._v("#")]),s._v(" 手动安装")]),s._v(" "),t("p",[s._v("expect 依赖 tcl,所以需要先安装 tcl:")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("wget")]),s._v(" https://nchc.dl.sourceforge.net/project/tcl/Tcl/8.6.9/tcl8.6.9-src.tar.gz\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("tar")]),s._v(" xf tcl8.6.9-src.tar.gz\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("cd")]),s._v(" tcl8.6.9/unix/\n./configure "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("&&")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("make")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("&&")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("make")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v("\n")])])]),t("p",[s._v("再安装 expect:")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[s._v("wget")]),s._v(" https://nchc.dl.sourceforge.net/project/expect/Expect/5.45.4/expect5.45.4.tar.gz\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("tar")]),s._v(" xf expect5.45.4.tar.gz\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("cd")]),s._v(" ./expect5.45.4\n./configure "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("&&")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("make")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("&&")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("make")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v("\n")])])]),t("h2",{attrs:{id:"expect-参数"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#expect-参数"}},[s._v("#")]),s._v(" expect 参数")]),s._v(" "),t("p",[s._v("启用选项:")]),s._v(" "),t("ul",[t("li",[t("code",[s._v("-c")]),s._v(" - 执行脚本前先执行的命令,可多次使用。")]),s._v(" "),t("li",[t("code",[s._v("-d")]),s._v(" - debug 模式,可以在运行时输出一些诊断信息,与在脚本开始处使用 "),t("code",[s._v("exp_internal 1")]),s._v(" 相似。")]),s._v(" "),t("li",[t("code",[s._v("-D")]),s._v(" - 启用交换调式器,可设一整数参数。")]),s._v(" "),t("li",[t("code",[s._v("-f")]),s._v(" - 从文件读取命令,仅用于使用 "),t("code",[s._v("#!")]),s._v(" 时。如果文件名为 "),t("code",[s._v("-")]),s._v(",则从 stdin 读取(使用 "),t("code",[s._v("./-")]),s._v(" 从文件名为-的文件读取)。")]),s._v(" "),t("li",[t("code",[s._v("-i")]),s._v(" - 交互式输入命令,使用 "),t("code",[s._v("exit")]),s._v(" 或 "),t("code",[s._v("EOF")]),s._v(" 退出输入状态。")]),s._v(" "),t("li",[t("code",[s._v("--")]),s._v(" - 标示选项结束(如果你需要传递与 "),t("code",[s._v("expect")]),s._v(" 选项相似的参数给脚本时),可放到 "),t("code",[s._v("#!")]),s._v(" 行: "),t("code",[s._v("#!/usr/bin/expect --")]),s._v(" 。")]),s._v(" "),t("li",[t("code",[s._v("-v")]),s._v(" - 显示 "),t("code",[s._v("expect")]),s._v(" 版本信息。")])]),s._v(" "),t("h2",{attrs:{id:"expect-命令"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#expect-命令"}},[s._v("#")]),s._v(" expect 命令")]),s._v(" "),t("ul",[t("li",[t("code",[s._v("spawn")]),s._v(" - 命令用来启动新的进程,"),t("code",[s._v("spawn")]),s._v("后的"),t("code",[s._v("send")]),s._v("和"),t("code",[s._v("expect")]),s._v("命令都是和使用"),t("code",[s._v("spawn")]),s._v("打开的进程进行交互。")]),s._v(" "),t("li",[t("code",[s._v("expect")]),s._v(" - 获取匹配信息,匹配成功则执行 "),t("code",[s._v("expect")]),s._v(" 后面的程序动作。\n"),t("ul",[t("li",[t("code",[s._v("exp_continue")]),s._v(" - 在 "),t("code",[s._v("expect")]),s._v(" 中多次匹配就需要用到。")])])]),s._v(" "),t("li",[t("code",[s._v("send")]),s._v(" - 命令接收一个字符串参数,并将该参数发送到进程。\n"),t("ul",[t("li",[t("code",[s._v("send exp_send")]),s._v(" - 用于发送指定的字符串信息。")])])]),s._v(" "),t("li",[t("code",[s._v("interact")]),s._v(" - 命令用的其实不是很多,一般情况下使用"),t("code",[s._v("spawn")]),s._v("、"),t("code",[s._v("send")]),s._v("和"),t("code",[s._v("expect")]),s._v("命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用"),t("code",[s._v("interact")]),s._v("命令的,"),t("code",[s._v("interact")]),s._v("命令主要用于退出自动化,进入人工交互。比如我们使用"),t("code",[s._v("spawn")]),s._v("、"),t("code",[s._v("send")]),s._v("和"),t("code",[s._v("expect")]),s._v("命令完成了 ftp 登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在 ftp 命令行状态,以便手动的执行后续命令,此时使用"),t("code",[s._v("interact")]),s._v("命令就可以很好的完成这个任务。")]),s._v(" "),t("li",[t("code",[s._v("send_user")]),s._v(" - 用来打印输出 相当于 shell 中的 echo")]),s._v(" "),t("li",[t("code",[s._v("set")]),s._v(" - 定义变量。\n"),t("ul",[t("li",[t("code",[s._v("set timeout")]),s._v(" - 设置超时时间。")])])]),s._v(" "),t("li",[t("code",[s._v("puts")]),s._v(" - 输出变量。")]),s._v(" "),t("li",[t("code",[s._v("exit")]),s._v(" - 退出 expect 脚本")]),s._v(" "),t("li",[t("code",[s._v("eof")]),s._v(" - expect 执行结束,退出。")])]),s._v(" "),t("h2",{attrs:{id:"示例场景"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#示例场景"}},[s._v("#")]),s._v(" 示例场景")]),s._v(" "),t("p",[s._v("远程登录")]),s._v(" "),t("p",[s._v("(1)ssh 登录远程主机执行命令,执行方法 "),t("code",[s._v("expect 1.sh")]),s._v(" 或者 "),t("code",[s._v("source 1.sh")])]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[t("span",{pre:!0,attrs:{class:"token shebang important"}},[s._v("#!/usr/bin/expect")]),s._v("\n\nspawn "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("ssh")]),s._v(" saneri@192.168.56.103 "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("df")]),s._v(" -Th\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("expect")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"*password"')]),s._v("\nsend "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"123456'),t("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v('"')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("expect")]),s._v(" eof\n")])])]),t("p",[s._v("(2)ssh 远程登录主机执行命令,在 shell 脚本中执行 expect 命令,执行方法 sh 2.sh、bash 2.sh 或./2.sh 都可以执行.")]),s._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('#!/bin/bash\n\npasswd=\'123456\'\n\n/usr/bin/expect <<-EOF\n\nset time 30\nspawn ssh saneri@192.168.56.103 df -Th\nexpect {\n"*yes/no" { send "yes\\r"; exp_continue }\n"*password:" { send "$passwd\\r" }\n}\nexpect eof\nEOF\n')])])]),t("p",[s._v("(3)expect 执行多条命令")]),s._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('#!/usr/bin/expect -f\n\nset timeout 10\n\nspawn sudo su - root\nexpect "*password*"\nsend "123456\\r"\nexpect "#*"\nsend "ls\\r"\nexpect "#*"\nsend "df -Th\\r"\nsend "exit\\r"\nexpect eof\n')])])]),t("p",[s._v("(4)创建 ssh key,将 id_rsa 和 id_rsa.pub 文件分发到各台主机上面。")]),s._v(" "),t("div",{staticClass:"language-shell extra-class"},[t("pre",{pre:!0,attrs:{class:"language-shell"}},[t("code",[t("span",{pre:!0,attrs:{class:"token shebang important"}},[s._v("#!/bin/bash")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 判断id_rsa密钥文件是否存在")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("if")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("!")]),s._v(" -f ~/.ssh/id_rsa "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("then")]),s._v("\n ssh-keygen -t rsa -P "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),s._v(" -f ~/.ssh/id_rsa\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("else")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('"id_rsa has created ..."')]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("fi")]),s._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#分发到各个节点,这里分发到host文件中的主机中.")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("while")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("read")]),s._v(" line\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("do")]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("user")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" $line "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("cut")]),s._v(" -d "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('" "')]),s._v(" -f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("2")]),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ip")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" $line "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("cut")]),s._v(" -d "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('" "')]),s._v(" -f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("1")]),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")])]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("passwd")]),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" $line "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("cut")]),s._v(" -d "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('" "')]),s._v(" -f "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3")]),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")])]),s._v("\n\n "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("expect")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<<")]),t("span",{pre:!0,attrs:{class:"token string"}},[s._v("EOF\n set timeout 10\n spawn ssh-copy-id "),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$user")]),s._v("@"),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$ip")]),s._v('\n expect {\n "yes/no" { send "yes'),t("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v('";exp_continue }\n "password" { send "'),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$passwd")]),t("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v('" }\n }\n expect "password" { send "'),t("span",{pre:!0,attrs:{class:"token variable"}},[s._v("$passwd")]),t("span",{pre:!0,attrs:{class:"token entity",title:"\\n"}},[s._v("\\n")]),s._v('" }\nEOF')]),s._v("\n "),t("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("done")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[s._v("<")]),s._v(" hosts\n")])])]),t("p",[s._v("(5)shell 调用 expect 执行多行命令.")]),s._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[s._v('#!/bin/bash\nip=$1\nuser=$2\npassword=$3\n\nexpect <3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return f(n,e,i);if(Array.isArray(e))return Object.assign(f(n,e[0],i),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(f(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},325:function(t,e,n){"use strict";var i=n(177),r=n(8),a=n(17),s=n(23),o=n(178),u=n(179);i("match",1,(function(t,e,n){return[function(e){var n=s(this),i=null==e?void 0:e[t];return void 0!==i?i.call(e,n):new RegExp(e)[t](String(n))},function(t){var i=n(e,t,this);if(i.done)return i.value;var s=r(t),l=String(this);if(!s.global)return u(s,l);var c=s.unicode;s.lastIndex=0;for(var h,p=[],f=0;null!==(h=u(s,l));){var d=String(h[0]);p[f]=d,""===d&&(s.lastIndex=o(l,a(s.lastIndex),c)),f++}return 0===f?null:p}]}))},327:function(t,e,n){"use strict";var i=n(177),r=n(174),a=n(8),s=n(23),o=n(106),u=n(178),l=n(17),c=n(179),h=n(77),p=n(176).UNSUPPORTED_Y,f=[].push,d=Math.min;i("split",2,(function(t,e,n){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var i=String(s(this)),a=void 0===n?4294967295:n>>>0;if(0===a)return[];if(void 0===t)return[i];if(!r(t))return e.call(i,t,a);for(var o,u,l,c=[],p=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),d=0,g=new RegExp(t.source,p+"g");(o=h.call(g,i))&&!((u=g.lastIndex)>d&&(c.push(i.slice(d,o.index)),o.length>1&&o.index=a));)g.lastIndex===o.index&&g.lastIndex++;return d===i.length?!l&&g.test("")||c.push(""):c.push(i.slice(d)),c.length>a?c.slice(0,a):c}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var r=s(this),a=null==e?void 0:e[t];return void 0!==a?a.call(e,r,n):i.call(String(r),e,n)},function(t,r){var s=n(i,t,this,r,i!==e);if(s.done)return s.value;var h=a(t),f=String(this),g=o(h,RegExp),v=h.unicode,m=(h.ignoreCase?"i":"")+(h.multiline?"m":"")+(h.unicode?"u":"")+(p?"g":"y"),b=new g(p?"^(?:"+h.source+")":h,m),k=void 0===r?4294967295:r>>>0;if(0===k)return[];if(0===f.length)return null===c(b,f)?[f]:[];for(var _=0,x=0,C=[];x-1)&&(e=e.replace(/y/g,""));var o=s(x?new m(t,e):m(t,e),i?this:b,$);C&&n&&(d(o).sticky=!0);return o},y=function(t){t in $||o($,t,{configurable:!0,get:function(){return m[t]},set:function(e){m[t]=e}})},L=u(m),w=0;L.length>w;)y(L[w++]);b.constructor=$,$.prototype=b,p(r,"RegExp",$)}g("RegExp")},331:function(t,e,n){"use strict";var i=n(18),r=n(8),a=n(4),s=n(175),o=RegExp.prototype,u=o.toString,l=a((function(){return"/a/b"!=u.call({source:"a",flags:"b"})})),c="toString"!=u.name;(l||c)&&i(RegExp.prototype,"toString",(function(){var t=r(this),e=String(t.source),n=t.flags;return"/"+e+"/"+String(void 0===n&&t instanceof RegExp&&!("flags"in o)?s.call(t):n)}),{unsafe:!0})},332:function(t,e,n){},333:function(t,e,n){},334:function(t,e,n){},335:function(t,e,n){},336:function(t,e,n){},337:function(t,e,n){},338:function(t,e){t.exports=function(t){return null==t}},339:function(t,e,n){},340:function(t,e,n){},341:function(t,e,n){},342:function(t,e,n){},343:function(t,e,n){},344:function(t,e,n){},352:function(t,e,n){"use strict";n.r(e);n(100);var i=n(322),r={name:"SidebarGroup",components:{DropdownTransition:n(353).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(352).default},methods:{isActive:i.e}},a=(n(372),n(15)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(373),n(74);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,p=c.sidebarDepth,f=Object(i.e)(a,h.path),d="auto"===h.type?f||h.children.some((function(t){return Object(i.e)(a,h.basePath+"#"+t.slug)})):f,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[r.frontmatter.sidebarDepth,p,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!i.d.test(h.path)?[g,u(t,Object(i.c)(h.headers),h.path,a,v)]:g}};n(374);function c(t,e){if("group"===e.type){var n=e.path&&Object(i.e)(t,e.path),r=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}));return n||r}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},p=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=p.exports},353:function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(364),n(15)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},354:function(t,e,n){"use strict";var i=n(2),r=n(355);i({target:"String",proto:!0,forced:n(356)("link")},{link:function(t){return r(this,"a","href",t)}})},355:function(t,e,n){var i=n(23),r=/"/g;t.exports=function(t,e,n,a){var s=String(i(t)),o="<"+e;return""!==n&&(o+=" "+n+'="'+String(a).replace(r,""")+'"'),o+">"+s+""}},356:function(t,e,n){var i=n(4);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},357:function(t,e,n){"use strict";n(328)},358:function(t,e,n){var i=n(2),r=n(359);i({global:!0,forced:parseInt!=r},{parseInt:r})},359:function(t,e,n){var i=n(3),r=n(181).trim,a=n(182),s=i.parseInt,o=/^[+-]?0[Xx]/,u=8!==s(a+"08")||22!==s(a+"0x16");t.exports=u?function(t,e){var n=r(String(t));return s(n,e>>>0||(o.test(n)?16:10))}:s},360:function(t,e,n){var i=n(4),r=n(182);t.exports=function(t){return i((function(){return!!r[t]()||"​…᠎"!="​…᠎"[t]()||r[t].name!==t}))}},361:function(t,e,n){"use strict";var i,r=n(2),a=n(25).f,s=n(17),o=n(107),u=n(23),l=n(108),c=n(24),h="".endsWith,p=Math.min,f=l("endsWith");r({target:"String",proto:!0,forced:!!(c||f||(i=a(String.prototype,"endsWith"),!i||i.writable))&&!f},{endsWith:function(t){var e=String(u(this));o(t);var n=arguments.length>1?arguments[1]:void 0,i=s(e.length),r=void 0===n?i:p(s(n),i),a=String(t);return h?h.call(e,a,r):e.slice(r-a.length,r)===a}})},362:function(t,e,n){"use strict";n(332)},363:function(t,e,n){"use strict";n(333)},364:function(t,e,n){"use strict";n(334)},365:function(t,e,n){"use strict";n(335)},366:function(t,e,n){"use strict";n(336)},367:function(t,e,n){"use strict";n(337)},368:function(t,e,n){"use strict";n(339)},369:function(t,e,n){var i=n(36),r=n(19),a=n(29);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},370:function(t,e,n){"use strict";n(340)},371:function(t,e,n){"use strict";n(341)},372:function(t,e,n){"use strict";n(342)},373:function(t,e,n){"use strict";var i=n(2),r=n(35).find,a=n(105),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),i({target:"Array",proto:!0,forced:s},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},374:function(t,e,n){"use strict";n(343)},375:function(t,e,n){"use strict";n(344)},393:function(t,e,n){"use strict";n.r(e);n(354),n(100),n(101);var i=n(322),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(15),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction(e)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(357),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):t._e()],1)}),[],!1,null,null,null).exports),l=(n(358),n(329),n(173),n(104),n(33),n(50),n(325),n(184),n(185),n(180),n(75),n(330),n(331),n(74),n(327),n(361),n(187)),c=n.n(l),h=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=c()(e,"title","");return c()(e,"frontmatter.tags")&&(i+=" ".concat(e.frontmatter.tags.join(" "))),n&&(i+=" ".concat(n)),p(t,i)},p=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},i=new RegExp("[^\0-]"),r=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(i.test(t))return r.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(r.map((function(t,e){return r.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},f={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===i&&this.isSearchable(s))if(h(t,s))r.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&h(t,s,u.title)&&r.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return r}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),g=(n(363),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),v=n(48),m=(n(186),n(353)),b=n(188),k=n.n(b),_={name:"DropdownLink",components:{NavLink:s,DropdownTransition:m.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return k()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},x=(n(365),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(_,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(v.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),G=Object(a.a)(W,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=G.exports}}]); \ No newline at end of file diff --git a/assets/js/40.3b7a219e.js b/assets/js/40.3b7a219e.js new file mode 100644 index 0000000..f495599 --- /dev/null +++ b/assets/js/40.3b7a219e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[40],{428:function(e,t,s){"use strict";s.r(t);var a=s(15),r=Object(a.a)({},(function(){var e=this,t=e.$createElement,s=e._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[s("h1",{attrs:{id:"防火墙-firewalld"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#防火墙-firewalld"}},[e._v("#")]),e._v(" 防火墙 - Firewalld")]),e._v(" "),s("h2",{attrs:{id:"一、firewalld-服务命令"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#一、firewalld-服务命令"}},[e._v("#")]),e._v(" 一、firewalld 服务命令")]),e._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[e._v("systemctl "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("enable")]),e._v(" firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 开启服务(开机自动启动服务)")]),e._v("\nsystemctl disable firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 关闭服务(开机不会自动启动服务)")]),e._v("\nsystemctl start firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 启动服务")]),e._v("\nsystemctl stop firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 停止服务")]),e._v("\nsystemctl restart firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 重启服务")]),e._v("\nsystemctl reload firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 重新载入配置")]),e._v("\nsystemctl status firewalld.service "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看服务状态")]),e._v("\n")])])]),s("h2",{attrs:{id:"二、firewall-cmd-命令"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二、firewall-cmd-命令"}},[e._v("#")]),e._v(" 二、firewall-cmd 命令")]),e._v(" "),s("p",[s("code",[e._v("firewall-cmd")]),e._v(" 命令用于配置防火墙。")]),e._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[e._v("firewall-cmd --version "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看版本")]),e._v("\nfirewall-cmd --help "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看帮助")]),e._v("\nfirewall-cmd --state "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 显示状态")]),e._v("\nfirewall-cmd --reload "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 更新防火墙规则")]),e._v("\nfirewall-cmd --get-active-zones "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看区域信息")]),e._v("\nfirewall-cmd --get-zone-of-interface"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("eth0 "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看指定接口所属区域")]),e._v("\nfirewall-cmd --panic-on "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 拒绝所有包")]),e._v("\nfirewall-cmd --panic-off "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 取消拒绝状态")]),e._v("\nfirewall-cmd --query-panic "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看是否拒绝")]),e._v("\n\nfirewall-cmd --zone"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("public --list-ports "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看所有打开的端口")]),e._v("\nfirewall-cmd --zone"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("public --query-port"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("80")]),e._v("/tcp "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 查看是否有开放的 80 TCP 端口")]),e._v("\nfirewall-cmd --zone"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("public --add-port"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("8080")]),e._v("/tcp --permanent "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 添加开放端口(--permanent永久生效,没有此参数重启后失效)")]),e._v("\nfirewall-cmd --zone"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("public --remove-port"),s("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[e._v("80")]),e._v("/tcp --permanent "),s("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# 永久删除开放的 80 TCP 端口")]),e._v("\n")])])]),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[e._v("#")]),e._v(" 参考资料")]),e._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://www.cnblogs.com/moxiaoan/p/5683743.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("CentOS7 使用 firewalld 打开关闭防火墙与端口"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/41.e727eee9.js b/assets/js/41.e727eee9.js new file mode 100644 index 0000000..648be66 --- /dev/null +++ b/assets/js/41.e727eee9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[41],{429:function(t,s,a){"use strict";a.r(s);var e=a(15),r=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"iptables-应用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#iptables-应用"}},[t._v("#")]),t._v(" Iptables 应用")]),t._v(" "),a("blockquote",[a("p",[a("em",[t._v("iptables")]),t._v(" 是一个配置 Linux 内核 "),a("a",{attrs:{href:"https://wiki.archlinux.org/index.php/Firewall",target:"_blank",rel:"noopener noreferrer"}},[t._v("防火墙"),a("OutboundLink")],1),t._v(" 的命令行工具,是 "),a("a",{attrs:{href:"https://en.wikipedia.org/wiki/Netfilter",target:"_blank",rel:"noopener noreferrer"}},[t._v("netfilter"),a("OutboundLink")],1),t._v(" 项目的一部分。 可以直接配置,也可以通过许多前端和图形界面配置。")]),t._v(" "),a("p",[t._v("iptables 也经常代指该内核级防火墙。iptables 用于 "),a("a",{attrs:{href:"https://en.wikipedia.org/wiki/Ipv4",target:"_blank",rel:"noopener noreferrer"}},[t._v("ipv4"),a("OutboundLink")],1),t._v(","),a("em",[t._v("ip6tables")]),t._v(" 用于 "),a("a",{attrs:{href:"https://en.wikipedia.org/wiki/Ipv6",target:"_blank",rel:"noopener noreferrer"}},[t._v("ipv6"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://wiki.archlinux.org/index.php/Nftables",target:"_blank",rel:"noopener noreferrer"}},[t._v("nftables"),a("OutboundLink")],1),t._v(" 已经包含在 "),a("a",{attrs:{href:"http://www.phoronix.com/scan.php?page=news_item&px=MTQ5MDU",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux kernel 3.13"),a("OutboundLink")],1),t._v(" 中,以后会取代 iptables 成为主要的 Linux 防火墙工具。")]),t._v(" "),a("p",[t._v("环境:CentOS7")])]),t._v(" "),a("h2",{attrs:{id:"_1-简介"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-简介"}},[t._v("#")]),t._v(" 1. 简介")]),t._v(" "),a("p",[a("strong",[t._v("iptables 可以检测、修改、转发、重定向和丢弃 IPv4 数据包")]),t._v("。")]),t._v(" "),a("p",[t._v("过滤 IPv4 数据包的代码已经内置于内核中,并且按照不同的目的被组织成 "),a("strong",[t._v("表")]),t._v(" 的集合。"),a("strong",[t._v("表")]),t._v(" 由一组预先定义的 "),a("strong",[t._v("链")]),t._v(" 组成,"),a("strong",[t._v("链")]),t._v("包含遍历顺序规则。每一条规则包含一个谓词的潜在匹配和相应的动作(称为 "),a("strong",[t._v("目标")]),t._v("),如果谓词为真,该动作会被执行。也就是说条件匹配。")]),t._v(" "),a("h2",{attrs:{id:"_2-安装-iptables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-安装-iptables"}},[t._v("#")]),t._v(" 2. 安装 iptables")]),t._v(" "),a("p",[t._v("(1)禁用 firewalld")]),t._v(" "),a("p",[t._v("CentOS 7 上默认安装了 firewalld 作为防火墙,使用 iptables 建议关闭并禁用 firewalld。")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("systemctl stop firewalld\nsystemctl disable firewalld\n")])])]),a("p",[t._v("(2)安装 iptables")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("yum install -y iptables-services\n")])])]),a("p",[t._v("(3)服务管理")]),t._v(" "),a("ul",[a("li",[t._v("查看服务状态:"),a("code",[t._v("systemctl status iptables")])]),t._v(" "),a("li",[t._v("启用服务:"),a("code",[t._v("systemctl enable iptables")])]),t._v(" "),a("li",[t._v("禁用服务:"),a("code",[t._v("systemctl disable iptables")])]),t._v(" "),a("li",[t._v("启动服务:"),a("code",[t._v("systemctl start iptables")])]),t._v(" "),a("li",[t._v("重启服务:"),a("code",[t._v("systemctl restart iptables")])]),t._v(" "),a("li",[t._v("关闭服务: "),a("code",[t._v("systemctl stop iptables")])])]),t._v(" "),a("h2",{attrs:{id:"_3-命令"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-命令"}},[t._v("#")]),t._v(" 3. 命令")]),t._v(" "),a("p",[t._v("基本语法:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("iptables(选项)(参数)\n")])])]),a("p",[t._v("基本选项说明:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",[t._v("参数")]),t._v(" "),a("th",[t._v("作用")])])]),t._v(" "),a("tbody",[a("tr",[a("td",[t._v("-P")]),t._v(" "),a("td",[t._v("设置默认策略:iptables -P INPUT (DROP")])]),t._v(" "),a("tr",[a("td",[t._v("-F")]),t._v(" "),a("td",[t._v("清空规则链")])]),t._v(" "),a("tr",[a("td",[t._v("-L")]),t._v(" "),a("td",[t._v("查看规则链")])]),t._v(" "),a("tr",[a("td",[t._v("-A")]),t._v(" "),a("td",[t._v("在规则链的末尾加入新规则")])]),t._v(" "),a("tr",[a("td",[t._v("-I")]),t._v(" "),a("td",[t._v("num 在规则链的头部加入新规则")])]),t._v(" "),a("tr",[a("td",[t._v("-D")]),t._v(" "),a("td",[t._v("num 删除某一条规则")])]),t._v(" "),a("tr",[a("td",[t._v("-s")]),t._v(" "),a("td",[t._v('匹配来源地址 IP/MASK,加叹号"!"表示除这个 IP 外。')])]),t._v(" "),a("tr",[a("td",[t._v("-d")]),t._v(" "),a("td",[t._v("匹配目标地址")])]),t._v(" "),a("tr",[a("td",[t._v("-i")]),t._v(" "),a("td",[t._v("网卡名称 匹配从这块网卡流入的数据")])]),t._v(" "),a("tr",[a("td",[t._v("-o")]),t._v(" "),a("td",[t._v("网卡名称 匹配从这块网卡流出的数据")])]),t._v(" "),a("tr",[a("td",[t._v("-p")]),t._v(" "),a("td",[t._v("匹配协议,如 tcp,udp,icmp")])]),t._v(" "),a("tr",[a("td",[t._v("--dport num")]),t._v(" "),a("td",[t._v("匹配目标端口号")])]),t._v(" "),a("tr",[a("td",[t._v("--sport num")]),t._v(" "),a("td",[t._v("匹配来源端口号")])])])]),t._v(" "),a("p",[t._v("顺序:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作\n")])])]),a("h2",{attrs:{id:"_4-iptables-示例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-iptables-示例"}},[t._v("#")]),t._v(" 4. iptables 示例")]),t._v(" "),a("h3",{attrs:{id:"_4-1-清空当前的所有规则和计数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-清空当前的所有规则和计数"}},[t._v("#")]),t._v(" 4.1. 清空当前的所有规则和计数")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -F "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清空所有的防火墙规则")]),t._v("\niptables -X "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除用户自定义的空链")]),t._v("\niptables -Z "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清空计数")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-2-配置允许-ssh-端口连接"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-2-配置允许-ssh-端口连接"}},[t._v("#")]),t._v(" 4.2. 配置允许 ssh 端口连接")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".1.0/24 -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v(" -j ACCEPT\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 22为你的ssh端口, -s 192.168.1.0/24表示允许这个网段的机器来连接,其它网段的ip地址是登陆不了你的机器的。 -j ACCEPT表示接受这样的请求")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-3-允许本地回环地址可以正常使用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-允许本地回环地址可以正常使用"}},[t._v("#")]),t._v(" 4.3. 允许本地回环地址可以正常使用")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -i lo -j ACCEPT\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#本地圆环地址就是那个127.0.0.1,是本机上使用的,它进与出都设置为允许")]),t._v("\niptables -A OUTPUT -o lo -j ACCEPT\n")])])]),a("h3",{attrs:{id:"_4-4-设置默认的规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-4-设置默认的规则"}},[t._v("#")]),t._v(" 4.4. 设置默认的规则")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -P INPUT DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 配置默认的不让进")]),t._v("\niptables -P FORWARD DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 默认的不允许转发")]),t._v("\niptables -P OUTPUT ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 默认的可以出去")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-5-配置白名单"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-5-配置白名单"}},[t._v("#")]),t._v(" 4.5. 配置白名单")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -p all -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".1.0/24 -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 允许机房内网机器可以访问")]),t._v("\niptables -A INPUT -p all -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".140.0/24 -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 允许机房内网机器可以访问")]),t._v("\niptables -A INPUT -p tcp -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("183.121")]),t._v(".3.7 --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3380")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 允许183.121.3.7访问本机的3380端口")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-6-开启相应的服务端口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-6-开启相应的服务端口"}},[t._v("#")]),t._v(" 4.6. 开启相应的服务端口")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 开启80端口,因为web对外都是这个端口")]),t._v("\niptables -A INPUT -p icmp --icmp-type "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 允许被ping")]),t._v("\niptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 已经建立的连接得让它进来")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-7-保存规则到配置文件中"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-7-保存规则到配置文件中"}},[t._v("#")]),t._v(" 4.7. 保存规则到配置文件中")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" /etc/sysconfig/iptables /etc/sysconfig/iptables.bak "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 任何改动之前先备份,请保持这一优秀的习惯")]),t._v("\niptables-save "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" /etc/sysconfig/iptables\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("cat")]),t._v(" /etc/sysconfig/iptables\n")])])]),a("h3",{attrs:{id:"_4-8-列出已设置的规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-8-列出已设置的规则"}},[t._v("#")]),t._v(" 4.8. 列出已设置的规则")]),t._v(" "),a("blockquote",[a("p",[t._v("iptables -L [-t 表名][链名]")])]),t._v(" "),a("ul",[a("li",[t._v("四个表名 "),a("code",[t._v("raw")]),t._v(","),a("code",[t._v("nat")]),t._v(","),a("code",[t._v("filter")]),t._v(","),a("code",[t._v("mangle")])]),t._v(" "),a("li",[t._v("五个规则链名 "),a("code",[t._v("INPUT")]),t._v("、"),a("code",[t._v("OUTPUT")]),t._v("、"),a("code",[t._v("FORWARD")]),t._v("、"),a("code",[t._v("PREROUTING")]),t._v("、"),a("code",[t._v("POSTROUTING")])]),t._v(" "),a("li",[t._v("filter 表包含"),a("code",[t._v("INPUT")]),t._v("、"),a("code",[t._v("OUTPUT")]),t._v("、"),a("code",[t._v("FORWARD")]),t._v("三个规则链")])]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -L -t nat "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出 nat 上面的所有规则")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# ^ -t 参数指定,必须是 raw, nat,filter,mangle 中的一个")]),t._v("\niptables -L -t nat --line-numbers "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 规则带编号")]),t._v("\niptables -L INPUT\n\niptables -L -nv "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看,这个列表看起来更详细")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-9-清除已有规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-9-清除已有规则"}},[t._v("#")]),t._v(" 4.9. 清除已有规则")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -F INPUT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清空指定链 INPUT 上面的所有规则")]),t._v("\niptables -X INPUT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 删除指定的链,这个链必须没有被其它任何规则引用,而且这条上必须没有任何规则。")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 如果没有指定链名,则会删除该表中所有非内置的链。")]),t._v("\niptables -Z INPUT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 把指定链,或者表中的所有链上的所有计数器清零。")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-10-删除已添加的规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-10-删除已添加的规则"}},[t._v("#")]),t._v(" 4.10. 删除已添加的规则")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 添加一条规则")]),t._v("\niptables -A INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".1.5 -j DROP\n")])])]),a("p",[t._v("将所有 iptables 以序号标记显示,执行:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -L -n --line-numbers\n")])])]),a("p",[t._v("比如要删除 INPUT 里序号为 8 的规则,执行:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -D INPUT "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-11-开放指定的端口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-11-开放指定的端口"}},[t._v("#")]),t._v(" 4.11. 开放指定的端口")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("127.0")]),t._v(".0.1 -d "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("127.0")]),t._v(".0.1 -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许本地回环接口(即运行本机访问本机)")]),t._v("\niptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许已建立的或相关连的通行")]),t._v("\niptables -A OUTPUT -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许所有本机向外的访问")]),t._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许访问22端口")]),t._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许访问80端口")]),t._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("21")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许ftp服务的21端口")]),t._v("\niptables -A INPUT -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v(" -j ACCEPT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#允许FTP服务的20端口")]),t._v("\niptables -A INPUT -j reject "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#禁止其他未允许的规则访问")]),t._v("\niptables -A FORWARD -j REJECT "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#禁止其他未允许的规则访问")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-12-屏蔽-ip"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-12-屏蔽-ip"}},[t._v("#")]),t._v(" 4.12. 屏蔽 IP")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -p tcp -m tcp -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".0.8 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 屏蔽恶意主机(比如,192.168.0.8")]),t._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("123.45")]),t._v(".6.7 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#屏蔽单个IP的命令")]),t._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("123.0")]),t._v(".0.0/8 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#封整个段即从123.0.0.1到123.255.255.254的命令")]),t._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("124.45")]),t._v(".0.0/16 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#封IP段即从123.45.0.1到123.45.255.254的命令")]),t._v("\niptables -I INPUT -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("123.45")]),t._v(".6.0/24 -j DROP "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#封IP段即从123.45.6.1到123.45.6.254的命令是")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-13-指定数据包出去的网络接口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-13-指定数据包出去的网络接口"}},[t._v("#")]),t._v(" 4.13. 指定数据包出去的网络接口")]),t._v(" "),a("p",[t._v("只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A FORWARD -o eth0\n")])])]),a("h3",{attrs:{id:"_4-14-查看已添加的规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-14-查看已添加的规则"}},[t._v("#")]),t._v(" 4.14. 查看已添加的规则")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -L -n -v\nChain INPUT "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("policy DROP "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("48106")]),t._v(" packets, 2690K bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("source")]),t._v(" destination\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5075")]),t._v(" 589K ACCEPT all -- lo * "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0\n 191K 90M ACCEPT tcp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 tcp dpt:22\n1499K 133M ACCEPT tcp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 tcp dpt:80\n4364K 6351M ACCEPT all -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 state RELATED,ESTABLISHED\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("6256")]),t._v(" 327K ACCEPT icmp -- * * "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0\n\nChain FORWARD "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("policy ACCEPT "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" packets, "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("source")]),t._v(" destination\n\nChain OUTPUT "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("policy ACCEPT 3382K packets, 1819M bytes"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n pkts bytes target prot opt "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("in")]),t._v(" out "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("source")]),t._v(" destination\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5075")]),t._v(" 589K ACCEPT all -- * lo "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0\n")])])]),a("h3",{attrs:{id:"_4-15-启动网络转发规则"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-15-启动网络转发规则"}},[t._v("#")]),t._v(" 4.15. 启动网络转发规则")]),t._v(" "),a("p",[t._v("公网"),a("code",[t._v("210.14.67.7")]),t._v("让内网"),a("code",[t._v("192.168.188.0/24")]),t._v("上网")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -t nat -A POSTROUTING -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".188.0/24 -j SNAT --to-source "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("210.14")]),t._v(".67.127\n")])])]),a("h3",{attrs:{id:"_4-16-端口映射"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-16-端口映射"}},[t._v("#")]),t._v(" 4.16. 端口映射")]),t._v(" "),a("p",[t._v("本机的 2222 端口映射到内网 虚拟机的 22 端口")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -t nat -A PREROUTING -d "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("210.14")]),t._v(".67.127 -p tcp --dport "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2222")]),t._v(" -j DNAT --to-dest "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".188.115:22\n")])])]),a("h3",{attrs:{id:"_4-17-字符串匹配"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-17-字符串匹配"}},[t._v("#")]),t._v(" 4.17. 字符串匹配")]),t._v(" "),a("p",[t._v("比如,我们要过滤所有 TCP 连接中的字符串"),a("code",[t._v("test")]),t._v(",一旦出现它我们就终止这个连接,我们可以这么做:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -p tcp -m string --algo kmp --string "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"test"')]),t._v(" -j REJECT --reject-with tcp-reset\niptables -L\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Chain INPUT (policy ACCEPT)")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# target prot opt source destination")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('# REJECT tcp -- anywhere anywhere STRING match "test" ALGO name kmp TO 65535 reject-with tcp-reset')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Chain FORWARD (policy ACCEPT)")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# target prot opt source destination")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Chain OUTPUT (policy ACCEPT)")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# target prot opt source destination")]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-18-阻止-windows-蠕虫的攻击"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-18-阻止-windows-蠕虫的攻击"}},[t._v("#")]),t._v(" 4.18. 阻止 Windows 蠕虫的攻击")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -I INPUT -j DROP -p tcp -s "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0.0")]),t._v(".0.0/0 -m string --algo kmp --string "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"cmd.exe"')]),t._v("\n")])])]),a("h3",{attrs:{id:"_4-19-防止-syn-洪水攻击"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-19-防止-syn-洪水攻击"}},[t._v("#")]),t._v(" 4.19. 防止 SYN 洪水攻击")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("iptables -A INPUT -p tcp --syn -m limit --limit "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("/second -j ACCEPT\n")])])]),a("h2",{attrs:{id:"_5-参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_5-参考资料"}},[t._v("#")]),t._v(" 5. 参考资料")]),t._v(" "),a("ul",[a("li",[t._v("https://wiki.archlinux.org/index.php/iptables_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)")]),t._v(" "),a("li",[t._v("https://wangchujiang.com/linux-command/c/iptables.html")])])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/42.0134c187.js b/assets/js/42.0134c187.js new file mode 100644 index 0000000..c94cb08 --- /dev/null +++ b/assets/js/42.0134c187.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{430:function(t,a,s){"use strict";s.r(a);var e=s(15),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"linux-典型运维应用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#linux-典型运维应用"}},[t._v("#")]),t._v(" Linux 典型运维应用")]),t._v(" "),s("blockquote",[s("p",[t._v("💡 如果没有特殊说明,本文的案例都是针对 Centos 发行版本。")])]),t._v(" "),s("h2",{attrs:{id:"网络操作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#网络操作"}},[t._v("#")]),t._v(" 网络操作")]),t._v(" "),s("h3",{attrs:{id:"无法访问外网域名"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#无法访问外网域名"}},[t._v("#")]),t._v(" 无法访问外网域名")]),t._v(" "),s("p",[t._v("(1)在 hosts 中添加本机实际 IP 和本机实际域名的映射")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("echo")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"192.168.0.1 hostname"')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" /etc/hosts\n")])])]),s("p",[t._v("如果不知道本机域名,使用 "),s("code",[t._v("hostname")]),t._v(" 命令查一下;如果不知道本机实际 IP,使用 "),s("code",[t._v("ifconfig")]),t._v(" 查一下。")]),t._v(" "),s("p",[t._v("(2)配置信赖的 DNS 服务器")]),t._v(" "),s("p",[t._v("执行 "),s("code",[t._v("vi /etc/resolv.conf")]),t._v(" ,添加以下内容:")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[t._v("nameserver "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("114.114")]),t._v(".114.114\nnameserver "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("8.8")]),t._v(".8.8\n")])])]),s("blockquote",[s("p",[t._v("114.114.114.114 是国内老牌 DNS")]),t._v(" "),s("p",[t._v("8.8.8.8 是 Google DNS")]),t._v(" "),s("p",[t._v("👉 参考:"),s("a",{attrs:{href:"https://www.zhihu.com/question/32229915",target:"_blank",rel:"noopener noreferrer"}},[t._v("公共 DNS 哪家强"),s("OutboundLink")],1)])]),t._v(" "),s("p",[t._v("(3)测试一下能否 ping 通 www.baidu.com")]),t._v(" "),s("h3",{attrs:{id:"配置网卡"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置网卡"}},[t._v("#")]),t._v(" 配置网卡")]),t._v(" "),s("p",[t._v("使用 root 权限编辑 "),s("code",[t._v("/etc/sysconfig/network-scripts/ifcfg-eno16777736X")]),t._v(" 文件")]),t._v(" "),s("p",[t._v("参考以下进行配置:")]),t._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("TYPE")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("Ethernet # 网络类型:Ethernet以太网")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("BOOTPROTO")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("none # 引导协议:自动获取、static静态、none不指定")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("DEFROUTE")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes # 启动默认路由")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV4_FAILURE_FATAL")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("no # 不启用IPV4错误检测功能")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6INIT")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes # 启用IPV6协议")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_AUTOCONF")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes # 自动配置IPV6地址")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_DEFROUTE")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes # 启用IPV6默认路由")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_FAILURE_FATAL")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("no # 不启用IPV6错误检测功能")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_PEERDNS")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_PEERROUTES")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPV6_PRIVACY")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v('"no"')]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("NAME")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("eno16777736 # 网卡设备的别名(需要和文件名同名)")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("UUID")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("90528772-9967-46da-b401-f82b64b4acbc # 网卡设备的UUID唯一标识号")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("DEVICE")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("eno16777736 # 网卡的设备名称")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("ONBOOT")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("yes # 开机自动激活网卡")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("IPADDR")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("192.168.1.199 # 网卡的固定IP地址")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("PREFIX")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("24 # 子网掩码")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("GATEWAY")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("192.168.1.1 # 默认网关IP地址")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("DNS1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[t._v("8.8.8.8 # DNS域名解析服务器的IP地址")]),t._v("\n")])])]),s("p",[t._v("修改完后,执行 "),s("code",[t._v("systemctl restart network.service")]),t._v(" 重启网卡服务。")]),t._v(" "),s("h2",{attrs:{id:"系统维护"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#系统维护"}},[t._v("#")]),t._v(" 系统维护")]),t._v(" "),s("h2",{attrs:{id:"自动化脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#自动化脚本"}},[t._v("#")]),t._v(" 自动化脚本")]),t._v(" "),s("h3",{attrs:{id:"linux-开机自启动脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#linux-开机自启动脚本"}},[t._v("#")]),t._v(" Linux 开机自启动脚本")]),t._v(" "),s("p",[t._v("(1)在 "),s("code",[t._v("/etc/rc.local")]),t._v(" 文件中添加命令")]),t._v(" "),s("p",[t._v("如果不想将脚本粘来粘去,或创建链接,可以在 "),s("code",[t._v("/etc/rc.local")]),t._v(" 文件中添加启动命令")]),t._v(" "),s("ol",[s("li",[t._v("先修改好脚本,使其所有模块都能在任意目录启动时正常执行;")]),t._v(" "),s("li",[t._v("再在 "),s("code",[t._v("/etc/rc.local")]),t._v(" 的末尾添加一行以绝对路径启动脚本的行;")])]),t._v(" "),s("p",[t._v("例:")]),t._v(" "),s("p",[t._v("执行 "),s("code",[t._v("vim /etc/rc.local")]),t._v(" 命令,输入以下内容:")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token shebang important"}},[t._v("#!/bin/sh")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# This script will be executed *after* all the other init scripts.")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# You can put your own initialization stuff in here if you don't")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# want to do the full Sys V style init stuff.")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("touch")]),t._v(" /var/lock/subsys/local\n/opt/pjt_test/test.pl\n")])])]),s("p",[t._v("(2)在 "),s("code",[t._v("/etc/rc.d/init.d")]),t._v(" 目录下添加自启动脚本")]),t._v(" "),s("p",[t._v("Linux 在 "),s("code",[t._v("/etc/rc.d/init.d")]),t._v(" 下有很多的文件,每个文件都是可以看到内容的,其实都是一些 shell 脚本或者可执行二进制文件。")]),t._v(" "),s("p",[t._v("Linux 开机的时候,会加载运行 "),s("code",[t._v("/etc/rc.d/init.d")]),t._v(" 目录下的程序,因此我们可以把想要自动运行的脚本放到这个目录下即可。系统服务的启动就是通过这种方式实现的。")]),t._v(" "),s("p",[t._v("(3)运行级别设置")]),t._v(" "),s("p",[t._v("简单的说,运行级就是操作系统当前正在运行的功能级别。")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[t._v("不同的运行级定义如下:\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 0 - 停机(千万不能把initdefault 设置为0 )")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 1 - 单用户模式   进入方法#init s = init 1")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 2 - 多用户,没有 NFS")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 3 - 完全多用户模式(标准的运行级)")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 4 - 没有用到")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 5 - X11 多用户图形模式(xwindow)")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 6 - 重新启动 (千万不要把initdefault 设置为6 )")]),t._v("\n")])])]),s("p",[t._v("这些级别在 "),s("code",[t._v("/etc/inittab")]),t._v(" 文件里指定,这个文件是 init 程序寻找的主要文件,最先运行的服务是放在/etc/rc.d 目录下的文件。")]),t._v(" "),s("p",[t._v("在 "),s("code",[t._v("/etc")]),t._v(" 目录下面有这么几个目录值得注意:rcS.d rc0.d rc1.d ... rc6.d (0,1... 6 代表启动级别 0 代表停止,1 代表单用户模式,2-5 代表多用户模式,6 代表重启) 它们的作用就相当于 redhat 下的 rc.d ,你可以把脚本放到 rcS.d,然后修改文件名,给它一个启动序号,如: S88mysql")]),t._v(" "),s("p",[t._v("不过,最好的办法是放到相应的启动级别下面。具体作法:")]),t._v(" "),s("p",[t._v("(1)先把脚本 mysql 放到 /etc/init.d 目录下")]),t._v(" "),s("p",[t._v("(2)查看当前系统的启动级别")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[t._v("$ runlevel\nN "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n")])])]),s("p",[t._v("(3)设定启动级别")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 98 为启动序号")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 2 是系统的运行级别,可自己调整,注意不要忘了结尾的句点")]),t._v("\n$ update-rc.d mysql start "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("98")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n")])])]),s("p",[t._v("现在我们到 /etc/rc2.d 下,就多了一个 S98mysql 这样的符号链接。")]),t._v(" "),s("p",[t._v("(4)重启系统,验证设置是否有效。")]),t._v(" "),s("p",[t._v("(5)移除符号链接")]),t._v(" "),s("p",[t._v("当你需要移除这个符号连接时,方法有三种:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("直接到 "),s("code",[t._v("/etc/rc2.d")]),t._v(" 下删掉相应的链接,当然不是最好的方法;")])]),t._v(" "),s("li",[s("p",[t._v("推荐做法:"),s("code",[t._v("update-rc.d -f s10 remove")])])]),t._v(" "),s("li",[s("p",[t._v("如果 update-rc.d 命令你不熟悉,还可以试试看 rcconf 这个命令,也很方便。")])])]),t._v(" "),s("blockquote",[s("p",[t._v("👉 参考:")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://blog.csdn.net/linuxshine/article/details/50717272",target:"_blank",rel:"noopener noreferrer"}},[t._v("linux 添加开机自启动脚本示例详解"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://www.cnblogs.com/ssooking/p/6094740.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("linux 设置开机自启动"),s("OutboundLink")],1)])])]),t._v(" "),s("h3",{attrs:{id:"定时执行脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#定时执行脚本"}},[t._v("#")]),t._v(" 定时执行脚本")]),t._v(" "),s("h2",{attrs:{id:"配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置"}},[t._v("#")]),t._v(" 配置")]),t._v(" "),s("h3",{attrs:{id:"设置-linux-启动模式"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#设置-linux-启动模式"}},[t._v("#")]),t._v(" 设置 Linux 启动模式")]),t._v(" "),s("ol",[s("li",[t._v("停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)")]),t._v(" "),s("li",[t._v("单用户模式,就像 Win9X 下的安全模式")]),t._v(" "),s("li",[t._v("多用户,但是没有 NFS")]),t._v(" "),s("li",[t._v("完全多用户模式,准则的运行级")]),t._v(" "),s("li",[t._v("通常不用,在一些特殊情况下可以用它来做一些事情")]),t._v(" "),s("li",[t._v("X11,即进到 X-Window 系统")]),t._v(" "),s("li",[t._v("重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)")])]),t._v(" "),s("p",[t._v("设置方法:")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sed")]),t._v(" -i "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'s/id:5:initdefault:/id:3:initdefault:/'")]),t._v(" /etc/inittab\n")])])]),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://www.cnblogs.com/moxiaoan/p/5683743.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("CentOS7 使用 firewalld 打开关闭防火墙与端口"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://blog.csdn.net/z_yong_cool/article/details/79288397",target:"_blank",rel:"noopener noreferrer"}},[t._v("linux 定时执行脚本"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/43.175e982f.js b/assets/js/43.175e982f.js new file mode 100644 index 0000000..e223a9c --- /dev/null +++ b/assets/js/43.175e982f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{431:function(t,s,e){"use strict";e.r(s);var a=e(15),n=Object(a.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"时间服务器-ntp"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#时间服务器-ntp"}},[t._v("#")]),t._v(" 时间服务器 - NTP")]),t._v(" "),e("h2",{attrs:{id:"一、ntp-简介"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#一、ntp-简介"}},[t._v("#")]),t._v(" 一、NTP 简介")]),t._v(" "),e("p",[t._v("网络时间协议(英语:Network Time Protocol,缩写:NTP)是在数据网络潜伏时间可变的计算机系统之间通过分组交换进行时钟同步的一个网络协议,位于 OSI 模型的应用层。自 1985 年以来,NTP 是目前仍在使用的最古老的互联网协议之一。NTP 由特拉华大学的 David L. Mills(英语:David L. Mills)设计。")]),t._v(" "),e("p",[e("strong",[t._v("NTP 意图将所有参与计算机的协调世界时(UTC)时间同步到几毫秒的误差内")]),t._v("。")]),t._v(" "),e("p",[t._v("NTP 要点:")]),t._v(" "),e("ul",[e("li",[t._v("地球共有 24 个时区,而以格林威治时间 (GMT) 为标准时间;")]),t._v(" "),e("li",[t._v("中国本地时间为 GMT +8 小时;")]),t._v(" "),e("li",[t._v("最准确的时间为使用原子钟 (Atomic clock) 所计算的,例如 UTC (Coordinated Universal Time) 就是一例;")]),t._v(" "),e("li",[t._v("Linux 系统本来就有两种时间,一种是 Linux 以 "),e("code",[t._v("1970/01/01")]),t._v(" 开始计数的系统时间,一种则是 BIOS 记载的硬件时间;")]),t._v(" "),e("li",[t._v("Linux 可以透过网络校时,最常见的网络校时为使用 NTP 服务器,这个服务启动在 "),e("code",[t._v("udp port 123")]),t._v(";")]),t._v(" "),e("li",[t._v("时区档案主要放置于 "),e("code",[t._v("/usr/share/zoneinfo/")]),t._v(" 目录下,而本地时区则参考 "),e("code",[t._v("/etc/localtime")]),t._v(";")]),t._v(" "),e("li",[t._v("NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 "),e("code",[t._v("nptd")]),t._v(" 与 "),e("code",[t._v("ntpdate")]),t._v(" 两个指令不可同时使用;")]),t._v(" "),e("li",[t._v("NTP 服务器的联机状态可以使用 "),e("code",[t._v("ntpstat")]),t._v(" 及 "),e("code",[t._v("ntpq -p")]),t._v(" 来查询;")]),t._v(" "),e("li",[t._v("NTP 提供的客户端软件为 "),e("code",[t._v("ntpdate")]),t._v(" 这个指令;")]),t._v(" "),e("li",[t._v("在 Linux 下想要手动处理时间时,需以 "),e("code",[t._v("date")]),t._v(" 设定时间后,以 "),e("code",[t._v("hwclock -w")]),t._v(" 来写入 BIOS 所记录的时间。")]),t._v(" "),e("li",[t._v("NTP 服务器之间的时间误差不可超过 1000 秒,否则 NTP 服务会自动关闭。")])]),t._v(" "),e("blockquote",[e("p",[t._v("更多 NTP 详情可以参考:"),e("a",{attrs:{href:"http://cn.linux.vbird.org/linux_server/0440ntp.php",target:"_blank",rel:"noopener noreferrer"}},[t._v("鸟哥的 Linux 私房菜-- NTP 时间服务器"),e("OutboundLink")],1)])]),t._v(" "),e("h2",{attrs:{id:"二、ntpd-服务"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#二、ntpd-服务"}},[t._v("#")]),t._v(" 二、ntpd 服务")]),t._v(" "),e("blockquote",[e("p",[t._v("环境:CentOS")])]),t._v(" "),e("h3",{attrs:{id:"yum-安装"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#yum-安装"}},[t._v("#")]),t._v(" yum 安装")]),t._v(" "),e("p",[t._v("CentOS 安装 NTP 很简单,执行以下命令即可:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("yum -y "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" ntp\n")])])]),e("h3",{attrs:{id:"ntpd-配置"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#ntpd-配置"}},[t._v("#")]),t._v(" ntpd 配置")]),t._v(" "),e("p",[t._v("ntp 的配置文件路径为: "),e("code",[t._v("/etc/ntp.conf")]),t._v(" ,参考配置:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 1. 先处理权限方面的问题,包括放行上层服务器以及开放区网用户来源:")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# restrict default kod nomodify notrap nopeer noquery # 拒绝 IPv4 的用户")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# restrict -6 default kod nomodify notrap nopeer noquery # 拒绝 IPv6 的用户")]),t._v("\nrestrict default nomodify notrap nopeer noquery\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#restrict 192.168.100.0 mask 255.255.255.0 nomodify # 放行同局域网来源(根据网关和子网掩码决定)")]),t._v("\nrestrict "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("127.0")]),t._v(".0.1 "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 默认值,放行本机 IPv4 来源")]),t._v("\nrestrict ::1 "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 默认值,放行本机 IPv6 来源")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 2. 设定 NTP 主机来源")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 注释掉默认 NTP 来源")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# server 0.centos.pool.ntp.org iburst")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# server 1.centos.pool.ntp.org iburst")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# server 2.centos.pool.ntp.org iburst")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# server 3.centos.pool.ntp.org iburst")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置国内 NTP 来源")]),t._v("\nserver cn.pool.ntp.org prefer "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 以这个主机为优先")]),t._v("\nserver ntp1.aliyun.com\nserver ntp.sjtu.edu.cn\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 3. 预设时间差异分析档案与暂不用到的 keys 等,不需要更改它:")]),t._v("\ndriftfile /var/lib/ntp/drift\nkeys /etc/ntp/keys\nincludefile /etc/ntp/crypto/pw\n")])])]),e("blockquote",[e("p",[t._v("注意:如果更改配置,必须重启 NTP 服务("),e("code",[t._v("systemctl restart ntpd")]),t._v(")才能生效。")])]),t._v(" "),e("h3",{attrs:{id:"放开防火墙限制"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#放开防火墙限制"}},[t._v("#")]),t._v(" 放开防火墙限制")]),t._v(" "),e("p",[t._v("NTP 服务的端口是 "),e("code",[t._v("123")]),t._v(",使用的是 udp 协议,所以 NTP 服务器的防火墙必须对外开放 udp 123 这个端口。")]),t._v(" "),e("p",[t._v("如果防火墙使用 "),e("strong",[e("code",[t._v("iptables")])]),t._v(",执行以下命令:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("iptables -A INPUT -p UDP -i eth0 -s "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("192.168")]),t._v(".0.0/24 --dport "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),t._v(" -j ACCEPT\n")])])]),e("p",[t._v("如果防火墙使用 "),e("strong",[e("code",[t._v("firewalld")])]),t._v(",执行以下命令:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("firewall-cmd --zone"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("public --add-port"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),t._v("/udp --permanent\n")])])]),e("h3",{attrs:{id:"ntpd-服务命令"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#ntpd-服务命令"}},[t._v("#")]),t._v(" ntpd 服务命令")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("systemctl "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("enable")]),t._v(" ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 开启服务(开机自动启动服务)")]),t._v("\nsystemctl disable ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 关闭服务(开机不会自动启动服务)")]),t._v("\nsystemctl start ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 启动服务")]),t._v("\nsystemctl stop ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 停止服务")]),t._v("\nsystemctl restart ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重启服务")]),t._v("\nsystemctl reload ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重新载入配置")]),t._v("\nsystemctl status ntpd.service "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看服务状态")]),t._v("\n")])])]),e("h3",{attrs:{id:"查看-ntp-服务状态"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#查看-ntp-服务状态"}},[t._v("#")]),t._v(" 查看 ntp 服务状态")]),t._v(" "),e("h4",{attrs:{id:"验证-ntp-服务正常工作"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#验证-ntp-服务正常工作"}},[t._v("#")]),t._v(" 验证 NTP 服务正常工作")]),t._v(" "),e("p",[t._v("执行 "),e("code",[t._v("ntpstat")]),t._v(" 可以查看 ntp 服务器有无和上层 ntp 连通,,如果成功,可以看到类似以下的内容:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("$ ntpstat\nsynchronised to NTP server "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5.79")]),t._v(".108.34"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" at stratum "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("time")]),t._v(" correct to within "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1129")]),t._v(" ms\n polling server every "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v(" s\n")])])]),e("h4",{attrs:{id:"查看-ntp-服务器与上层-ntp-的状态"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#查看-ntp-服务器与上层-ntp-的状态"}},[t._v("#")]),t._v(" 查看 ntp 服务器与上层 ntp 的状态")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("ntpq -p\n remote refid st t when poll reach delay offset jitter\n"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v("\n*ntp1.ams1.nl.le "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("130.133")]),t._v(".1.10 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" u "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("36")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("367")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("230.801")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5.271")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2.791")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("120.25")]),t._v(".115.20 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10.137")]),t._v(".53.7 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" u "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("377")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("25.930")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("15.908")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3.168")]),t._v("\n time.cloudflare "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10.21")]),t._v(".8.251 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" u "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("31")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("64")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("367")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("251.109")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("16.976")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3.264")]),t._v("\n")])])]),e("h2",{attrs:{id:"三、ntpdate-命令"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#三、ntpdate-命令"}},[t._v("#")]),t._v(" 三、ntpdate 命令")]),t._v(" "),e("blockquote",[e("p",[t._v("注意:NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 "),e("code",[t._v("nptd")]),t._v(" 与 "),e("code",[t._v("ntpdate")]),t._v(" 两个指令不可同时使用。")])]),t._v(" "),e("h3",{attrs:{id:"手动执行时间同步"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#手动执行时间同步"}},[t._v("#")]),t._v(" 手动执行时间同步")]),t._v(" "),e("p",[e("code",[t._v("ntpdate")]),t._v(" 命令是 NTP 的客户端软件,它可以用于请求时间同步。")]),t._v(" "),e("p",[t._v("语法:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("/usr/sbin/ntpdate "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v("ntp_server"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v("\n")])])]),e("p",[e("code",[t._v("ntp_server")]),t._v(" 可以从 [国内 NTP 服务器](#国内 NTP 服务器) 中选择。")]),t._v(" "),e("p",[t._v("示例:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("$ ntpdate cn.pool.ntp.org\n"),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v(" Feb "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v(":47:12 ntpdate"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("30423")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(": step "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("time")]),t._v(" server "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("84.16")]),t._v(".73.33 offset -49.894774 sec\n")])])]),e("h3",{attrs:{id:"自动定时同步时间"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#自动定时同步时间"}},[t._v("#")]),t._v(" 自动定时同步时间")]),t._v(" "),e("p",[t._v("如果需要自动定时同步时间,可以利用 "),e("a",{attrs:{href:"#crontab"}},[t._v("Crontab")]),t._v(" 工具。本质就是用 crontab 定时执行一次手动时间同步命令 ntp。")]),t._v(" "),e("p",[t._v("示例:执行如下命令,就可以在每天凌晨 3 点同步系统时间:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("echo")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"0 3 * * * /usr/sbin/ntpdate cn.pool.ntp.org"')]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" /etc/crontab "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 修改 crond 服务配置")]),t._v("\nsystemctl restart crond "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重启 crond 服务以生效")]),t._v("\n")])])]),e("h2",{attrs:{id:"四、国内-ntp-服务器"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#四、国内-ntp-服务器"}},[t._v("#")]),t._v(" 四、国内 NTP 服务器")]),t._v(" "),e("p",[t._v("以下 NTP 服务器搜集自网络:")]),t._v(" "),e("div",{staticClass:"language-shell extra-class"},[e("pre",{pre:!0,attrs:{class:"language-shell"}},[e("code",[t._v("cn.pool.ntp.org "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 最常用的国内NTP服务器,参考:https://www.ntppool.org/zh/use.html")]),t._v("\ncn.ntp.org.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 中国")]),t._v("\nedu.ntp.org.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 中国教育网")]),t._v("\nntp1.aliyun.com "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 阿里云")]),t._v("\nntp2.aliyun.com "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 阿里云")]),t._v("\nntp.sjtu.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 上海交通大学")]),t._v("\ns1a.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 北京邮电大学")]),t._v("\ns1b.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清华大学")]),t._v("\ns1c.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 北京大学")]),t._v("\ns1d.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 东南大学")]),t._v("\ns1e.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清华大学")]),t._v("\ns2a.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清华大学")]),t._v("\ns2b.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 清华大学")]),t._v("\ns2c.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 北京邮电大学")]),t._v("\ns2d.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 西南地区网络中心")]),t._v("\ns2e.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 西北地区网络中心")]),t._v("\ns2f.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 东北地区网络中心")]),t._v("\ns2g.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 华东南地区网络中心")]),t._v("\ns2h.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 四川大学网络管理中心")]),t._v("\ns2j.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 大连理工大学网络中心")]),t._v("\ns2k.time.edu.cn "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# CERNET桂林主节点")]),t._v("\n")])])]),e("h2",{attrs:{id:"参考资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"http://cn.linux.vbird.org/linux_server/0440ntp.php",target:"_blank",rel:"noopener noreferrer"}},[t._v("鸟哥的 Linux 私房菜-- NTP 时间服务器"),e("OutboundLink")],1)]),t._v(" "),e("li",[e("a",{attrs:{href:"https://www.cnblogs.com/quchunhui/p/7658853.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 配置 ntp 时间服务器"),e("OutboundLink")],1)])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/44.72d90888.js b/assets/js/44.72d90888.js new file mode 100644 index 0000000..5e5319a --- /dev/null +++ b/assets/js/44.72d90888.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[44],{432:function(a,s,t){"use strict";t.r(s);var n=t(15),e=Object(n.a)({},(function(){var a=this,s=a.$createElement,t=a._self._c||s;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h1",{attrs:{id:"samba-应用"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#samba-应用"}},[a._v("#")]),a._v(" Samba 应用")]),a._v(" "),t("blockquote",[t("p",[a._v("samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件。")]),a._v(" "),t("p",[a._v("samba 提供了在不同计算机(即使操作系统不同)上共享服务的能力。")]),a._v(" "),t("p",[a._v("关键词:"),t("code",[a._v("samba")]),a._v(", "),t("code",[a._v("selinux")])])]),a._v(" "),t("h2",{attrs:{id:"_1-安装配置-samba"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-安装配置-samba"}},[a._v("#")]),a._v(" 1. 安装配置 samba")]),a._v(" "),t("p",[a._v("本文将以一个完整的示例来展示如何配置 samba 来实现 Linux 和 Windows 的文件共享。")]),a._v(" "),t("p",[a._v("目标:假设希望共享 Linux 服务器上的 /share/fs 目录。")]),a._v(" "),t("h3",{attrs:{id:"_1-1-查看是否已经安装-samba"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-查看是否已经安装-samba"}},[a._v("#")]),a._v(" 1.1. 查看是否已经安装 samba")]),a._v(" "),t("ul",[t("li",[a._v("CentOS:"),t("code",[a._v("rpm -qa | grep samba")])]),a._v(" "),t("li",[a._v("Ubuntu:"),t("code",[a._v("dpkg -l | grep samba")])])]),a._v(" "),t("h3",{attrs:{id:"_1-2-安装-samba-工具"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-安装-samba-工具"}},[a._v("#")]),a._v(" 1.2. 安装 samba 工具")]),a._v(" "),t("ul",[t("li",[a._v("CentOS:"),t("code",[a._v("yum install -y samba samba-client samba-common")])]),a._v(" "),t("li",[a._v("Ubuntu:"),t("code",[a._v("sudo apt-get install -y samba samba-client")])])]),a._v(" "),t("h3",{attrs:{id:"_1-3-配置-samba"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-3-配置-samba"}},[a._v("#")]),a._v(" 1.3. 配置 samba")]),a._v(" "),t("p",[a._v("samba 服务的配置文件是 "),t("code",[a._v("/etc/samba/smb.conf")]),a._v(",如果没有则 samba 无法启动。")]),a._v(" "),t("p",[a._v("执行以下命令,编辑配置文件:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[a._v("vim")]),a._v(" /etc/samba/smb.conf\n")])])]),t("p",[a._v("修改配置如下:")]),a._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[global]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" workgroup")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" SAMBA")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" security")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" user")]),a._v("\n\n passdb backend "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" tdbsam")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" printing")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n printcap name "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n load printers "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n cups options "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" raw")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[homes]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Home Directories")]),a._v("\n valid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" %S, %D%w%S")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n read only "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n inherit acls "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Yes")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[printers]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" All Printers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/tmp")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" printable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Yes")]),a._v("\n create mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0600")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[print$]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Printer Drivers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/lib/samba/drivers")]),a._v("\n write list "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" @printadmin root")]),a._v("\n force group "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" @printadmin")]),a._v("\n create mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0664")]),a._v("\n directory mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0775")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[fs]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" share folder")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /share/fs")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" writable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n read only "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\n guest ok "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n create mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0777")]),a._v("\n directory mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0777")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" public")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n valid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" root")]),a._v("\n")])])]),t("blockquote",[t("p",[a._v("说明:")]),a._v(" "),t("ul",[t("li",[a._v("我在这里添加了一个 "),t("strong",[a._v("[fs]")]),a._v(" 标签,这就是共享区域的配置。")]),a._v(" "),t("li",[a._v("这里设置 "),t("code",[a._v("path")]),a._v(" 属性为 "),t("code",[a._v("/share/fs")]),a._v(",意味着准备共享 "),t("code",[a._v("/share/fs")]),a._v(" 目录,需要根据实际需要设置路径。"),t("code",[a._v("/share/fs")]),a._v(" 目录的权限要设置为 "),t("strong",[a._v("777")]),a._v(":"),t("code",[a._v("chmod 777 /share/fs")]),a._v("。")]),a._v(" "),t("li",[t("code",[a._v("browseable")]),a._v("、"),t("code",[a._v("writable")]),a._v(" 等属性就比较容易理解了,即配置共享目录的访问权限。")]),a._v(" "),t("li",[t("code",[a._v("valid users")]),a._v(" 属性指定允许访问的用户,需要注意的是指定的用户必须是 Linux 机器上实际存在的用户。")])])]),a._v(" "),t("h3",{attrs:{id:"_1-4-创建-samba-用户"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-4-创建-samba-用户"}},[a._v("#")]),a._v(" 1.4. 创建 samba 用户")]),a._v(" "),t("p",[a._v("创建的 samba 用户必须是 Linux 机器上实际存在的用户。")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" smbpasswd -a root\nNew SMB password:\nRetype new SMB password:\nAdded user root.\n")])])]),t("p",[a._v("根据提示输入 samba 用户的密码。当 samba 服务成功安装、启动后,通过 Windows 系统访问机器共享目录时,就要输入这里配置的用户名、密码。")]),a._v(" "),t("ul",[t("li",[a._v("查看 samba 服务器中已拥有哪些用户 - "),t("code",[a._v("pdbedit -L")])]),a._v(" "),t("li",[a._v("删除 samba 服务中的某个用户 - "),t("code",[a._v("smbpasswd -x 用户名")])])]),a._v(" "),t("h3",{attrs:{id:"_1-5-启动-samba-服务"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-5-启动-samba-服务"}},[a._v("#")]),a._v(" 1.5. 启动 samba 服务")]),a._v(" "),t("p",[a._v("CentOS 6")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("service")]),a._v(" samba restart "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 重启 samba")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("service")]),a._v(" smb restart "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 重启 samba")]),a._v("\n")])])]),t("p",[a._v("CentOS 7")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" systemctl start smb.service "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 启动 samba")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" systemctl restart smb.service "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 重启 samba")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" systemctl "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("enable")]),a._v(" smb.service "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 设置开机自动启动")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" systemctl status smb.service "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 查询 samba 状态")]),a._v("\n")])])]),t("p",[a._v("Ubuntu 16.04.3")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("$ sudo service smbd restart\n")])])]),t("h3",{attrs:{id:"_1-6-为-samba-添加防火墙规则"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-6-为-samba-添加防火墙规则"}},[a._v("#")]),a._v(" 1.6. 为 samba 添加防火墙规则")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("$ sudo firewall-cmd --permanent --zone=public --add-service=samba\n$ sudo firewall-cmd --reload\n")])])]),t("h3",{attrs:{id:"_1-7-测试-samba-服务"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-7-测试-samba-服务"}},[a._v("#")]),a._v(" 1.7. 测试 samba 服务")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("$ smbclient //localhost/fs -U root\n")])])]),t("p",[a._v("输入 samba 用户的密码,如果成功,就会进入 "),t("code",[a._v("smb: \\>")]),a._v("。")]),a._v(" "),t("h3",{attrs:{id:"_1-8-访问-samba-服务共享的目录"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_1-8-访问-samba-服务共享的目录"}},[a._v("#")]),a._v(" 1.8. 访问 samba 服务共享的目录")]),a._v(" "),t("p",[a._v("Windows:")]),a._v(" "),t("p",[a._v("访问:"),t("code",[a._v("\\\\<你的ip>\\<你的共享路径>")]),a._v(" :")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20180920180928161334.png",alt:"img"}})]),a._v(" "),t("p",[a._v("Mac:")]),a._v(" "),t("p",[a._v("与 Windows 类似,直接在 Finder 中访问 "),t("code",[a._v("smb://<你的ip>/<你的共享路径>")]),a._v(" 即可。")]),a._v(" "),t("h2",{attrs:{id:"_2-配置详解"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-配置详解"}},[a._v("#")]),a._v(" 2. 配置详解")]),a._v(" "),t("h3",{attrs:{id:"_2-1-samba-默认配置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-samba-默认配置"}},[a._v("#")]),a._v(" 2.1. samba 默认配置")]),a._v(" "),t("p",[a._v("你可以从 "),t("a",{attrs:{href:"https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD",target:"_blank",rel:"noopener noreferrer"}},[a._v("这里"),t("OutboundLink")],1),a._v(" 获取到默认配置文件:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v('$ cp /etc/samba/smb.conf /etc/samba/smb.conf.bak\n$ wget "https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD" -O /etc/samba/smb.conf\n')])])]),t("p",[a._v("smb.conf 默认内容如下:")]),a._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[global]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" workgroup")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" SAMBA")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" security")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" user")]),a._v("\n\n passdb backend "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" tdbsam")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" printing")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n printcap name "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n load printers "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n cups options "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" raw")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[homes]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Home Directories")]),a._v("\n valid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" %S, %D%w%S")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n read only "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n inherit acls "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Yes")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[printers]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" All Printers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/tmp")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" printable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Yes")]),a._v("\n create mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0600")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" No")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[print$]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Printer Drivers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v(" path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/lib/samba/drivers")]),a._v("\n write list "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" root")]),a._v("\n create mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0664")]),a._v("\n directory mask "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0775")]),a._v("\n")])])]),t("h3",{attrs:{id:"_2-2-全局参数-global"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-全局参数-global"}},[a._v("#")]),a._v(" 2.2. 全局参数 [global]")]),a._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[global]")]),a._v("\n\nconfig file "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /usr/local/samba/lib/smb.conf.%m")]),a._v("\n说明:config file可以让你使用另一个配置文件来覆盖缺省的配置文件。如果文件 不存在,则该项无效。这个参数很有用,可以使得samba配置更灵活,可以让一台samba服务器模拟多台不同配置的服务器。比如,你想让PC1(主机名)这台电脑在访问Samba Server时使用它自己的配置文件,那么先在/etc/samba/host/下为PC1配置一个名为smb.conf.pc1的文件,然后在smb.conf中加入:config file"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("/etc/samba/host/smb.conf.%m。这样当PC1请求连接Samba Server时,smb.conf.%m就被替换成smb.conf.pc1。这样,对于PC1来说,它所使用的Samba服务就是由smb.conf.pc1定义的,而其他机器访问Samba Server则还是应用smb.conf。")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("workgroup")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" WORKGROUP")]),a._v("\n说明:设定 Samba Server 所要加入的工作组或者域。\n\nserver string "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Samba Server Version %v")]),a._v("\n说明:设定 Samba Server 的注释,可以是任何字符串,也可以不填。宏%v表示显示Samba的版本号。\n\nnetbios name "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" smbserver")]),a._v("\n说明:设置Samba Server的NetBIOS名称。如果不填,则默认会使用该服务器的DNS名称的第一部分。netbios name和workgroup名字不要设置成一样了。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("interfaces")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" lo eth0 192.168.12.2/24 192.168.13.2/24")]),a._v("\n说明:设置Samba Server监听哪些网卡,可以写网卡名,也可以写该网卡的IP地址。\n\nhosts allow "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 127.192.168.1 192.168.10.1")]),a._v("\n说明:表示允许连接到Samba Server的客户端,多个参数以空格隔开。可以用一个IP表示,也可以用一个网段表示。hosts deny 与hosts allow 刚好相反。\n例如:\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 表示容许来自172.17.2.*.*的主机连接,但排除172.17.2.50")]),a._v("\nhosts allow"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("172.17.2.EXCEPT172.17.2.50")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 表示容许来自172.17.2.0/255.255.0.0子网中的所有主机连接")]),a._v("\nhosts allow"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("172.17.2.0/255.255.0.0")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 表示容许来自M1和M2两台计算机连接")]),a._v("\nhosts allow"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("M1,M2")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 表示容许来自SC域的所有计算机连接")]),a._v("\nhosts allow"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("@SC")]),a._v("\nmax connections "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0")]),a._v("\n说明:max connections用来指定连接Samba Server的最大连接数目。如果超出连接数目,则新的连接请求将被拒绝。0表示不限制。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("deadtime")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 0")]),a._v("\n说明:deadtime用来设置断掉一个没有打开任何文件的连接的时间。单位是分钟,0代表Samba Server不自动切断任何连接。\n\ntime server "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:time server用来设置让nmdb成为windows客户端的时间服务器。\n\nlog file "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/log/samba/log.%m")]),a._v("\n说明:设置Samba Server日志文件的存储位置以及日志文件名称。在文件名后加个宏%m(主机名),表示对每台访问Samba Server的机器都单独记录一个日志文件。如果pc1、pc2访问过Samba Server,就会在/var/log/samba目录下留下log.pc1和log.pc2两个日志文件。\n\nmax log size "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 50")]),a._v("\n说明:设置Samba Server日志文件的最大容量,单位为kB,0代表不限制。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("security")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" user")]),a._v("\n说明:设置用户访问Samba Server的验证方式,一共有四种验证方式。\n1. share:用户访问Samba Server不需要提供用户名和口令, 安全性能较低。\n2. user:Samba Server共享目录只能被授权的用户访问,由Samba Server负责检查账号和密码的正确性。账号和密码要在本Samba Server中建立。\n3. server:依靠其他Windows NT/2000或Samba Server来验证用户的账号和密码,是一种代理验证。此种安全模式下,系统管理员可以把所有的Windows用户和口令集中到一个NT系统上,使用Windows NT进行Samba认证, 远程服务器可以自动认证全部用户和口令,如果认证失败,Samba将使用用户级安全模式作为替代的方式。\n4. domain:域安全级别,使用主域控制器(PDC)来完成认证。\n\npassdb backend "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" tdbsam")]),a._v("\n说明:passdb backend就是用户后台的意思。目前有三种后台:smbpasswd、tdbsam和ldapsam。sam应该是security account manager(安全账户管理)的简写。\n\nsmbpasswd:该方式是使用smb自己的工具smbpasswd来给系统用户(真实\n用户或者虚拟用户)设置一个Samba密码,客户端就用这个密码来访问Samba的资源。\n1. smbpasswd文件默认在/etc/samba目录下,不过有时候要手工建立该文件。\n2. tdbsam:该方式则是使用一个数据库文件来建立用户数据库。数据库文件叫passdb.tdb,默认在/etc/samba目录下。passdb.tdb用户数据库可以使用smbpasswd –a来建立Samba用户,不过要建立的Samba用户必须先是系统用户。我们也可以使用pdbedit命令来建立Samba账户。pdbedit命令的参数很多,我们列出几个主要的。\n pdbedit –a username:新建Samba账户。\n pdbedit –x username:删除Samba账户。\n pdbedit –L:列出Samba用户列表,读取passdb.tdb数据库文件。\n pdbedit –Lv:列出Samba用户列表的详细信息。\n pdbedit –c “[D]” –u username:暂停该Samba用户的账号。\n pdbedit –c “[]” –u username:恢复该Samba用户的账号。\n3. ldapsam:该方式则是基于LDAP的账户管理方式来验证用户。首先要建立LDAP服务,然后设置“passdb backend "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" ldapsam:ldap://LDAP Server”")]),a._v("\n\nencrypt passwords "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:是否将认证密码加密。因为现在windows操作系统都是使用加密密码,所以一般要开启此项。不过配置文件默认已开启。\n\nsmb passwd file "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /etc/samba/smbpasswd")]),a._v("\n说明:用来定义samba用户的密码文件。smbpasswd文件如果没有那就要手工新建。\n\nusername map "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /etc/samba/smbusers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("说明:用来定义用户名映射,比如可以将root换成administrator、admin等。不过要事先在smbusers文件中定义好。比如:root")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" administrator admin,这样就可以用administrator或admin这两个用户来代替root登陆Samba Server,更贴近windows用户的习惯。")]),a._v("\n\nguest account "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" nobody")]),a._v("\n说明:用来设置guest用户名。\n\nsocket options "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192")]),a._v("\n说明:用来设置服务器和客户端之间会话的Socket选项,可以优化传输速度。\n\ndomain master "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置Samba服务器是否要成为网域主浏览器,网域主浏览器可以管理跨子网域的浏览服务。\n\nlocal master "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:local master用来指定Samba Server是否试图成为本地网域主浏览器。如果设为no,则永远不会成为本地网域主浏览器。但是即使设置为yes,也不等于该Samba Server就能成为主浏览器,还需要参加选举。\n\npreferred master "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置Samba Server一开机就强迫进行主浏览器选举,可以提高Samba Server成为本地网域主浏览器的机会。如果该参数指定为yes时,最好把domain master也指定为yes。使用该参数时要注意:如果在本Samba Server所在的子网有其他的机器(不论是windows NT还是其他Samba Server)也指定为首要主浏览器时,那么这些机器将会因为争夺主浏览器而在网络上大发广播,影响网络性能。如果同一个区域内有多台Samba Server,将上面三个参数设定在一台即可。\n\nos level "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 200")]),a._v("\n说明:设置samba服务器的os level。该参数决定Samba Server是否有机会成为本地网域的主浏览器。os level从0到255,winNT的os level是32,win95/98的os level是1。Windows 2000的os level是64。如果设置为0,则意味着Samba Server将失去浏览选择。如果想让Samba Server成为PDC,那么将它的os level值设大些。\n\ndomain logons "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置Samba Server是否要做为本地域控制器。主域控制器和备份域控制器都需要开启此项。\n\nlogon . "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" %u.bat")]),a._v("\n说明:当使用者用windows客户端登陆,那么Samba将提供一个登陆档。如果设置成%u.bat,那么就要为每个用户提供一个登陆档。如果人比较多,那就比较麻烦。可以设置成一个具体的文件名,比如start.bat,那么用户登陆后都会去执行start.bat,而不用为每个用户设定一个登陆档了。这个文件要放置在[netlogon]的path设置的目录路径下。\n\nwins support "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置samba服务器是否提供wins服务。\n\nwins server "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" wins服务器IP地址")]),a._v("\n说明:设置Samba Server是否使用别的wins服务器提供wins服务。\n\nwins proxy "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置Samba Server是否开启wins代理服务。\n\ndns proxy "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置Samba Server是否开启dns代理服务。\n\nload printers "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:设置是否在启动Samba时就共享打印机。\n\nprintcap name "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n说明:设置共享打印机的配置文件。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("printing")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" cups")]),a._v("\n说明:设置Samba共享打印机的类型。现在支持的打印系统有:bsd, sysv, plp, lprng, aix, hpux, qnx\n")])])]),t("h3",{attrs:{id:"_2-3-共享参数-共享名"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-共享参数-共享名"}},[a._v("#")]),a._v(" 2.3. 共享参数 [共享名]")]),a._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[共享名]")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 任意字符串")]),a._v("\n说明:comment是对该共享的描述,可以是任意字符串。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 共享目录路径")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("说明:path用来指定共享目录的路径。可以用%u、%m这样的宏来代替路径里的unix用户和客户机的Netbios名,用宏表示主要用于[homes]共享域。例如:如果我们不打算用home段做为客户的共享,而是在/home/share/下为每个Linux用户以他的用户名建个目录,作为他的共享目录,这样path就可以写成:path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /home/share/%u; 。用户在连接到这共享时具体的路径会被他的用户名代替,要注意这个用户名路径一定要存在,否则,客户机在访问时会找不到网络路径。同样,如果我们不是以用户来划分目录,而是以客户机来划分目录,为网络上每台可以访问samba的机器都各自建个以它的netbios名的路径,作为不同机器的共享资源,就可以这样写:path = /home/share/%m 。")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:browseable用来指定该共享是否可以浏览。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("writable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:writable用来指定该共享路径是否可写。\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("available")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:available用来指定该共享资源是否可用。\n\nadmin users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 该共享的管理者")]),a._v("\n说明:admin users用来指定该共享的管理员(对该共享具有完全控制权限)。在samba 3.0中,如果用户验证方式设置成“security"),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("share”时,此项无效。")]),a._v("\n例如:admin users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v("bobyuan,jane(多个用户中间用逗号隔开)。")]),a._v("\n\nvalid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 允许访问该共享的用户")]),a._v("\n说明:valid users用来指定允许访问该共享资源的用户。\n例如:valid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" bobyuan,@bob,@tech(多个用户或者组中间用逗号隔开,如果要加入一个组就用“@+组名”表示。)")]),a._v("\n\ninvalid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 禁止访问该共享的用户")]),a._v("\n说明:invalid users用来指定不允许访问该共享资源的用户。\n例如:invalid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" root,@bob(多个用户或者组中间用逗号隔开。)")]),a._v("\n\nwrite list "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" 允许写入该共享的用户")]),a._v("\n说明:write list用来指定可以在该共享下写入文件的用户。\n例如:write list "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" bobyuan,@bob")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("public")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:public用来指定该共享是否允许guest账户访问。\n\nguest ok "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes/no")]),a._v("\n说明:意义同“public”。\n\n几个特殊共享:\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[homes]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Home Directories")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("writable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\nvalid users "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" %S")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("; valid users = MYDOMAIN\\%S")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[printers]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" All Printers")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/spool/samba")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\nguest ok "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("writable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("printable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[netlogon]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("comment")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" Network Logon Service")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/lib/samba/netlogon")]),a._v("\nguest ok "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("writable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\nshare modes "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\n\n"),t("span",{pre:!0,attrs:{class:"token selector"}},[a._v("[Profiles]")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("path")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" /var/lib/samba/profiles")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[a._v("browseable")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" no")]),a._v("\nguest ok "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" yes")]),a._v("\n")])])]),t("h2",{attrs:{id:"_3-常见问题"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-常见问题"}},[a._v("#")]),a._v(" 3. 常见问题")]),a._v(" "),t("h3",{attrs:{id:"_3-1-你可能没有权限访问网络资源"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-你可能没有权限访问网络资源"}},[a._v("#")]),a._v(" 3.1. 你可能没有权限访问网络资源")]),a._v(" "),t("p",[a._v("问题现象:")]),a._v(" "),t("ul",[t("li",[a._v("出现 "),t("strong",[a._v("NT_STATUS_ACCESS_DENIED")]),a._v(" 错误")]),a._v(" "),t("li",[a._v("Windows 下成功登陆 samba 后,点击共享目录仍然提示——你可能没有权限访问网络资源。")])]),a._v(" "),t("p",[a._v("解决步骤:")]),a._v(" "),t("ol",[t("li",[a._v("检查是否配置了防火墙规则")])]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 一种方法是强行关闭防火墙")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("service")]),a._v(" iptables stop\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 另一种方法是配置防火墙规则")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" firewall-cmd --permanent --zone"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("public --add-service"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("samba\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" firewall-cmd --reload\n")])])]),t("ol",{attrs:{start:"2"}},[t("li",[a._v("关闭 selinux")])]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 将 /etc/selinux/config 文件中的 SELINUX 设为 disabled")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("sed")]),a._v(" -i "),t("span",{pre:!0,attrs:{class:"token string"}},[a._v("'s/SELINUX=enforcing/SELINUX=disabled/'")]),a._v(" /etc/selinux/config\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# 重启生效")]),a._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("reboot")]),a._v("\n")])])]),t("h3",{attrs:{id:"_3-2-window-下对-samba-的清理操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-window-下对-samba-的清理操作"}},[a._v("#")]),a._v(" 3.2. window 下对 samba 的清理操作")]),a._v(" "),t("ol",[t("li",[a._v("windows 清除访问 samba 局域网密码缓存\n"),t("ul",[t("li",[a._v("在 dos 窗口中输入 "),t("code",[a._v("control userpasswords2")]),a._v(" 或者 "),t("code",[a._v("control keymgr.dll")]),a._v(",然后【高级】/【密码管理】,删掉保存的该机器密码。")])])]),a._v(" "),t("li",[a._v("windows 清除连接的 linux 的 samba 服务缓存\n"),t("ol",[t("li",[a._v("打开 win 的命令行。")]),a._v(" "),t("li",[a._v("输入 net use,就会打印出当前缓存的连接上列表。")]),a._v(" "),t("li",[a._v("根据列表,一个个删除连接: net use 远程连接名称 /del;或者一次性全部删除:"),t("code",[a._v("net use * /del")]),a._v("。")])])])]),a._v(" "),t("h2",{attrs:{id:"_4-参考资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#_4-参考资料"}},[a._v("#")]),a._v(" 4. 参考资料")]),a._v(" "),t("ul",[t("li",[a._v("http://blog.51cto.com/yuanbin/115761")]),a._v(" "),t("li",[a._v("https://www.jianshu.com/p/750be209a6f0")]),a._v(" "),t("li",[a._v("https://github.com/judasn/Linux-Tutorial/blob/master/markdown-file/Samba.md")]),a._v(" "),t("li",[a._v("https://blog.csdn.net/lan120576664/article/details/50396511")])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/45.d49955bd.js b/assets/js/45.d49955bd.js new file mode 100644 index 0000000..5562ed0 --- /dev/null +++ b/assets/js/45.d49955bd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[45],{433:function(t,s,e){"use strict";e.r(s);var a=e(15),n=Object(a.a)({},(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"systemd-应用"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#systemd-应用"}},[t._v("#")]),t._v(" Systemd 应用")]),t._v(" "),e("blockquote",[e("p",[t._v("搬运自:"),e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Systemd 入门教程:命令篇"),e("OutboundLink")],1),t._v("、"),e("RouterLink",{attrs:{to:"hhttp://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html"}},[t._v("Systemd 入门教程:实战篇")])],1)]),t._v(" "),e("p",[t._v("Systemd 是 Linux 系统工具,用来启动"),e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("守护进程"),e("OutboundLink")],1),t._v(",已成为大多数发行版的标准配置。")]),t._v(" "),e("p",[t._v("本文介绍它的基本用法,分为上下两篇。今天介绍它的主要命令,"),e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("下一篇"),e("OutboundLink")],1),t._v("介绍如何用于实战。")]),t._v(" "),e("h2",{attrs:{id:"_1-由来"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-由来"}},[t._v("#")]),t._v(" 1. 由来")]),t._v(" "),e("p",[t._v("历史上,"),e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2013/08/linux_boot_process.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Linux 的启动"),e("OutboundLink")],1),t._v("一直采用"),e("a",{attrs:{href:"https://en.wikipedia.org/wiki/Init",target:"_blank",rel:"noopener noreferrer"}},[e("code",[t._v("init")]),e("OutboundLink")],1),t._v("进程。")]),t._v(" "),e("p",[t._v("下面的命令用来启动服务。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" /etc/init.d/apache2 start\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 或者")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("service")]),t._v(" apache2 start\n")])])]),e("p",[t._v("这种方法有两个缺点。")]),t._v(" "),e("p",[t._v("一是启动时间长。"),e("code",[t._v("init")]),t._v("进程是串行启动,只有前一个进程启动完,才会启动下一个进程。")]),t._v(" "),e("p",[t._v("二是启动脚本复杂。"),e("code",[t._v("init")]),t._v("进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种\n情况,这往往使得脚本变得很长。")]),t._v(" "),e("h2",{attrs:{id:"_2-systemd-概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-systemd-概述"}},[t._v("#")]),t._v(" 2. Systemd 概述")]),t._v(" "),e("p",[t._v("Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套\n完整的解决方案。")]),t._v(" "),e("p",[t._v("根据 Linux 惯例,字母"),e("code",[t._v("d")]),t._v("是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就\n是它要守护整个系统。")]),t._v(" "),e("p",[t._v("使用了 Systemd,就不需要再用"),e("code",[t._v("init")]),t._v("了。Systemd 取代了"),e("code",[t._v("initd")]),t._v(",成为系统的第一个进\n程(PID 等于 1),其他进程都是它的子进程。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl --version\n")])])]),e("p",[t._v("上面的命令查看 Systemd 的版本。")]),t._v(" "),e("p",[t._v('Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。事实上,现在还有很\n多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反"keep\nsimple, keep stupid"\n的'),e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2009/06/unix_philosophy.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Unix 哲学"),e("OutboundLink")],1),t._v("。")]),t._v(" "),e("p",[e("img",{attrs:{src:"http://www.ruanyifeng.com/blogimg/asset/2016/bg2016030703.png",alt:"img"}})]),t._v(" "),e("p",[t._v("(上图为 Systemd 架构图)")]),t._v(" "),e("h2",{attrs:{id:"_3-系统管理"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-系统管理"}},[t._v("#")]),t._v(" 3. 系统管理")]),t._v(" "),e("p",[t._v("Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。")]),t._v(" "),e("h3",{attrs:{id:"_3-1-systemctl"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-systemctl"}},[t._v("#")]),t._v(" 3.1. systemctl")]),t._v(" "),e("p",[e("code",[t._v("systemctl")]),t._v("是 Systemd 的主命令,用于管理系统。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重启系统")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("reboot")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 关闭系统,切断电源")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl poweroff\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# CPU停止工作")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("halt")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 暂停系统")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("suspend")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 让系统进入冬眠状态")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl hibernate\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 让系统进入交互式休眠状态")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl hybrid-sleep\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 启动进入救援状态(单用户状态)")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl rescue\n")])])]),e("h3",{attrs:{id:"_3-2-systemd-analyze"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-systemd-analyze"}},[t._v("#")]),t._v(" 3.2. systemd-analyze")]),t._v(" "),e("p",[e("code",[t._v("systemd-analyze")]),t._v("命令用于查看启动耗时。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看启动耗时")]),t._v("\n$ systemd-analyze\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看每个服务的启动耗时")]),t._v("\n$ systemd-analyze blame\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示瀑布状的启动过程流")]),t._v("\n$ systemd-analyze critical-chain\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示指定服务的启动流")]),t._v("\n$ systemd-analyze critical-chain atd.service\n")])])]),e("h3",{attrs:{id:"_3-3-hostnamectl"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-hostnamectl"}},[t._v("#")]),t._v(" 3.3. hostnamectl")]),t._v(" "),e("p",[e("code",[t._v("hostnamectl")]),t._v("命令用于查看当前主机的信息。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示当前主机的信息")]),t._v("\n$ hostnamectl\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置主机名。")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" hostnamectl set-hostname rhel7\n")])])]),e("h3",{attrs:{id:"_3-4-localectl"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-localectl"}},[t._v("#")]),t._v(" 3.4. localectl")]),t._v(" "),e("p",[e("code",[t._v("localectl")]),t._v("命令用于查看本地化设置。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看本地化设置")]),t._v("\n$ localectl\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置本地化参数。")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" localectl set-locale "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e("span",{pre:!0,attrs:{class:"token environment constant"}},[t._v("LANG")])]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("en_GB.utf8\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" localectl set-keymap en_GB\n")])])]),e("h3",{attrs:{id:"_3-5-timedatectl"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-5-timedatectl"}},[t._v("#")]),t._v(" 3.5. timedatectl")]),t._v(" "),e("p",[e("code",[t._v("timedatectl")]),t._v("命令用于查看当前时区设置。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看当前时区设置")]),t._v("\n$ timedatectl\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示所有可用的时区")]),t._v("\n$ timedatectl list-timezones\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置当前时区")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" timedatectl set-timezone America/New_York\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" timedatectl set-time YYYY-MM-DD\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" timedatectl set-time HH:MM:SS\n")])])]),e("h3",{attrs:{id:"_3-6-loginctl"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-6-loginctl"}},[t._v("#")]),t._v(" 3.6. loginctl")]),t._v(" "),e("p",[e("code",[t._v("loginctl")]),t._v("命令用于查看当前登录的用户。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前session")]),t._v("\n$ loginctl list-sessions\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出当前登录用户")]),t._v("\n$ loginctl list-users\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出显示指定用户的信息")]),t._v("\n$ loginctl show-user ruanyf\n")])])]),e("h2",{attrs:{id:"_4-unit"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-unit"}},[t._v("#")]),t._v(" 4. Unit")]),t._v(" "),e("h3",{attrs:{id:"_4-1-含义"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-1-含义"}},[t._v("#")]),t._v(" 4.1. 含义")]),t._v(" "),e("p",[t._v("Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。")]),t._v(" "),e("p",[t._v("Unit 一共分成 12 种。")]),t._v(" "),e("ul",[e("li",[t._v("Service unit:系统服务")]),t._v(" "),e("li",[t._v("Target unit:多个 Unit 构成的一个组")]),t._v(" "),e("li",[t._v("Device Unit:硬件设备")]),t._v(" "),e("li",[t._v("Mount Unit:文件系统的挂载点")]),t._v(" "),e("li",[t._v("Automount Unit:自动挂载点")]),t._v(" "),e("li",[t._v("Path Unit:文件或路径")]),t._v(" "),e("li",[t._v("Scope Unit:不是由 Systemd 启动的外部进程")]),t._v(" "),e("li",[t._v("Slice Unit:进程组")]),t._v(" "),e("li",[t._v("Snapshot Unit:Systemd 快照,可以切回某个快照")]),t._v(" "),e("li",[t._v("Socket Unit:进程间通信的 socket")]),t._v(" "),e("li",[t._v("Swap Unit:swap 文件")]),t._v(" "),e("li",[t._v("Timer Unit:定时器")])]),t._v(" "),e("p",[e("code",[t._v("systemctl list-units")]),t._v("命令可以查看当前系统的所有 Unit 。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出正在运行的 Unit")]),t._v("\n$ systemctl list-units\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有Unit,包括没有找到配置文件的或者启动失败的")]),t._v("\n$ systemctl list-units --all\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有没有运行的 Unit")]),t._v("\n$ systemctl list-units --all --state"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("inactive\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有加载失败的 Unit")]),t._v("\n$ systemctl list-units --failed\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有正在运行的、类型为 service 的 Unit")]),t._v("\n$ systemctl list-units --type"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("service\n")])])]),e("h3",{attrs:{id:"_4-2-unit-的状态"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-2-unit-的状态"}},[t._v("#")]),t._v(" 4.2. Unit 的状态")]),t._v(" "),e("p",[e("code",[t._v("systemctl status")]),t._v("命令用于查看系统状态和单个 Unit 的状态。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示系统状态")]),t._v("\n$ systemctl status\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示单个 Unit 的状态")]),t._v("\n$ sysystemctl status bluetooth.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示远程主机的某个 Unit 的状态")]),t._v("\n$ systemctl -H root@rhel7.example.com status httpd.service\n")])])]),e("p",[t._v("除了"),e("code",[t._v("status")]),t._v("命令,"),e("code",[t._v("systemctl")]),t._v("还提供了三个查询状态的简单方法,主要供脚本内部的判\n断语句使用。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示某个 Unit 是否正在运行")]),t._v("\n$ systemctl is-active application.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示某个 Unit 是否处于启动失败状态")]),t._v("\n$ systemctl is-failed application.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示某个 Unit 服务是否建立了启动链接")]),t._v("\n$ systemctl is-enabled application.service\n")])])]),e("h3",{attrs:{id:"_4-3-unit-管理"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-3-unit-管理"}},[t._v("#")]),t._v(" 4.3. Unit 管理")]),t._v(" "),e("p",[t._v("对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 立即启动一个服务")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl start apache.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 立即停止一个服务")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl stop apache.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重启一个服务")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl restart apache.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 杀死一个服务的所有子进程")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("kill")]),t._v(" apache.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重新加载一个服务的配置文件")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl reload apache.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重载所有修改过的配置文件")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl daemon-reload\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示某个 Unit 的所有底层参数")]),t._v("\n$ systemctl show httpd.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示某个 Unit 的指定属性的值")]),t._v("\n$ systemctl show -p CPUShares httpd.service\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置某个 Unit 的指定属性")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl set-property httpd.service "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("CPUShares")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v("\n")])])]),e("h3",{attrs:{id:"_4-4-依赖关系"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-4-依赖关系"}},[t._v("#")]),t._v(" 4.4. 依赖关系")]),t._v(" "),e("p",[t._v("Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启\n动 B。")]),t._v(" "),e("p",[e("code",[t._v("systemctl list-dependencies")]),t._v("命令列出一个 Unit 的所有依赖。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl list-dependencies nginx.service\n")])])]),e("p",[t._v("上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如\n果要展开 Target,就需要使用"),e("code",[t._v("--all")]),t._v("参数。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl list-dependencies --all nginx.service\n")])])]),e("h2",{attrs:{id:"_5-unit-的配置文件"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_5-unit-的配置文件"}},[t._v("#")]),t._v(" 5. Unit 的配置文件")]),t._v(" "),e("h3",{attrs:{id:"_5-1-概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_5-1-概述"}},[t._v("#")]),t._v(" 5.1. 概述")]),t._v(" "),e("p",[t._v("每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。")]),t._v(" "),e("p",[t._v("Systemd 默认从目录"),e("code",[t._v("/etc/systemd/system/")]),t._v("读取配置文件。但是,里面存放的大部分文件\n都是符号链接,指向目录"),e("code",[t._v("/usr/lib/systemd/system/")]),t._v(",真正的配置文件存放在那个目录。")]),t._v(" "),e("p",[e("code",[t._v("systemctl enable")]),t._v("命令用于在上面两个目录之间,建立符号链接关系。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("enable")]),t._v(" clamd@scan.service\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 等同于")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("ln")]),t._v(" -s "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/usr/lib/systemd/system/clamd@scan.service'")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/etc/systemd/system/multi-user.target.wants/clamd@scan.service'")]),t._v("\n")])])]),e("p",[t._v("如果配置文件里面设置了开机启动,"),e("code",[t._v("systemctl enable")]),t._v("命令相当于激活开机启动。")]),t._v(" "),e("p",[t._v("与之对应的,"),e("code",[t._v("systemctl disable")]),t._v("命令用于在两个目录之间,撤销符号链接关系,相当于\n撤销开机启动。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl disable clamd@scan.service\n")])])]),e("p",[t._v("配置文件的后缀名,就是该 Unit 的种类,比如"),e("code",[t._v("sshd.socket")]),t._v("。如果省略,Systemd 默认\n后缀名为"),e("code",[t._v(".service")]),t._v(",所以"),e("code",[t._v("sshd")]),t._v("会被理解成"),e("code",[t._v("sshd.service")]),t._v("。")]),t._v(" "),e("h3",{attrs:{id:"_5-2-配置文件的状态"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_5-2-配置文件的状态"}},[t._v("#")]),t._v(" 5.2. 配置文件的状态")]),t._v(" "),e("p",[e("code",[t._v("systemctl list-unit-files")]),t._v("命令用于列出所有配置文件。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出所有配置文件")]),t._v("\n$ systemctl list-unit-files\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 列出指定类型的配置文件")]),t._v("\n$ systemctl list-unit-files --type"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("service\n")])])]),e("p",[t._v("这个命令会输出一个列表。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl list-unit-files\n\nUNIT FILE STATE\nchronyd.service enabled\nclamd@.service static\nclamd@scan.service disabled\n")])])]),e("p",[t._v("这个列表显示每个配置文件的状态,一共有四种。")]),t._v(" "),e("ul",[e("li",[t._v("enabled:已建立启动链接")]),t._v(" "),e("li",[t._v("disabled:没建立启动链接")]),t._v(" "),e("li",[t._v("static:该配置文件没有"),e("code",[t._v("[Install]")]),t._v("部分(无法执行),只能作为其他配置文件的依赖")]),t._v(" "),e("li",[t._v("masked:该配置文件被禁止建立启动链接")])]),t._v(" "),e("p",[t._v("注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到\n的"),e("code",[t._v("systemctl status")]),t._v("命令。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl status bluetooth.service\n")])])]),e("p",[t._v("一旦修改配置文件,就要让 SystemD 重新加载配置文件,然后重新启动,否则修改不会生\n效。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl daemon-reload\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl restart httpd.service\n")])])]),e("h3",{attrs:{id:"_5-3-配置文件的格式"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_5-3-配置文件的格式"}},[t._v("#")]),t._v(" 5.3. 配置文件的格式")]),t._v(" "),e("p",[t._v("配置文件就是普通的文本文件,可以用文本编辑器打开。")]),t._v(" "),e("p",[e("code",[t._v("systemctl cat")]),t._v("命令可以查看配置文件的内容。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("cat")]),t._v(" atd.service\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Unit"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Description")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("ATD daemon\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Service"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Type")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("forking\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("ExecStart")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("/usr/bin/atd\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Install"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("WantedBy")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("multi-user.target\n")])])]),e("p",[t._v("从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,是用方括号表示的区\n别名,比如"),e("code",[t._v("[Unit]")]),t._v("。注意,配置文件的区块名和字段名,都是大小写敏感的。")]),t._v(" "),e("p",[t._v("每个区块内部是一些等号连接的键值对。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Section"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Directive1")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("value\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Directive2")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("value\n\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v(".")]),t._v("\n")])])]),e("p",[t._v("注意,键值对的等号两侧不能有空格。")]),t._v(" "),e("h3",{attrs:{id:"_5-4-配置文件的区块"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_5-4-配置文件的区块"}},[t._v("#")]),t._v(" 5.4. 配置文件的区块")]),t._v(" "),e("p",[e("code",[t._v("[Unit]")]),t._v("区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他\nUnit 的关系。它的主要字段如下。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("Description")]),t._v(":简短描述")]),t._v(" "),e("li",[e("code",[t._v("Documentation")]),t._v(":文档地址")]),t._v(" "),e("li",[e("code",[t._v("Requires")]),t._v(":当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败")]),t._v(" "),e("li",[e("code",[t._v("Wants")]),t._v(":与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败")]),t._v(" "),e("li",[e("code",[t._v("BindsTo")]),t._v(":与"),e("code",[t._v("Requires")]),t._v("类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行")]),t._v(" "),e("li",[e("code",[t._v("Before")]),t._v(":如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动")]),t._v(" "),e("li",[e("code",[t._v("After")]),t._v(":如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动")]),t._v(" "),e("li",[e("code",[t._v("Conflicts")]),t._v(":这里指定的 Unit 不能与当前 Unit 同时运行")]),t._v(" "),e("li",[e("code",[t._v("Condition...")]),t._v(":当前 Unit 运行必须满足的条件,否则不会运行")]),t._v(" "),e("li",[e("code",[t._v("Assert...")]),t._v(":当前 Unit 运行必须满足的条件,否则会报启动失败")])]),t._v(" "),e("p",[e("code",[t._v("[Install]")]),t._v("通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它\n的主要字段如下。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("WantedBy")]),t._v(":它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放\n入"),e("code",[t._v("/etc/systemd/system")]),t._v("目录下面以 Target 名 + "),e("code",[t._v(".wants")]),t._v("后缀构成的子目录中")]),t._v(" "),e("li",[e("code",[t._v("RequiredBy")]),t._v(":它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放\n入"),e("code",[t._v("/etc/systemd/system")]),t._v("目录下面以 Target 名 + "),e("code",[t._v(".required")]),t._v("后缀构成的子目录中")]),t._v(" "),e("li",[e("code",[t._v("Alias")]),t._v(":当前 Unit 可用于启动的别名")]),t._v(" "),e("li",[e("code",[t._v("Also")]),t._v(":当前 Unit 激活(enable)时,会被同时激活的其他 Unit")])]),t._v(" "),e("p",[e("code",[t._v("[Service]")]),t._v("区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的\n主要字段如下。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("Type")]),t._v(":定义启动时的进程行为。它有以下几种值。")]),t._v(" "),e("li",[e("code",[t._v("Type=simple")]),t._v(":默认值,执行"),e("code",[t._v("ExecStart")]),t._v("指定的命令,启动主进程")]),t._v(" "),e("li",[e("code",[t._v("Type=forking")]),t._v(":以 fork 方式从父进程创建子进程,创建后父进程会立即退出")]),t._v(" "),e("li",[e("code",[t._v("Type=oneshot")]),t._v(":一次性进程,Systemd 会等当前服务退出,再继续往下执行")]),t._v(" "),e("li",[e("code",[t._v("Type=dbus")]),t._v(":当前服务通过 D-Bus 启动")]),t._v(" "),e("li",[e("code",[t._v("Type=notify")]),t._v(":当前服务启动完毕,会通知"),e("code",[t._v("Systemd")]),t._v(",再继续往下执行")]),t._v(" "),e("li",[e("code",[t._v("Type=idle")]),t._v(":若有其他任务执行完毕,当前服务才会运行")]),t._v(" "),e("li",[e("code",[t._v("ExecStart")]),t._v(":启动当前服务的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStartPre")]),t._v(":启动当前服务之前执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStartPost")]),t._v(":启动当前服务之后执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecReload")]),t._v(":重启当前服务时执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStop")]),t._v(":停止当前服务时执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStopPost")]),t._v(":停止当其服务之后执行的命令")]),t._v(" "),e("li",[e("code",[t._v("RestartSec")]),t._v(":自动重启当前服务间隔的秒数")]),t._v(" "),e("li",[e("code",[t._v("Restart")]),t._v(":定义何种情况 Systemd 会自动重启当前服务,可能的值包括"),e("code",[t._v("always")]),t._v("(总是\n重启)、"),e("code",[t._v("on-success")]),t._v("、"),e("code",[t._v("on-failure")]),t._v("、"),e("code",[t._v("on-abnormal")]),t._v("、"),e("code",[t._v("on-abort")]),t._v("、"),e("code",[t._v("on-watchdog")])]),t._v(" "),e("li",[e("code",[t._v("TimeoutSec")]),t._v(":定义 Systemd 停止当前服务之前等待的秒数")]),t._v(" "),e("li",[e("code",[t._v("Environment")]),t._v(":指定环境变量")])]),t._v(" "),e("p",[t._v("Unit 配置文件的完整字段清单,请参\n考"),e("a",{attrs:{href:"https://www.freedesktop.org/software/systemd/man/systemd.unit.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("官方文档"),e("OutboundLink")],1),t._v("。")]),t._v(" "),e("h2",{attrs:{id:"_6-target"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_6-target"}},[t._v("#")]),t._v(" 6. Target")]),t._v(" "),e("p",[t._v("启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要\n哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。")]),t._v(" "),e("p",[t._v('简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候\n,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于"状态点\n",启动某个 Target 就好比启动到某种状态。')]),t._v(" "),e("p",[t._v("传统的"),e("code",[t._v("init")]),t._v("启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是\n,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动\n。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看当前系统的所有 Target")]),t._v("\n$ systemctl list-unit-files --type"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("target\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看一个 Target 包含的所有 Unit")]),t._v("\n$ systemctl list-dependencies multi-user.target\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看启动时的默认 Target")]),t._v("\n$ systemctl get-default\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 设置启动时的默认 Target")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl set-default multi-user.target\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换 Target 时,默认不关闭前一个 Target 启动的进程,")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# systemctl isolate 命令改变这种行为,")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 关闭前一个 Target 里面所有不属于后一个 Target 的进程")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl isolate multi-user.target\n")])])]),e("p",[t._v("Target 与 传统 RunLevel 的对应关系如下。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("Traditional runlevel New target name Symbolically linked to"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel0.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" poweroff.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel1.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" rescue.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel2.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" multi-user.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel3.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" multi-user.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel4.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" multi-user.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel5.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" graphical.target\nRunlevel "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" runlevel6.target -"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" reboot.target\n")])])]),e("p",[t._v("它与"),e("code",[t._v("init")]),t._v("进程的主要差别如下。")]),t._v(" "),e("p",[e("strong",[t._v("(1)默认的 RunLevel")]),t._v("(在"),e("code",[t._v("/etc/inittab")]),t._v("文件设置)现在被默认的 Target 取代,\n位置是"),e("code",[t._v("/etc/systemd/system/default.target")]),t._v(",通常符号链接到"),e("code",[t._v("graphical.target")]),t._v("(\n图形界面)或者"),e("code",[t._v("multi-user.target")]),t._v("(多用户命令行)。")]),t._v(" "),e("p",[e("strong",[t._v("(2)启动脚本的位置")]),t._v(",以前是"),e("code",[t._v("/etc/init.d")]),t._v("目录,符号链接到不同的 RunLevel 目\n录 (比如"),e("code",[t._v("/etc/rc3.d")]),t._v("、"),e("code",[t._v("/etc/rc5.d")]),t._v("等),现在则存放\n在"),e("code",[t._v("/lib/systemd/system")]),t._v("和"),e("code",[t._v("/etc/systemd/system")]),t._v("目录。")]),t._v(" "),e("p",[e("strong",[t._v("(3)配置文件的位置")]),t._v(",以前"),e("code",[t._v("init")]),t._v("进程的配置文件是"),e("code",[t._v("/etc/inittab")]),t._v(",各种服务的\n配置文件存放在"),e("code",[t._v("/etc/sysconfig")]),t._v("目录。现在的配置文件主要存放在"),e("code",[t._v("/lib/systemd")]),t._v("目录\n,在"),e("code",[t._v("/etc/systemd")]),t._v("目录里面的修改可以覆盖原始设置。")]),t._v(" "),e("h2",{attrs:{id:"_7-日志管理"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_7-日志管理"}},[t._v("#")]),t._v(" 7. 日志管理")]),t._v(" "),e("p",[t._v("Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用"),e("code",[t._v("journalctl")]),t._v("一个命\n令,查看所有日志(内核日志和应用日志)。日志的配置文件\n是"),e("code",[t._v("/etc/systemd/journald.conf")]),t._v("。")]),t._v(" "),e("p",[e("code",[t._v("journalctl")]),t._v("功能强大,用法非常多。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看所有日志(默认情况下 ,只保存本次启动的日志)")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看内核日志(不显示应用日志)")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -k\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看系统本次启动的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -b\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -b -0\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看上一次启动的日志(需更改设置)")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -b -1\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看指定时间的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --since"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2012-10-30 18:17:16"')]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --since "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"20 min ago"')]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --since yesterday\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --since "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2015-01-10"')]),t._v(" --until "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"2015-01-11 03:00"')]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --since 09:00 --until "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"1 hour ago"')]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示尾部的最新10行日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -n\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示尾部指定行数的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -n "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 实时滚动显示最新日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -f\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看指定服务的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl /usr/lib/systemd/systemd\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看指定进程的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("_PID")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看某个路径的脚本的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl /usr/bin/bash\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看指定用户的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("_UID")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v(" --since today\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看某个 Unit 的日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -u nginx.service\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -u nginx.service --since today\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 实时滚动显示某个 Unit 的最新日志")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -u nginx.service -f\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 合并显示多个 Unit 的日志")]),t._v("\n$ journalctl -u nginx.service -u php-fpm.service --since today\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看指定优先级(及其以上级别)的日志,共有8级")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 0: emerg")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 1: alert")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 2: crit")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 3: err")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 4: warning")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 5: notice")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 6: info")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 7: debug")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -p err -b\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 日志默认分页输出,--no-pager 改为正常的标准输出")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --no-pager\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 以 JSON 格式(单行)输出")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -b -u nginx.service -o json\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 以 JSON 格式(多行)输出,可读性更好")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl -b -u nginx.serviceqq\n -o json-pretty\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 显示日志占据的硬盘空间")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --disk-usage\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 指定日志文件占据的最大空间")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --vacuum-size"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("1G\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 指定日志文件保存多久")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" journalctl --vacuum-time"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("1years\n")])])]),e("h2",{attrs:{id:"_8-实战"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-实战"}},[t._v("#")]),t._v(" 8. 实战")]),t._v(" "),e("h3",{attrs:{id:"_8-1-开机启动"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-1-开机启动"}},[t._v("#")]),t._v(" 8.1. 开机启动")]),t._v(" "),e("p",[t._v("对于那些支持 Systemd 的软件,安装的时候,会自动在"),e("code",[t._v("/usr/lib/systemd/system")]),t._v("目录添\n加一个配置文件。")]),t._v(" "),e("p",[t._v("如果你想让该软件开机启动,就执行下面的命令(以"),e("code",[t._v("httpd.service")]),t._v("为例)。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("enable")]),t._v(" httpd\n")])])]),e("p",[t._v("上面的命令相当于在"),e("code",[t._v("/etc/systemd/system")]),t._v("目录添加一个符号链接,指\n向"),e("code",[t._v("/usr/lib/systemd/system")]),t._v("里面的"),e("code",[t._v("httpd.service")]),t._v("文件。")]),t._v(" "),e("p",[t._v("这是因为开机时,"),e("code",[t._v("Systemd")]),t._v("只执行"),e("code",[t._v("/etc/systemd/system")]),t._v("目录里面的配置文件。这也意味\n着,如果把修改后的配置文件放在该目录,就可以达到覆盖原始配置的效果。")]),t._v(" "),e("h3",{attrs:{id:"_8-2-启动服务"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-2-启动服务"}},[t._v("#")]),t._v(" 8.2. 启动服务")]),t._v(" "),e("p",[t._v("设置开机启动以后,软件并不会立即启动,必须等到下一次开机。如果想现在就运行该软件\n,那么要执行"),e("code",[t._v("systemctl start")]),t._v("命令。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl start httpd\n")])])]),e("p",[t._v("执行上面的命令以后,有可能启动失败,因此要用"),e("code",[t._v("systemctl status")]),t._v("命令查看一下该服务\n的状态。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl status httpd\n\nhttpd.service - The Apache HTTP Server\nLoaded: loaded "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("/usr/lib/systemd/system/httpd.service"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" enabled"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nActive: active "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("running"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" since 金 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2014")]),t._v("-12-05 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(":18:22 JST"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" 7min ago\nMain PID: "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("4349")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("httpd"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\nStatus: "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Total requests: 1; Current requests/sec: 0; Current traffic: 0 B/sec"')]),t._v("\nCGroup: /system.slice/httpd.service\n ├─4349 /usr/sbin/httpd -DFOREGROUND\n ├─4350 /usr/sbin/httpd -DFOREGROUND\n ├─4351 /usr/sbin/httpd -DFOREGROUND\n ├─4352 /usr/sbin/httpd -DFOREGROUND\n ├─4353 /usr/sbin/httpd -DFOREGROUND\n └─4354 /usr/sbin/httpd -DFOREGROUND\n\n"),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v("月 05 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(":18:22 localhost.localdomain systemd"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(": Starting The Apache HTTP Server"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n"),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v("月 05 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(":18:22 localhost.localdomain systemd"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(": Started The Apache HTTP Server.\n"),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v("月 05 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("12")]),t._v(":22:40 localhost.localdomain systemd"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(": Started The Apache HTTP Server.\n")])])]),e("p",[t._v("上面的输出结果含义如下。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("Loaded")]),t._v("行:配置文件的位置,是否设为开机启动")]),t._v(" "),e("li",[e("code",[t._v("Active")]),t._v("行:表示正在运行")]),t._v(" "),e("li",[e("code",[t._v("Main PID")]),t._v("行:主进程 ID")]),t._v(" "),e("li",[e("code",[t._v("Status")]),t._v("行:由应用本身(这里是 httpd )提供的软件当前状态")]),t._v(" "),e("li",[e("code",[t._v("CGroup")]),t._v("块:应用的所有子进程")]),t._v(" "),e("li",[t._v("日志块:应用的日志")])]),t._v(" "),e("h3",{attrs:{id:"_8-3-停止服务"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-3-停止服务"}},[t._v("#")]),t._v(" 8.3. 停止服务")]),t._v(" "),e("p",[t._v("终止正在运行的服务,需要执行"),e("code",[t._v("systemctl stop")]),t._v("命令。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl stop httpd.service\n")])])]),e("p",[t._v('有时候,该命令可能没有响应,服务停不下来。这时候就不得不"杀进程"了,向正在运行的\n进程发出'),e("code",[t._v("kill")]),t._v("信号。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("kill")]),t._v(" httpd.service\n")])])]),e("p",[t._v("此外,重启服务要执行"),e("code",[t._v("systemctl restart")]),t._v("命令。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl restart httpd.service\n")])])]),e("h3",{attrs:{id:"_8-4-读懂配置文件"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-4-读懂配置文件"}},[t._v("#")]),t._v(" 8.4. 读懂配置文件")]),t._v(" "),e("p",[t._v("一个服务怎么启动,完全由它的配置文件决定。下面就来看,配置文件有些什么内容。")]),t._v(" "),e("p",[t._v("前面说过,配置文件主要放在"),e("code",[t._v("/usr/lib/systemd/system")]),t._v("目录,也可能\n在"),e("code",[t._v("/etc/systemd/system")]),t._v("目录。找到配置文件以后,使用文本编辑器打开即可。")]),t._v(" "),e("p",[e("code",[t._v("systemctl cat")]),t._v("命令可以用来查看配置文件,下面以"),e("code",[t._v("sshd.service")]),t._v("文件为例,它的作用\n是启动一个 SSH 服务器,供其他用户以 SSH 方式登录。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("$ systemctl cat sshd.service\n\n[Unit]\nDescription=OpenSSH server daemon\nDocumentation=man:sshd(8) man:sshd_config(5)\nAfter=network.target sshd-keygen.service\nWants=sshd-keygen.service\n\n[Service]\nEnvironmentFile=/etc/sysconfig/sshd\nExecStart=/usr/sbin/sshd -D $OPTIONS\nExecReload=/bin/kill -HUP $MAINPID\nType=simple\nKillMode=process\nRestart=on-failure\nRestartSec=42s\n\n[Install]\nWantedBy=multi-user.target\n")])])]),e("p",[t._v("可以看到,配置文件分成几个区块,每个区块包含若干条键值对。")]),t._v(" "),e("p",[t._v("下面依次解释每个区块的内容。")]),t._v(" "),e("h3",{attrs:{id:"_8-5-unit-区块-启动顺序与依赖关系。"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-5-unit-区块-启动顺序与依赖关系。"}},[t._v("#")]),t._v(" 8.5. [Unit] 区块:启动顺序与依赖关系。")]),t._v(" "),e("p",[e("code",[t._v("Unit")]),t._v("区块的"),e("code",[t._v("Description")]),t._v("字段给出当前服务的简单描述,"),e("code",[t._v("Documentation")]),t._v("字段给出文档\n位置。")]),t._v(" "),e("p",[t._v("接下来的设置是启动顺序和依赖关系,这个比较重要。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("After")]),t._v("字段:表示如果"),e("code",[t._v("network.target")]),t._v("或"),e("code",[t._v("sshd-keygen.service")]),t._v("需要启动,那\n么"),e("code",[t._v("sshd.service")]),t._v("应该在它们之后启动。")])]),t._v(" "),e("p",[t._v("相应地,还有一个"),e("code",[t._v("Before")]),t._v("字段,定义"),e("code",[t._v("sshd.service")]),t._v("应该在哪些服务之前启动。")]),t._v(" "),e("p",[t._v("注意,"),e("code",[t._v("After")]),t._v("和"),e("code",[t._v("Before")]),t._v("字段只涉及启动顺序,不涉及依赖关系。")]),t._v(" "),e("p",[t._v("举例来说,某 Web 应用需要 postgresql 数据库储存数据。在配置文件中,它只定义要在\npostgresql 之后启动,而没有定义依赖 postgresql 。上线后,由于某种原因\n,postgresql 需要重新启动,在停止服务期间,该 Web 应用就会无法建立数据库连接。")]),t._v(" "),e("p",[t._v("设置依赖关系,需要使用"),e("code",[t._v("Wants")]),t._v("字段和"),e("code",[t._v("Requires")]),t._v("字段。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("Wants")]),t._v("字段:表示"),e("code",[t._v("sshd.service")]),t._v("与"),e("code",[t._v("sshd-keygen.service")]),t._v('之间存在"弱依赖"关系,即\n如果"sshd-keygen.service"启动失败或停止运行,不影响'),e("code",[t._v("sshd.service")]),t._v("继续执行。")])]),t._v(" "),e("p",[e("code",[t._v("Requires")]),t._v('字段则表示"强依赖"关系,即如果该服务启动失败或异常退出,那\n么'),e("code",[t._v("sshd.service")]),t._v("也必须退出。")]),t._v(" "),e("p",[t._v("注意,"),e("code",[t._v("Wants")]),t._v("字段与"),e("code",[t._v("Requires")]),t._v("字段只涉及依赖关系,与启动顺序无关,默认情况下是同\n时启动的。")]),t._v(" "),e("h3",{attrs:{id:"_8-6-service-区块-启动行为"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-6-service-区块-启动行为"}},[t._v("#")]),t._v(" 8.6. [Service] 区块:启动行为")]),t._v(" "),e("p",[e("code",[t._v("Service")]),t._v("区块定义如何启动当前服务。")]),t._v(" "),e("h4",{attrs:{id:"_8-6-1-启动命令"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-6-1-启动命令"}},[t._v("#")]),t._v(" 8.6.1. 启动命令")]),t._v(" "),e("p",[t._v("许多软件都有自己的环境参数文件,该文件可以用"),e("code",[t._v("EnvironmentFile")]),t._v("字段读取。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("EnvironmentFile")]),t._v("字段:指定当前服务的环境参数文件。该文件内部的"),e("code",[t._v("key=value")]),t._v("键值\n对,可以用"),e("code",[t._v("$key")]),t._v("的形式,在当前配置文件中获取。")])]),t._v(" "),e("p",[t._v("上面的例子中,sshd 的环境参数文件是"),e("code",[t._v("/etc/sysconfig/sshd")]),t._v("。")]),t._v(" "),e("p",[t._v("配置文件里面最重要的字段是"),e("code",[t._v("ExecStart")]),t._v("。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("ExecStart")]),t._v("字段:定义启动进程时执行的命令。")])]),t._v(" "),e("p",[t._v("上面的例子中,启动"),e("code",[t._v("sshd")]),t._v(",执行的命令是"),e("code",[t._v("/usr/sbin/sshd -D $OPTIONS")]),t._v(",其中的变\n量"),e("code",[t._v("$OPTIONS")]),t._v("就来自"),e("code",[t._v("EnvironmentFile")]),t._v("字段指定的环境参数文件。")]),t._v(" "),e("p",[t._v("与之作用相似的,还有如下这些字段。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("ExecReload")]),t._v("字段:重启服务时执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStop")]),t._v("字段:停止服务时执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStartPre")]),t._v("字段:启动服务之前执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStartPost")]),t._v("字段:启动服务之后执行的命令")]),t._v(" "),e("li",[e("code",[t._v("ExecStopPost")]),t._v("字段:停止服务之后执行的命令")])]),t._v(" "),e("p",[t._v("请看下面的例子。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("[Service]\nExecStart=/bin/echo execstart1\nExecStart=\nExecStart=/bin/echo execstart2\nExecStartPost=/bin/echo post1\nExecStartPost=/bin/echo post2\n")])])]),e("p",[t._v("上面这个配置文件,第二行"),e("code",[t._v("ExecStart")]),t._v("设为空值,等于取消了第一行的设置,运行结果如\n下。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("execstart2\npost1\npost2\n")])])]),e("p",[t._v("所有的启动设置之前,都可以加上一个连词号("),e("code",[t._v("-")]),t._v('),表示"抑制错误",即发生错误的时\n候,不影响其他命令的执行。比如,'),e("code",[t._v("EnvironmentFile=-/etc/sysconfig/sshd")]),t._v("(注意等号\n后面的那个连词号),就表示即使"),e("code",[t._v("/etc/sysconfig/sshd")]),t._v("文件不存在,也不会抛出错误。")]),t._v(" "),e("h4",{attrs:{id:"_8-6-2-启动类型"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-6-2-启动类型"}},[t._v("#")]),t._v(" 8.6.2. 启动类型")]),t._v(" "),e("p",[e("code",[t._v("Type")]),t._v("字段定义启动类型。它可以设置的值如下。")]),t._v(" "),e("ul",[e("li",[t._v("simple(默认值):"),e("code",[t._v("ExecStart")]),t._v("字段启动的进程为主进程")]),t._v(" "),e("li",[t._v("forking:"),e("code",[t._v("ExecStart")]),t._v("字段将以"),e("code",[t._v("fork()")]),t._v("方式启动,此时父进程将会退出,子进程将成\n为主进程")]),t._v(" "),e("li",[t._v("oneshot:类似于"),e("code",[t._v("simple")]),t._v(",但只执行一次,Systemd 会等它执行完,才启动其他服务")]),t._v(" "),e("li",[t._v("dbus:类似于"),e("code",[t._v("simple")]),t._v(",但会等待 D-Bus 信号后启动")]),t._v(" "),e("li",[t._v("notify:类似于"),e("code",[t._v("simple")]),t._v(",启动结束后会发出通知信号,然后 Systemd 再启动其他服\n务")]),t._v(" "),e("li",[t._v("idle:类似于"),e("code",[t._v("simple")]),t._v(",但是要等到其他任务都执行完,才会启动该服务。一种使用场\n合是为让该服务的输出,不与其他服务的输出相混合")])]),t._v(" "),e("p",[t._v("下面是一个"),e("code",[t._v("oneshot")]),t._v("的例子,笔记本电脑启动时,要把触摸板关掉,配置文件可以这样写\n。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("[Unit]\nDescription=Switch-off Touchpad\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/touchpad-off\n\n[Install]\nWantedBy=multi-user.target\n")])])]),e("p",[t._v("上面的配置文件,启动类型设为"),e("code",[t._v("oneshot")]),t._v(",就表明这个服务只要运行一次就够了,不需要\n长期运行。")]),t._v(" "),e("p",[t._v("如果关闭以后,将来某个时候还想打开,配置文件修改如下。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("[Unit]\nDescription=Switch-off Touchpad\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/touchpad-off start\nExecStop=/usr/bin/touchpad-off stop\nRemainAfterExit=yes\n\n[Install]\nWantedBy=multi-user.target\n")])])]),e("p",[t._v("上面配置文件中,"),e("code",[t._v("RemainAfterExit")]),t._v("字段设为"),e("code",[t._v("yes")]),t._v(",表示进程退出以后,服务仍然保持执\n行。这样的话,一旦使用"),e("code",[t._v("systemctl stop")]),t._v("命令停止服务,"),e("code",[t._v("ExecStop")]),t._v("指定的命令就会执行\n,从而重新开启触摸板。")]),t._v(" "),e("h4",{attrs:{id:"_8-6-3-重启行为"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-6-3-重启行为"}},[t._v("#")]),t._v(" 8.6.3. 重启行为")]),t._v(" "),e("p",[e("code",[t._v("Service")]),t._v("区块有一些字段,定义了重启行为。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("KillMode")]),t._v("字段:定义 Systemd 如何停止 sshd 服务。")])]),t._v(" "),e("p",[t._v("上面这个例子中,将"),e("code",[t._v("KillMode")]),t._v("设为"),e("code",[t._v("process")]),t._v(",表示只停止主进程,不停止任何 sshd 子\n进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对 sshd 很重\n要,否则你停止服务的时候,会连自己打开的 SSH session 一起杀掉。")]),t._v(" "),e("p",[e("code",[t._v("KillMode")]),t._v("字段可以设置的值如下。")]),t._v(" "),e("ul",[e("li",[t._v("control-group(默认值):当前控制组里面的所有子进程,都会被杀掉")]),t._v(" "),e("li",[t._v("process:只杀主进程")]),t._v(" "),e("li",[t._v("mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号")]),t._v(" "),e("li",[t._v("none:没有进程会被杀掉,只是执行服务的 stop 命令。")])]),t._v(" "),e("p",[t._v("接下来是"),e("code",[t._v("Restart")]),t._v("字段。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("Restart")]),t._v("字段:定义了 sshd 退出后,Systemd 的重启方式。")])]),t._v(" "),e("p",[t._v("上面的例子中,"),e("code",[t._v("Restart")]),t._v("设为"),e("code",[t._v("on-failure")]),t._v(",表示任何意外的失败,就将重启 sshd。如果\nsshd 正常停止(比如执行"),e("code",[t._v("systemctl stop")]),t._v("命令),它就不会重启。")]),t._v(" "),e("p",[e("code",[t._v("Restart")]),t._v("字段可以设置的值如下。")]),t._v(" "),e("ul",[e("li",[t._v("no(默认值):退出后不会重启")]),t._v(" "),e("li",[t._v("on-success:只有正常退出时(退出状态码为 0),才会重启")]),t._v(" "),e("li",[t._v("on-failure:非正常退出时(退出状态码非 0),包括被信号终止和超时,才会重启")]),t._v(" "),e("li",[t._v("on-abnormal:只有被信号终止和超时,才会重启")]),t._v(" "),e("li",[t._v("on-abort:只有在收到没有捕捉到的信号终止时,才会重启")]),t._v(" "),e("li",[t._v("on-watchdog:超时退出,才会重启")]),t._v(" "),e("li",[t._v("always:不管是什么退出原因,总是重启")])]),t._v(" "),e("p",[t._v("对于守护进程,推荐设为"),e("code",[t._v("on-failure")]),t._v("。对于那些允许发生错误退出的服务,可以设\n为"),e("code",[t._v("on-abnormal")]),t._v("。")]),t._v(" "),e("p",[t._v("最后是"),e("code",[t._v("RestartSec")]),t._v("字段。")]),t._v(" "),e("blockquote",[e("p",[e("code",[t._v("RestartSec")]),t._v("字段:表示 Systemd 重启服务之前,需要等待的秒数。上面的例子设为等\n待 42 秒。")])]),t._v(" "),e("h3",{attrs:{id:"_8-7-install-区块"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-7-install-区块"}},[t._v("#")]),t._v(" 8.7. [Install] 区块")]),t._v(" "),e("p",[e("code",[t._v("Install")]),t._v("区块,定义如何安装这个配置文件,即怎样做到开机启动。")]),t._v(" "),e("p",[e("code",[t._v("WantedBy")]),t._v("字段:表示该服务所在的 Target。")]),t._v(" "),e("p",[e("code",[t._v("Target")]),t._v("的含义是服务组,表示一组服务。"),e("code",[t._v("WantedBy=multi-user.target")]),t._v("指的是,sshd\n所在的 Target 是"),e("code",[t._v("multi-user.target")]),t._v("。")]),t._v(" "),e("p",[t._v("这个设置非常重要,因为执行"),e("code",[t._v("systemctl enable sshd.service")]),t._v("命令时\n,"),e("code",[t._v("sshd.service")]),t._v("的一个符号链接,就会放在"),e("code",[t._v("/etc/systemd/system")]),t._v("目录下面\n的"),e("code",[t._v("multi-user.target.wants")]),t._v("子目录之中。")]),t._v(" "),e("p",[t._v("Systemd 有默认的启动 Target。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl get-default\nmulti-user.target\n")])])]),e("p",[t._v("上面的结果表示,默认的启动 Target 是"),e("code",[t._v("multi-user.target")]),t._v("。在这个组里的所有服务,\n都将开机启动。这就是为什么"),e("code",[t._v("systemctl enable")]),t._v("命令能设置开机启动的原因。")]),t._v(" "),e("p",[t._v("使用 Target 的时候,"),e("code",[t._v("systemctl list-dependencies")]),t._v("命令和"),e("code",[t._v("systemctl isolate")]),t._v("命令也\n很有用。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 查看 multi-user.target 包含的所有服务")]),t._v("\n$ systemctl list-dependencies multi-user.target\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换到另一个 target")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# shutdown.target 就是关机状态")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl isolate shutdown.target\n")])])]),e("p",[t._v("一般来说,常用的 Target 有两个:一个是"),e("code",[t._v("multi-user.target")]),t._v(",表示多用户命令行状态\n;另一个是"),e("code",[t._v("graphical.target")]),t._v(",表示图形用户状态,它依赖于"),e("code",[t._v("multi-user.target")]),t._v("。官\n方文档有一张非常清晰的\n"),e("a",{attrs:{href:"https://www.freedesktop.org/software/systemd/man/bootup.html#System%20Manager%20Bootup",target:"_blank",rel:"noopener noreferrer"}},[t._v("Target 依赖关系图"),e("OutboundLink")],1),t._v("。")]),t._v(" "),e("h3",{attrs:{id:"_8-8-target-的配置文件"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-8-target-的配置文件"}},[t._v("#")]),t._v(" 8.8. Target 的配置文件")]),t._v(" "),e("p",[t._v("Target 也有自己的配置文件。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ systemctl "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("cat")]),t._v(" multi-user.target\n\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("Unit"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Description")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("Multi-User System\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Documentation")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("man:systemd.special"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("7")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Requires")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("basic.target\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("Conflicts")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("rescue.service rescue.target\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("After")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("basic.target rescue.service rescue.target\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("AllowIsolate")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("yes\n")])])]),e("p",[t._v("注意,Target 配置文件里面没有启动命令。")]),t._v(" "),e("p",[t._v("上面输出结果中,主要字段含义如下。")]),t._v(" "),e("ul",[e("li",[e("code",[t._v("Requires")]),t._v("字段:要求"),e("code",[t._v("basic.target")]),t._v("一起运行。")]),t._v(" "),e("li",[e("code",[t._v("Conflicts")]),t._v("字段:冲突字段。如果"),e("code",[t._v("rescue.service")]),t._v("或"),e("code",[t._v("rescue.target")]),t._v("正在运行\n,"),e("code",[t._v("multi-user.target")]),t._v("就不能运行,反之亦然。")]),t._v(" "),e("li",[e("code",[t._v("After")]),t._v(":表示"),e("code",[t._v("multi-user.target")]),t._v("在"),e("code",[t._v("basic.target")]),t._v(" 、 "),e("code",[t._v("rescue.service")]),t._v("、\n"),e("code",[t._v("rescue.target")]),t._v("之后启动,如果它们有启动的话。")]),t._v(" "),e("li",[e("code",[t._v("AllowIsolate")]),t._v(":允许使用"),e("code",[t._v("systemctl isolate")]),t._v("命令切换到"),e("code",[t._v("multi-user.target")]),t._v("。")])]),t._v(" "),e("h3",{attrs:{id:"_8-9-修改配置文件后重启"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_8-9-修改配置文件后重启"}},[t._v("#")]),t._v(" 8.9. 修改配置文件后重启")]),t._v(" "),e("p",[t._v("修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重新加载配置文件")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl daemon-reload\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 重启相关服务")]),t._v("\n$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" systemctl restart foobar\n")])])]),e("h2",{attrs:{id:"_9-参考资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_9-参考资料"}},[t._v("#")]),t._v(" 9. 参考资料")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Systemd 入门教程:命令篇"),e("OutboundLink")],1)]),t._v(" "),e("li",[e("RouterLink",{attrs:{to:"hhttp://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html"}},[t._v("Systemd 入门教程:实战篇")])],1)])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/46.a9c290ec.js b/assets/js/46.a9c290ec.js new file mode 100644 index 0000000..34cc19d --- /dev/null +++ b/assets/js/46.a9c290ec.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[46],{434:function(v,_,e){"use strict";e.r(_);var t=e(15),o=Object(t.a)({},(function(){var v=this,_=v.$createElement,e=v._self._c||_;return e("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[e("h1",{attrs:{id:"vim-应用"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#vim-应用"}},[v._v("#")]),v._v(" Vim 应用")]),v._v(" "),e("h2",{attrs:{id:"_1-概念"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-概念"}},[v._v("#")]),v._v(" 1. 概念")]),v._v(" "),e("h3",{attrs:{id:"_1-1-什么是-vim"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-什么是-vim"}},[v._v("#")]),v._v(" 1.1. 什么是 vim")]),v._v(" "),e("p",[v._v("Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。和 Emacs 并列成为类 Unix 系统用户最喜欢的编辑器。")]),v._v(" "),e("h3",{attrs:{id:"_1-2-vim-的模式"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-vim-的模式"}},[v._v("#")]),v._v(" 1.2. Vim 的模式")]),v._v(" "),e("p",[v._v("基本上 vi/vim 共分为三种模式,分别是"),e("strong",[v._v("命令模式(Command mode)")]),v._v(","),e("strong",[v._v("插入模式(Insert mode)"),e("strong",[v._v("和")]),v._v("底线命令模式(Last line mode)")]),v._v("。")]),v._v(" "),e("h4",{attrs:{id:"_1-2-1-命令模式"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-1-命令模式"}},[v._v("#")]),v._v(" 1.2.1. 命令模式")]),v._v(" "),e("p",[e("strong",[v._v("用户刚刚启动 vi/vim,便进入了命令模式。")])]),v._v(" "),e("p",[v._v("此状态下敲击键盘动作会被 Vim 识别为命令,而非输入字符。")]),v._v(" "),e("h4",{attrs:{id:"_1-2-2-插入模式"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-2-插入模式"}},[v._v("#")]),v._v(" 1.2.2. 插入模式")]),v._v(" "),e("p",[e("strong",[v._v("在命令模式下按下 "),e("code",[v._v("i")]),v._v(" 就进入了输入模式。")])]),v._v(" "),e("p",[v._v("在输入模式下,你可以输入文本内容。")]),v._v(" "),e("h4",{attrs:{id:"_1-2-3-底线命令模式"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-3-底线命令模式"}},[v._v("#")]),v._v(" 1.2.3. 底线命令模式")]),v._v(" "),e("p",[e("strong",[v._v("在命令模式下按下 "),e("code",[v._v(":")]),v._v("(英文冒号)就进入了底线命令模式。")])]),v._v(" "),e("p",[v._v("底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。")]),v._v(" "),e("h2",{attrs:{id:"_2-vim-渐进学习"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-vim-渐进学习"}},[v._v("#")]),v._v(" 2. Vim 渐进学习")]),v._v(" "),e("h3",{attrs:{id:"_2-1-存活"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-存活"}},[v._v("#")]),v._v(" 2.1. 存活")]),v._v(" "),e("ol",[e("li",[v._v("安装 "),e("a",{attrs:{href:"http://www.vim.org/",target:"_blank",rel:"noopener noreferrer"}},[v._v("vim"),e("OutboundLink")],1)]),v._v(" "),e("li",[v._v("启动 vim")]),v._v(" "),e("li",[v._v("**什么也别干!**请先阅读")])]),v._v(" "),e("p",[v._v("当你安装好一个编辑器后,你一定会想在其中输入点什么东西,然后看看这个编辑器是什么样子。但 vim 不是这样的,请按照下面的命令操作:")]),v._v(" "),e("ul",[e("li",[v._v("启 动 Vim 后,vim 在 "),e("em",[v._v("Normal")]),v._v(" 模式下。")]),v._v(" "),e("li",[v._v("让我们进入 "),e("em",[v._v("Insert")]),v._v(" 模式,请按下键 i 。(注:你会看到 vim 左下角有一个–insert–字样,表示,你可以以插入的方式输入了)")]),v._v(" "),e("li",[v._v("此时,你可以输入文本了,就像你用“记事本”一样。")]),v._v(" "),e("li",[v._v("如果你想返回 "),e("em",[v._v("Normal")]),v._v(" 模式,请按 "),e("code",[v._v("ESC")]),v._v(" 键。")])]),v._v(" "),e("p",[v._v("现在,你知道如何在 "),e("em",[v._v("Insert")]),v._v(" 和 "),e("em",[v._v("Normal")]),v._v(" 模式下切换了。下面是一些命令,可以让你在 "),e("em",[v._v("Normal")]),v._v(" 模式下幸存下来:")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("i")]),v._v(" → "),e("em",[v._v("Insert")]),v._v(" 模式,按 "),e("code",[v._v("ESC")]),v._v(" 回到 "),e("em",[v._v("Normal")]),v._v(" 模式.")]),v._v(" "),e("li",[e("code",[v._v("x")]),v._v(" → 删当前光标所在的一个字符。")]),v._v(" "),e("li",[e("code",[v._v(":wq")]),v._v(" → 存盘 + 退出 ("),e("code",[v._v(":w")]),v._v(" 存盘, "),e("code",[v._v(":q")]),v._v(" 退出) (注::w 后可以跟文件名)")]),v._v(" "),e("li",[e("code",[v._v("dd")]),v._v(" → 删除当前行,并把删除的行存到剪贴板里")]),v._v(" "),e("li",[e("code",[v._v("p")]),v._v(" → 粘贴剪贴板")])]),v._v(" "),e("p",[e("strong",[v._v("推荐")])]),v._v(" "),e("ul",[e("li",[e("code",[v._v("hjkl")]),v._v(" (强例推荐使用其移动光标,但不必需) → 你也可以使用光标键 (←↓↑→). 注: "),e("code",[v._v("j")]),v._v(" 就像下箭头。")]),v._v(" "),e("li",[e("code",[v._v(":help ")]),v._v(" → 显示相关命令的帮助。你也可以就输入 "),e("code",[v._v(":help")]),v._v(" 而不跟命令。(注:退出帮助需要输入:q)")])])]),v._v(" "),e("p",[v._v("你能在 vim 幸存下来只需要上述的那 5 个命令,你就可以编辑文本了,你一定要把这些命令练成一种下意识的状态。于是你就可以开始进阶到第二级了。")]),v._v(" "),e("p",[v._v("当是,在你进入第二级时,需要再说一下 "),e("em",[v._v("Normal")]),v._v(" 模式。在一般的编辑器下,当你需要 copy 一段文字的时候,你需要使用 "),e("code",[v._v("Ctrl")]),v._v(" 键,比如:"),e("code",[v._v("Ctrl-C")]),v._v("。也就是说,"),e("code",[v._v("Ctrl")]),v._v(" 键就好像功能键一样,当你按下了功能键 "),e("code",[v._v("Ctrl")]),v._v(" 后,C 就不在是 C 了,而且就是一个命令或是一个快键键了,"),e("strong",[v._v("在 vim 的 Normal 模式下,所有的键都是功能键")]),v._v("。这个你需要知道。")]),v._v(" "),e("blockquote",[e("p",[e("strong",[v._v("标记")])]),v._v(" "),e("ul",[e("li",[v._v("下面的文字中,如果是 "),e("code",[v._v("Ctrl-λ")]),v._v("我会写成 "),e("code",[v._v("")]),v._v(".")]),v._v(" "),e("li",[v._v("以 "),e("code",[v._v(":")]),v._v(" 开始的命令你需要输入 "),e("code",[v._v("")]),v._v("回车,例如 — 如果我写成 "),e("code",[v._v(":q")]),v._v(" 也就是说你要输入 "),e("code",[v._v(":q")]),v._v(".")])])]),v._v(" "),e("h3",{attrs:{id:"_2-2-感觉良好"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-感觉良好"}},[v._v("#")]),v._v(" 2.2. 感觉良好")]),v._v(" "),e("p",[v._v("上面的那些命令只能让你存活下来,现在是时候学习一些更多的命令了,下面是我的建议:(注:所有的命令都需要在 Normal 模式下使用,如果你不知道现在在什么样的模式,你就狂按几次 ESC 键)")]),v._v(" "),e("ol",[e("li",[e("p",[v._v("各种插入模式")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("a")]),v._v(" → 在光标后插入")]),v._v(" "),e("li",[e("code",[v._v("o")]),v._v(" → 在当前行后插入一个新行")]),v._v(" "),e("li",[e("code",[v._v("O")]),v._v(" → 在当前行前插入一个新行")]),v._v(" "),e("li",[e("code",[v._v("cw")]),v._v(" → 替换从光标所在位置后到一个单词结尾的字符")])])])]),v._v(" "),e("li",[e("p",[v._v("简单的移动光标")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("0")]),v._v(" → 数字零,到行头")]),v._v(" "),e("li",[e("code",[v._v("^")]),v._v(" → 到本行第一个不是 blank 字符的位置(所谓 blank 字符就是空格,tab,换行,回车等)")]),v._v(" "),e("li",[e("code",[v._v("$")]),v._v(" → 到本行行尾")]),v._v(" "),e("li",[e("code",[v._v("g_")]),v._v(" → 到本行最后一个不是 blank 字符的位置。")]),v._v(" "),e("li",[e("code",[v._v("/pattern")]),v._v(" → 搜索 "),e("code",[v._v("pattern")]),v._v(" 的字符串(注:如果搜索出多个匹配,可按 n 键到下一个)")])])])]),v._v(" "),e("li",[e("p",[v._v("拷贝/粘贴")]),v._v(" "),e("p",[v._v("(注:p/P 都可以,p 是表示在当前位置之后,P 表示在当前位置之前)")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("P")]),v._v(" → 粘贴")]),v._v(" "),e("li",[e("code",[v._v("yy")]),v._v(" → 拷贝当前行当行于 "),e("code",[v._v("ddP")])])])])]),v._v(" "),e("li",[e("p",[v._v("Undo/Redo")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("u")]),v._v(" → undo")]),v._v(" "),e("li",[e("code",[v._v("")]),v._v(" → redo")])])])]),v._v(" "),e("li",[e("p",[v._v("打开/保存/退出/改变文件")]),v._v(" "),e("p",[v._v("(Buffer)")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v(":e ")]),v._v(" → 打开一个文件")]),v._v(" "),e("li",[e("code",[v._v(":w")]),v._v(" → 存盘")]),v._v(" "),e("li",[e("code",[v._v(":saveas ")]),v._v(" → 另存为 "),e("code",[v._v("")])]),v._v(" "),e("li",[e("code",[v._v(":x")]),v._v(", "),e("code",[v._v("ZZ")]),v._v(" 或 "),e("code",[v._v(":wq")]),v._v(" → 保存并退出 ("),e("code",[v._v(":x")]),v._v(" 表示仅在需要时保存,ZZ 不需要输入冒号并回车)")]),v._v(" "),e("li",[e("code",[v._v(":q!")]),v._v(" → 退出不保存 "),e("code",[v._v(":qa!")]),v._v(" 强行退出所有的正在编辑的文件,就算别的文件有更改。")]),v._v(" "),e("li",[e("code",[v._v(":bn")]),v._v(" 和 "),e("code",[v._v(":bp")]),v._v(" → 你可以同时打开很多文件,使用这两个命令来切换下一个或上一个文件。(注:我喜欢使用:n 到下一个文件)")])])])])]),v._v(" "),e("p",[v._v("花点时间熟悉一下上面的命令,一旦你掌握他们了,你就几乎可以干其它编辑器都能干的事了。但是到现在为止,你还是觉得使用 vim 还是有点笨拙,不过没关系,你可以进阶到第三级了。")]),v._v(" "),e("h3",{attrs:{id:"_2-3-更好-更强-更快"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-更好-更强-更快"}},[v._v("#")]),v._v(" 2.3. 更好,更强,更快")]),v._v(" "),e("p",[v._v("先恭喜你!你干的很不错。我们可以开始一些更为有趣的事了。在第三级,我们只谈那些和 vi 可以兼容的命令。")]),v._v(" "),e("h4",{attrs:{id:"_2-3-1-更好"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-1-更好"}},[v._v("#")]),v._v(" 2.3.1. 更好")]),v._v(" "),e("p",[v._v("下面,让我们看一下 vim 是怎么重复自己的:1515G")]),v._v(" "),e("ol",[e("li",[e("code",[v._v(".")]),v._v(" → (小数点) 可以重复上一次的命令")]),v._v(" "),e("li",[e("code",[v._v("N")]),v._v(" → 重复某个命令 N 次")])]),v._v(" "),e("p",[v._v("下面是一个示例,找开一个文件你可以试试下面的命令:")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("2dd")]),v._v(" → 删除 2 行")]),v._v(" "),e("li",[e("code",[v._v("3p")]),v._v(" → 粘贴文本 3 次")]),v._v(" "),e("li",[e("code",[v._v("100idesu [ESC]")]),v._v(" → 会写下 “desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu “")]),v._v(" "),e("li",[e("code",[v._v(".")]),v._v(" → 重复上一个命令—— 100 “desu “.")]),v._v(" "),e("li",[e("code",[v._v("3.")]),v._v(" → 重复 3 次 “desu” (注意:不是 300,你看,VIM 多聪明啊).")])])]),v._v(" "),e("h4",{attrs:{id:"_2-3-2-更强"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-2-更强"}},[v._v("#")]),v._v(" 2.3.2. 更强")]),v._v(" "),e("p",[v._v("你要让你的光标移动更有效率,你一定要了解下面的这些命令,"),e("strong",[v._v("千万别跳过")]),v._v("。")]),v._v(" "),e("ol",[e("li",[e("p",[v._v("N"),e("code",[v._v("G")]),v._v(" → 到第 N 行 (注:注意命令中的 G 是大写的,另我一般使用 : N 到第 N 行,如 :137 到第 137 行)")])]),v._v(" "),e("li",[e("p",[e("code",[v._v("gg")]),v._v(" → 到第一行。(注:相当于 1G,或 :1)")])]),v._v(" "),e("li",[e("p",[e("code",[v._v("G")]),v._v(" → 到最后一行。")])]),v._v(" "),e("li",[e("p",[v._v("按单词移动:")]),v._v(" "),e("blockquote",[e("ol",[e("li",[e("code",[v._v("w")]),v._v(" → 到下一个单词的开头。")]),v._v(" "),e("li",[e("code",[v._v("e")]),v._v(" → 到下一个单词的结尾。")])]),v._v(" "),e("p",[v._v("> 如果你认为单词是由默认方式,那么就用小写的 e 和 w。默认上来说,一个单词由字母,数字和下划线组成(注:程序变量)")]),v._v(" "),e("p",[v._v("> 如果你认为单词是由 blank 字符分隔符,那么你需要使用大写的 E 和 W。(注:程序语句)")]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-46f752c581d79057.jpg",alt:"img"}})])])])]),v._v(" "),e("p",[v._v("下面,让我来说说最强的光标移动:")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("%")]),v._v(" : 匹配括号移动,包括 "),e("code",[v._v("(")]),v._v(", "),e("code",[v._v("{")]),v._v(", "),e("code",[v._v("[")]),v._v(". (注:你需要把光标先移到括号上)")]),v._v(" "),e("li",[e("code",[v._v("*")]),v._v(" 和 "),e("code",[v._v("#")]),v._v(": 匹配光标当前所在的单词,移动光标到下一个(或上一个)匹配单词(*是下一个,#是上一个)")])])]),v._v(" "),e("p",[v._v("相信我,上面这三个命令对程序员来说是相当强大的。")]),v._v(" "),e("h4",{attrs:{id:"_2-3-3-更快"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-3-更快"}},[v._v("#")]),v._v(" 2.3.3. 更快")]),v._v(" "),e("p",[v._v("你一定要记住光标的移动,因为很多命令都可以和这些移动光标的命令连动。很多命令都可以如下来干:")]),v._v(" "),e("p",[e("code",[v._v("")])]),v._v(" "),e("p",[v._v("例如 "),e("code",[v._v("0y$")]),v._v(" 命令意味着:")]),v._v(" "),e("ul",[e("li",[e("code",[v._v("0")]),v._v(" → 先到行头")]),v._v(" "),e("li",[e("code",[v._v("y")]),v._v(" → 从这里开始拷贝")]),v._v(" "),e("li",[e("code",[v._v("$")]),v._v(" → 拷贝到本行最后一个字符")])]),v._v(" "),e("p",[v._v("你可可以输入 "),e("code",[v._v("ye")]),v._v(",从当前位置拷贝到本单词的最后一个字符。")]),v._v(" "),e("p",[v._v("你也可以输入 "),e("code",[v._v("y2/foo")]),v._v(" 来拷贝 2 个 “foo” 之间的字符串。")]),v._v(" "),e("p",[v._v("还有很多时间并不一定你就一定要按 y 才会拷贝,下面的命令也会被拷贝:")]),v._v(" "),e("ul",[e("li",[e("code",[v._v("d")]),v._v(" (删除 )")]),v._v(" "),e("li",[e("code",[v._v("v")]),v._v(" (可视化的选择)")]),v._v(" "),e("li",[e("code",[v._v("gU")]),v._v(" (变大写)")]),v._v(" "),e("li",[e("code",[v._v("gu")]),v._v(" (变小写)")]),v._v(" "),e("li",[v._v("等等")])]),v._v(" "),e("p",[v._v("(注:可视化选择是一个很有意思的命令,你可以先按 v,然后移动光标,你就会看到文本被选择,然后,你可能 d,也可 y,也可以变大写等)")]),v._v(" "),e("h3",{attrs:{id:"_2-4-vim-超能力"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-vim-超能力"}},[v._v("#")]),v._v(" 2.4. Vim 超能力")]),v._v(" "),e("p",[v._v("你只需要掌握前面的命令,你就可以很舒服的使用 VIM 了。但是,现在,我们向你介绍的是 VIM 杀手级的功能。下面这些功能是我只用 vim 的原因。")]),v._v(" "),e("h4",{attrs:{id:"_2-4-1-在当前行上移动光标-0-fftt"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-1-在当前行上移动光标-0-fftt"}},[v._v("#")]),v._v(" 2.4.1. 在当前行上移动光标: "),e("code",[v._v("0")]),v._v(" "),e("code",[v._v("^")]),v._v(" "),e("code",[v._v("####")]),v._v("f"),e("code",[v._v("F")]),v._v("t"),e("code",[v._v("T")]),v._v(",``;`")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v("0")]),v._v(" → 到行头")]),v._v(" "),e("li",[e("code",[v._v("^")]),v._v(" → 到本行的第一个非 blank 字符")]),v._v(" "),e("li",[e("code",[v._v("$")]),v._v(" → 到行尾")]),v._v(" "),e("li",[e("code",[v._v("g_")]),v._v(" → 到本行最后一个不是 blank 字符的位置。")]),v._v(" "),e("li",[e("code",[v._v("fa")]),v._v(" → 到下一个为 a 的字符处,你也可以 fs 到下一个为 s 的字符。")]),v._v(" "),e("li",[e("code",[v._v("t,")]),v._v(" → 到逗号前的第一个字符。逗号可以变成其它字符。")]),v._v(" "),e("li",[e("code",[v._v("3fa")]),v._v(" → 在当前行查找第三个出现的 a。")]),v._v(" "),e("li",[e("code",[v._v("F")]),v._v(" 和 "),e("code",[v._v("T")]),v._v(" → 和 "),e("code",[v._v("f")]),v._v(" 和 "),e("code",[v._v("t")]),v._v(" 一样,只不过是相反方向。\n"),e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-00835b8316330c58.jpg",alt:"img"}})])])]),v._v(" "),e("p",[v._v("还有一个很有用的命令是 "),e("code",[v._v('dt"')]),v._v(" → 删除所有的内容,直到遇到双引号—— "),e("code",[v._v('"。')])]),v._v(" "),e("h4",{attrs:{id:"_2-4-2-区域选择-action-a-object-或-action-i-object"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-2-区域选择-action-a-object-或-action-i-object"}},[v._v("#")]),v._v(" 2.4.2. 区域选择 "),e("code",[v._v("a")]),v._v(" 或 "),e("code",[v._v("i")])]),v._v(" "),e("p",[v._v("在 visual 模式下,这些命令很强大,其命令格式为")]),v._v(" "),e("p",[e("code",[v._v("a")]),v._v(" 和 "),e("code",[v._v("i")])]),v._v(" "),e("ul",[e("li",[v._v("action 可以是任何的命令,如 "),e("code",[v._v("d")]),v._v(" (删除), "),e("code",[v._v("y")]),v._v(" (拷贝), "),e("code",[v._v("v")]),v._v(" (可以视模式选择)。")]),v._v(" "),e("li",[v._v("object 可能是: "),e("code",[v._v("w")]),v._v(" 一个单词, "),e("code",[v._v("W")]),v._v(" 一个以空格为分隔的单词, "),e("code",[v._v("s")]),v._v(" 一个句字, "),e("code",[v._v("p")]),v._v(" 一个段落。也可以是一个特别的字符:"),e("code",[v._v('"、')]),v._v(" "),e("code",[v._v("'、")]),v._v(" "),e("code",[v._v(")、")]),v._v(" "),e("code",[v._v("}、")]),v._v(" "),e("code",[v._v("]。")])])]),v._v(" "),e("p",[v._v("假设你有一个字符串 "),e("code",[v._v('(map (+) ("foo"))')]),v._v(".而光标键在第一个 "),e("code",[v._v("o")]),v._v("的位置。")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v('vi"')]),v._v(" → 会选择 "),e("code",[v._v("foo")]),v._v(".")]),v._v(" "),e("li",[e("code",[v._v('va"')]),v._v(" → 会选择 "),e("code",[v._v('"foo"')]),v._v(".")]),v._v(" "),e("li",[e("code",[v._v("vi)")]),v._v(" → 会选择 "),e("code",[v._v('"foo"')]),v._v(".")]),v._v(" "),e("li",[e("code",[v._v("va)")]),v._v(" → 会选择"),e("code",[v._v('("foo")')]),v._v(".")]),v._v(" "),e("li",[e("code",[v._v("v2i)")]),v._v(" → 会选择 "),e("code",[v._v('map (+) ("foo")')])]),v._v(" "),e("li",[e("code",[v._v("v2a)")]),v._v(" → 会选择 "),e("code",[v._v('(map (+) ("foo"))')])])])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-0b109d66a6111c83.png",alt:"img"}})]),v._v(" "),e("h4",{attrs:{id:"_2-4-3-块操作-c-v"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-3-块操作-c-v"}},[v._v("#")]),v._v(" 2.4.3. 块操作: "),e("code",[v._v("")])]),v._v(" "),e("p",[v._v("块操作,典型的操作: "),e("code",[v._v("0 I-- [ESC]")])]),v._v(" "),e("ul",[e("li",[e("code",[v._v("^")]),v._v(" → 到行头")]),v._v(" "),e("li",[e("code",[v._v("")]),v._v(" → 开始块操作")]),v._v(" "),e("li",[e("code",[v._v("")]),v._v(" → 向下移动 (你也可以使用 hjkl 来移动光标,或是使用%,或是别的)")]),v._v(" "),e("li",[e("code",[v._v("I-- [ESC]")]),v._v(" → I 是插入,插入“"),e("code",[v._v("--")]),v._v("”,按 ESC 键来为每一行生效。")])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-8b093a0f65707949.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("p",[v._v("在 Windows 下的 vim,你需要使用 "),e("code",[v._v("")]),v._v(" 而不是 "),e("code",[v._v("")]),v._v(" ,"),e("code",[v._v("")]),v._v(" 是拷贝剪贴板。")]),v._v(" "),e("h4",{attrs:{id:"_2-4-4-自动提示-c-n-和-c-p"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-4-自动提示-c-n-和-c-p"}},[v._v("#")]),v._v(" 2.4.4. 自动提示: "),e("code",[v._v("")]),v._v(" 和 "),e("code",[v._v("")])]),v._v(" "),e("p",[v._v("在 Insert 模式下,你可以输入一个词的开头,然后按 "),e("code",[v._v("或是,自动补齐功能就出现了……")])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-e2ae877e67880ff7.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("h4",{attrs:{id:"_2-4-5-宏录制-qa-操作序列-q-a"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-5-宏录制-qa-操作序列-q-a"}},[v._v("#")]),v._v(" 2.4.5. 宏录制: "),e("code",[v._v("qa")]),v._v(" 操作序列 "),e("code",[v._v("q")]),v._v(", "),e("code",[v._v("@a")]),v._v(", "),e("code",[v._v("@@")])]),v._v(" "),e("ul",[e("li",[e("code",[v._v("qa")]),v._v(" 把你的操作记录在寄存器 "),e("code",[v._v("a。")])]),v._v(" "),e("li",[v._v("于是 "),e("code",[v._v("@a")]),v._v(" 会 replay 被录制的宏。")]),v._v(" "),e("li",[e("code",[v._v("@@")]),v._v(" 是一个快捷键用来 replay 最新录制的宏。")])]),v._v(" "),e("blockquote",[e("p",[e("strong",[v._v("示例")])]),v._v(" "),e("p",[v._v("在一个只有一行且这一行只有“1”的文本中,键入如下命令:")]),v._v(" "),e("ul",[e("li",[e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[v._v("qaYpq\n")])])]),e("p",[v._v("→")]),v._v(" "),e("ul",[e("li",[e("code",[v._v("qa")]),v._v(" 开始录制")]),v._v(" "),e("li",[e("code",[v._v("Yp")]),v._v(" 复制行.")]),v._v(" "),e("li",[e("code",[v._v("")]),v._v(" 增加 1.")]),v._v(" "),e("li",[e("code",[v._v("q")]),v._v(" 停止录制.")])])]),v._v(" "),e("li",[e("p",[e("code",[v._v("@a")]),v._v(" → 在 1 下面写下 2")])]),v._v(" "),e("li",[e("p",[e("code",[v._v("@@")]),v._v(" → 在 2 正面写下 3")])]),v._v(" "),e("li",[e("p",[v._v("现在做 "),e("code",[v._v("100@@")]),v._v(" 会创建新的 100 行,并把数据增加到 103.")])])])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-f1889f8bca723964.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("h4",{attrs:{id:"_2-4-6-可视化选择-v-v-c-v"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-6-可视化选择-v-v-c-v"}},[v._v("#")]),v._v(" 2.4.6. 可视化选择: "),e("code",[v._v("v")]),v._v(","),e("code",[v._v("V")]),v._v(","),e("code",[v._v("")])]),v._v(" "),e("p",[v._v("前面,我们看到了 "),e("code",[v._v("")]),v._v("的示例 (在 Windows 下应该是"),e("C-q",[v._v("),我们可以使用 "),e("code",[v._v("v")]),v._v(" 和 "),e("code",[v._v("V")]),v._v("。一但被选好了,你可以做下面的事:")])],1),v._v(" "),e("ul",[e("li",[e("code",[v._v("J")]),v._v(" → 把所有的行连接起来(变成一行)")]),v._v(" "),e("li",[e("code",[v._v("<")]),v._v(" 或 "),e("code",[v._v(">")]),v._v(" → 左右缩进")]),v._v(" "),e("li",[e("code",[v._v("=")]),v._v(" → 自动给缩进 (注:这个功能相当强大,我太喜欢了)")])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-fe1e19983fca213f.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("p",[v._v("在所有被选择的行后加上点东西:")]),v._v(" "),e("ul",[e("li",[e("code",[v._v("")])]),v._v(" "),e("li",[v._v("选中相关的行 (可使用 "),e("code",[v._v("j")]),v._v(" 或 "),e("code",[v._v("")]),v._v(" 或是 "),e("code",[v._v("/pattern")]),v._v(" 或是 "),e("code",[v._v("%")]),v._v(" 等……)")]),v._v(" "),e("li",[e("code",[v._v("$")]),v._v(" 到行最后")]),v._v(" "),e("li",[e("code",[v._v("A")]),v._v(", 输入字符串,按 "),e("code",[v._v("ESC。")])])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-b192601247334c4e.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("h4",{attrs:{id:"_2-4-7-分屏-split-和-vsplit"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-7-分屏-split-和-vsplit"}},[v._v("#")]),v._v(" 2.4.7. 分屏: "),e("code",[v._v(":split")]),v._v(" 和 "),e("code",[v._v("vsplit")]),v._v(".")]),v._v(" "),e("p",[v._v("下面是主要的命令,你可以使用 VIM 的帮助 "),e("code",[v._v(":help split")]),v._v(". 你可以参考本站以前的一篇文章"),e("a",{attrs:{href:"https://coolshell.cn/articles/1679.html",target:"_blank",rel:"noopener noreferrer"}},[v._v("VIM 分屏"),e("OutboundLink")],1),v._v("。")]),v._v(" "),e("blockquote",[e("ul",[e("li",[e("code",[v._v(":split")]),v._v(" → 创建分屏 ("),e("code",[v._v(":vsplit")]),v._v("创建垂直分屏)")]),v._v(" "),e("li",[e("code",[v._v("")]),v._v(" : dir 就是方向,可以是 "),e("code",[v._v("hjkl")]),v._v(" 或是 ←↓↑→ 中的一个,其用来切换分屏。")]),v._v(" "),e("li",[e("code",[v._v("_")]),v._v(" (或 "),e("code",[v._v("|")]),v._v(") : 最大化尺寸 ("),e("C-w",[v._v("| 垂直分屏)")])],1),v._v(" "),e("li",[e("code",[v._v("+")]),v._v(" (或 "),e("code",[v._v("-")]),v._v(") : 增加尺寸")])])]),v._v(" "),e("p",[e("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-f329d01e299cb366.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),v._v(" "),e("h2",{attrs:{id:"_3-vim-cheat-sheet"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-vim-cheat-sheet"}},[v._v("#")]),v._v(" 3. Vim Cheat Sheet")]),v._v(" "),e("blockquote",[e("p",[v._v("本节内容的原文地址:"),e("a",{attrs:{href:"http://cenalulu.github.io/linux/all-vim-cheatsheat/",target:"_blank",rel:"noopener noreferrer"}},[v._v("http://cenalulu.github.io/linux/all-vim-cheatsheat/"),e("OutboundLink")],1)])]),v._v(" "),e("h3",{attrs:{id:"_3-1-经典版"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-1-经典版"}},[v._v("#")]),v._v(" 3.1. 经典版")]),v._v(" "),e("p",[v._v("下面这个键位图应该是大家最常看见的经典版了。其实这个版本是一系列的入门教程键位图的组合结果。要查看不同编辑模式下的键位图,可以看"),e("a",{attrs:{href:"http://www.viemu.com/a_vi_vim_graphical_cheat_sheet_tutorial.html",target:"_blank",rel:"noopener noreferrer"}},[v._v("这里打包下载"),e("OutboundLink")],1)]),v._v(" "),e("p",[v._v("此外,"),e("a",{attrs:{href:"http://blog.ngedit.com/vi-vim-cheat-sheet-sch.gif",target:"_blank",rel:"noopener noreferrer"}},[v._v("这里"),e("OutboundLink")],1),v._v("还有简体中文版。")]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/vim-cheat-sheet.png",alt:"img"}})]),v._v(" "),e("h3",{attrs:{id:"_3-2-入门版"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-2-入门版"}},[v._v("#")]),v._v(" 3.2. 入门版")]),v._v(" "),e("p",[v._v("基本操作的入门版。"),e("a",{attrs:{href:"https://github.com/ahrencode/Miscellaneous",target:"_blank",rel:"noopener noreferrer"}},[v._v("原版出处"),e("OutboundLink")],1),v._v("还有 keynote 版本可供 DIY 以及其他相关有用的 cheatsheet。")]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/basic-vim-cheat-sheet.png",alt:"img"}})]),v._v(" "),e("h3",{attrs:{id:"_3-3-进阶版"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-3-进阶版"}},[v._v("#")]),v._v(" 3.3. 进阶版")]),v._v(" "),e("p",[v._v("下图是 300DPI 的超清大图,另外"),e("a",{attrs:{href:"http://michael.peopleofhonoronly.com/vim/",target:"_blank",rel:"noopener noreferrer"}},[v._v("查看原文"),e("OutboundLink")],1),v._v("还有更多版本:黑白,低分辨率,色盲等")]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/vim-cheat-sheet-for-programmers.png",alt:"img"}})]),v._v(" "),e("h3",{attrs:{id:"_3-4-增强版"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-4-增强版"}},[v._v("#")]),v._v(" 3.4. 增强版")]),v._v(" "),e("p",[v._v("下图是一个更新时间较新的现代版,含有的信息也更丰富。"),e("a",{attrs:{href:"http://vimcheatsheet.com/",target:"_blank",rel:"noopener noreferrer"}},[v._v("原文链接"),e("OutboundLink")],1)]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/vim-cheat-sheet-02.png",alt:"img"}})]),v._v(" "),e("h3",{attrs:{id:"_3-5-文字版"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-5-文字版"}},[v._v("#")]),v._v(" 3.5. 文字版")]),v._v(" "),e("p",[e("a",{attrs:{href:"http://tnerual.eriogerg.free.fr/vimqrc.pdf",target:"_blank",rel:"noopener noreferrer"}},[v._v("原文链接"),e("OutboundLink")],1)]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/vim-cheat-sheet-text-01.png",alt:"img"}})]),v._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/os/linux/vim/vim-cheat-sheet-text-02.png",alt:"img"}})]),v._v(" "),e("h2",{attrs:{id:"_4-资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_4-资料"}},[v._v("#")]),v._v(" 4. 资料")]),v._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"https://coolshell.cn/articles/5426.html",target:"_blank",rel:"noopener noreferrer"}},[v._v("简明 VIM 练级攻略"),e("OutboundLink")],1),v._v(" ,Vim 渐进学习内容来源于这篇文章,作为 Vim 新手,我觉得入门效果很好。")]),v._v(" "),e("li",[e("a",{attrs:{href:"https://vim.sourceforge.io/docs.php",target:"_blank",rel:"noopener noreferrer"}},[v._v("vim 官方文档"),e("OutboundLink")],1)]),v._v(" "),e("li",[e("a",{attrs:{href:"https://github.com/mhinz/vim-galore",target:"_blank",rel:"noopener noreferrer"}},[v._v("vim-galore"),e("OutboundLink")],1)]),v._v(" "),e("li",[e("a",{attrs:{href:"http://www.jianshu.com/p/bcbe916f97e1",target:"_blank",rel:"noopener noreferrer"}},[v._v("Vim 入门基础"),e("OutboundLink")],1)])])])}),[],!1,null,null,null);_.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/47.cc639f04.js b/assets/js/47.cc639f04.js new file mode 100644 index 0000000..4e51bd7 --- /dev/null +++ b/assets/js/47.cc639f04.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[47],{435:function(s,t,a){"use strict";a.r(t);var e=a(15),r=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"oh-my-zsh-应用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#oh-my-zsh-应用"}},[s._v("#")]),s._v(" oh-my-zsh 应用")]),s._v(" "),a("h2",{attrs:{id:"_1-zsh-简介"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-zsh-简介"}},[s._v("#")]),s._v(" 1. Zsh 简介")]),s._v(" "),a("h3",{attrs:{id:"_1-1-zsh-是什么"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-zsh-是什么"}},[s._v("#")]),s._v(" 1.1. Zsh 是什么")]),s._v(" "),a("p",[s._v("使用 Linux 的人都知道:*"),a("strong",[s._v("Shell_ 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。"),a("em",[s._v("Shell")]),s._v(" 既是一种命令语言,又是一种程序设计语言")]),s._v("。")]),s._v(" "),a("p",[s._v("Shell 的类型有很多种,linux 下默认的是 bash,虽然 bash 的功能已经很强大,但对于以懒惰为美德的程序员来说,bash 的提示功能不够强大,界面也不够炫,并非理想工具。")]),s._v(" "),a("p",[a("a",{attrs:{href:"http://www.zsh.org/",target:"_blank",rel:"noopener noreferrer"}},[a("strong",[s._v("Zsh")]),a("OutboundLink")],1),s._v(" 也是一种 Shell(据传说 99% 的 Bash 操作 和 Zsh 是相同的),它的功能极其强大,只是配置过于复杂,起初只有极客才在用。后来,出现了一个名叫 "),a("a",{attrs:{href:"https://github.com/robbyrussell/oh-my-zsh",target:"_blank",rel:"noopener noreferrer"}},[a("strong",[s._v("oh-my-zsh")]),a("OutboundLink")],1),s._v(" 的开源项目,使用 zsh 就变得十分简易了。")]),s._v(" "),a("h2",{attrs:{id:"_2-zsh-安装"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-zsh-安装"}},[s._v("#")]),s._v(" 2. Zsh 安装")]),s._v(" "),a("h3",{attrs:{id:"_2-1-环境要求"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-环境要求"}},[s._v("#")]),s._v(" 2.1. 环境要求")]),s._v(" "),a("ul",[a("li",[s._v("CentOS 6.7 64 bit")]),s._v(" "),a("li",[s._v("root 用户")])]),s._v(" "),a("h3",{attrs:{id:"_2-2-安装-zsh"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-安装-zsh"}},[s._v("#")]),s._v(" 2.2. 安装 zsh")]),s._v(" "),a("ul",[a("li",[s._v("先看下你的 CentOS 支持哪些 shell:"),a("code",[s._v("cat /etc/shells")]),s._v(",正常结果应该是这样的:")])]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[s._v("/bin/sh\n/bin/bash\n/sbin/nologin\n/bin/dash\n/bin/tcsh\n/bin/csh\n")])])]),a("p",[s._v("如果已经有 zsh ,那么我们就不必安装了。")]),s._v(" "),a("ul",[a("li",[s._v("CentOS 安装:"),a("code",[s._v("sudo yum install -y zsh")])]),s._v(" "),a("li",[s._v("Ubuntu 安装:"),a("code",[s._v("sudo apt-get install -y zsh")])]),s._v(" "),a("li",[s._v("检查系统的 shell:"),a("code",[s._v("cat /etc/shells")]),s._v(",你会发现多了一个:"),a("code",[s._v("/bin/zsh")])])]),s._v(" "),a("h3",{attrs:{id:"_2-3-安装-oh-my-zsh"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-3-安装-oh-my-zsh"}},[s._v("#")]),s._v(" 2.3. 安装 oh-my-zsh")]),s._v(" "),a("p",[s._v("使用 "),a("a",{attrs:{href:"http://www.zsh.org/",target:"_blank",rel:"noopener noreferrer"}},[a("strong",[s._v("Zsh")]),a("OutboundLink")],1),s._v(",怎么能离开灵魂伴侣 "),a("a",{attrs:{href:"https://github.com/robbyrussell/oh-my-zsh",target:"_blank",rel:"noopener noreferrer"}},[a("strong",[s._v("oh-my-zsh")]),a("OutboundLink")],1),s._v("?")]),s._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 安装 oh-my-zsh")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("wget")]),s._v(" https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sh")]),s._v("\n")])])]),a("h3",{attrs:{id:"_2-4-配置-oh-my-zsh"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-配置-oh-my-zsh"}},[s._v("#")]),s._v(" 2.4. 配置 oh-my-zsh")]),s._v(" "),a("h4",{attrs:{id:"_2-4-1-插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-1-插件"}},[s._v("#")]),s._v(" 2.4.1. 插件")]),s._v(" "),a("blockquote",[a("p",[s._v("oh-my-zsh 插件太多,不一一列举,请参考:"),a("a",{attrs:{href:"https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins",target:"_blank",rel:"noopener noreferrer"}},[s._v("oh-my-zsh 插件列表"),a("OutboundLink")],1)])]),s._v(" "),a("ul",[a("li",[s._v("启用 oh-my-zsh 中自带的插件。")]),s._v(" "),a("li",[s._v("查看 oh-my-zsh 插件数:"),a("code",[s._v('ls -l /root/.oh-my-zsh/plugins |grep "^d"|wc -l')])]),s._v(" "),a("li",[s._v("编辑配置文件:"),a("code",[s._v("vim /root/.zshrc")])]),s._v(" "),a("li",[s._v("插件推荐:\n"),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/zsh-users/zsh-autosuggestions",target:"_blank",rel:"noopener noreferrer"}},[a("code",[s._v("zsh-autosuggestions")]),a("OutboundLink")],1),s._v(" "),a("ul",[a("li",[s._v("这个插件会对历史命令一些补全,类似 fish 终端")]),s._v(" "),a("li",[s._v("安装,复制该命令:"),a("code",[s._v("git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-\\~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions")]),s._v(" - 编辑:"),a("code",[s._v("vim \\~/.zshrc")]),s._v(",找到这一行,后括号里面的后面添加:"),a("code",[s._v("plugins=( 前面的一些插件名称,换行,加上:zsh-autosuggestions)")]),s._v(" - 刷新下配置:"),a("code",[s._v("source \\~/.zshrc")])])])]),s._v(" "),a("li",[s._v("extract\n"),a("ul",[a("li",[s._v("功能强大的解压插件,所有类型的文件解压一个命令 x 全搞定,再也不需要去记 tar 后面到底是哪几个参数了。")])])]),s._v(" "),a("li",[s._v("z\n"),a("ul",[a("li",[s._v("强大的目录自动跳转命令,会记忆你曾经进入过的目录,用模糊匹配快速进入你想要的目录。")])])]),s._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/zsh-users/zsh-syntax-highlighting",target:"_blank",rel:"noopener noreferrer"}},[a("code",[s._v("zsh-syntax-highlighting")]),a("OutboundLink")],1),s._v(" "),a("ul",[a("li",[s._v("这个插件会对终端命令高亮显示,比如正确的拼写会是绿色标识,否则是红色,另外对于一些 shell 输出语句也会有高亮显示,算是不错的辅助插件")]),s._v(" "),a("li",[s._v("安装,复制该命令:"),a("code",[s._v("git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-\\~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting")])]),s._v(" "),a("li",[s._v("编辑:"),a("code",[s._v("vim \\~/.zshrc")]),s._v(",找到这一行,后括号里面的后面添加:"),a("code",[s._v("plugins=( 前面的一些插件名称,换行,加上:zsh-syntax-highlighting)")]),s._v(" - 刷新下配置:"),a("code",[s._v("source \\~/.zshrc")])])])]),s._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/mfaerevaag/wd",target:"_blank",rel:"noopener noreferrer"}},[a("code",[s._v("wd")]),a("OutboundLink")],1),s._v(" "),a("ul",[a("li",[s._v("简单地讲就是给指定目录映射一个全局的名字,以后方便直接跳转到这个目录,比如:")]),s._v(" "),a("li",[s._v("编辑配置文件,添加上 wd 的名字:"),a("code",[s._v("vim /root/.zshrc")])]),s._v(" "),a("li",[s._v("我常去目录:"),a("strong",[s._v("/opt/setups")]),s._v(",每次进入该目录下都需要这样:"),a("code",[s._v("cd /opt/setups")])]),s._v(" "),a("li",[s._v("现在用 wd 给他映射一个快捷方式:"),a("code",[s._v("cd /opt/setups ; wd add setups")])]),s._v(" "),a("li",[s._v("以后我在任何目录下只要运行:"),a("code",[s._v("wd setups")]),s._v(" 就自动跑到 /opt/setups 目录下了")])])]),s._v(" "),a("li",[a("a",{attrs:{href:"https://github.com/wting/autojump",target:"_blank",rel:"noopener noreferrer"}},[a("code",[s._v("autojump")]),a("OutboundLink")],1),s._v(" "),a("ul",[a("li",[s._v("这个插件会记录你常去的那些目录,然后做一下权重记录,你可以用这个命令看到你的习惯:"),a("code",[s._v("j --stat")]),s._v(",如果这个里面有你的记录,那你就只要敲最后一个文件夹名字即可进入,比如我个人习惯的 program:"),a("code",[s._v("j program")]),s._v(",就可以直接到:"),a("code",[s._v("/usr/program")])]),s._v(" "),a("li",[s._v("插件下载:"),a("code",[s._v("wget https://github.com/downloads/wting/autojump/autojump_v21.1.2.tar.gz")])]),s._v(" "),a("li",[s._v("解压:"),a("code",[s._v("tar zxvf autojump_v21.1.2.tar.gz")])]),s._v(" "),a("li",[s._v("进入解压后目录并安装:"),a("code",[s._v("cd autojump_v21.1.2/ ; ./install.sh")])]),s._v(" "),a("li",[s._v("再执行下这个:"),a("code",[s._v("source /etc/profile.d/autojump.sh")])]),s._v(" "),a("li",[s._v("编辑配置文件,添加上 autojump 的名字:"),a("code",[s._v("vim /root/.zshrc")])])])])])])]),s._v(" "),a("h4",{attrs:{id:"_2-4-2-主题"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_2-4-2-主题"}},[s._v("#")]),s._v(" 2.4.2. 主题")]),s._v(" "),a("blockquote",[a("p",[s._v("oh-my-zsh 主题太多,不一一列举,请参考:"),a("a",{attrs:{href:"https://github.com/robbyrussell/oh-my-zsh/wiki/Themes",target:"_blank",rel:"noopener noreferrer"}},[s._v("oh-my-zsh 主题列表"),a("OutboundLink")],1)])]),s._v(" "),a("ul",[a("li",[s._v("查看 oh-my-zsh 主题数:"),a("code",[s._v('ls -l /root/.oh-my-zsh/themes |grep "^-"|wc -l')])]),s._v(" "),a("li",[s._v("个人比较推荐的是(排名有先后):\n"),a("ul",[a("li",[a("code",[s._v("ys")])]),s._v(" "),a("li",[a("code",[s._v("agnoster")])]),s._v(" "),a("li",[a("code",[s._v("avit")])]),s._v(" "),a("li",[a("code",[s._v("blinks")])])])]),s._v(" "),a("li",[s._v("编辑配置文件:"),a("code",[s._v("vim /root/.zshrc")])]),s._v(" "),a("li",[s._v("配置好新主题需要重新连接 shell 才能看到效果")])]),s._v(" "),a("p",[s._v("zsh 效果如下:")]),s._v(" "),a("p",[a("img",{attrs:{src:"https://cloud.githubusercontent.com/assets/2618447/6316862/70f58fb6-ba03-11e4-82c9-c083bf9a6574.png",alt:"img"}})]),s._v(" "),a("h2",{attrs:{id:"_3-快捷键"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_3-快捷键"}},[s._v("#")]),s._v(" 3. 快捷键")]),s._v(" "),a("ul",[a("li",[s._v("呃,这个其实可以不用讲的,你自己用的时候你自己会发现的,各种便捷,特别是用 Tab 多的人一定会有各种惊喜的。")]),s._v(" "),a("li",[s._v("使用 ctrl-r 来搜索命令历史记录。按完此快捷键后,可以输入关键命令词语,如果历史记录有含有此词语会显示出来。")]),s._v(" "),a("li",[s._v("命令别名: - 在命令行中输入 alias 可以查看已经有的命令别名 - 自己新增一些别名,编辑文件:"),a("code",[s._v("vim \\~/.zshrc")]),s._v(",在文件加入下面格式的命令,比如以下是网友提供的一些思路:")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("cls")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'clear'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("ll")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'ls -l'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("la")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'ls -a'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("grep")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"grep --color=auto"')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("html")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在命令行直接输入后缀为 html 的文件名,会在 Vim 中打开")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("rb")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在命令行直接输入 ruby 文件,会在 Vim 中打开")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("py")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在命令行直接输入 python 文件,会用 vim 中打开,以下类似")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("js")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("c")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("java")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("txt")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'vim'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("gz")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'tar -xzvf'")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 在命令行直接输入后缀为 gz 的文件名,会自动解压打开")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("tgz")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'tar -xzvf'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("zip")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'unzip'")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("alias")]),s._v(" -s "),a("span",{pre:!0,attrs:{class:"token assign-left variable"}},[s._v("bz2")]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'tar -xjvf'")]),s._v("\n")])])]),a("h2",{attrs:{id:"_4-参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#_4-参考资料"}},[s._v("#")]),s._v(" 4. 参考资料")]),s._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/robbyrussell/oh-my-zsh",target:"_blank",rel:"noopener noreferrer"}},[s._v("oh-my-zsh Github"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/48.98c78321.js b/assets/js/48.98c78321.js new file mode 100644 index 0000000..8572453 --- /dev/null +++ b/assets/js/48.98c78321.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[48],{436:function(t,r,n){"use strict";n.r(r);var o=n(15),e=Object(o.a)({},(function(){var t=this,r=t.$createElement,n=t._self._c||r;return n("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[n("h1",{attrs:{id:"软件安装配置"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#软件安装配置"}},[t._v("#")]),t._v(" 软件安装配置")]),t._v(" "),n("h2",{attrs:{id:"📖-内容"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#📖-内容"}},[t._v("#")]),t._v(" 📖 内容")]),t._v(" "),n("ul",[n("li",[t._v("开发环境\n"),n("ul",[n("li",[n("RouterLink",{attrs:{to:"/linux/soft/jdk-install.html"}},[t._v("JDK 安装")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/maven-install.html"}},[t._v("Maven 安装")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/nodejs-install.html"}},[t._v("Nodejs 安装")])],1)])]),t._v(" "),n("li",[t._v("开发工具\n"),n("ul",[n("li",[n("RouterLink",{attrs:{to:"/linux/soft/nexus-ops.html"}},[t._v("Nexus 运维")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/gitlab-ops.html"}},[t._v("Gitlab 运维")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/jenkins-ops.html"}},[t._v("Jenkins 运维")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/svn-ops.html"}},[t._v("Svn 运维")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/yapi-ops.html"}},[t._v("YApi 运维")])],1)])]),t._v(" "),n("li",[t._v("中间件服务\n"),n("ul",[n("li",[n("a",{attrs:{href:"elastic"}},[t._v("Elastic 运维")])]),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/rocketmq-install.html"}},[t._v("RocketMQ 运维")])],1),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/nacos-install.html"}},[t._v("Nacos 运维")])],1)])]),t._v(" "),n("li",[t._v("服务器\n"),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/dunwu/nginx-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nginx 教程"),n("OutboundLink")],1),t._v(" 📚")]),t._v(" "),n("li",[n("RouterLink",{attrs:{to:"/linux/soft/tomcat-install.html"}},[t._v("Tomcat 运维")])],1)])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://github.com/dunwu/db-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据库"),n("OutboundLink")],1),t._v(" 📚\n"),n("ul",[n("li",[n("a",{attrs:{href:"https://github.com/dunwu/db-tutorial/blob/master/docs/sql/mysql/mysql-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Mysql 运维"),n("OutboundLink")],1)]),t._v(" "),n("li",[n("a",{attrs:{href:"https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Redis 运维"),n("OutboundLink")],1)])])]),t._v(" "),n("li",[t._v("大数据服务\n"),n("ul",[n("li",[n("RouterLink",{attrs:{to:"/linux/soft/kafka-install.html"}},[t._v("Kafka 运维")])],1),t._v(" "),n("li",[n("a",{attrs:{href:"https://github.com/dunwu/javatech/blob/master/docs/technology/monitor/zookeeper-ops.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Zookeeper 运维"),n("OutboundLink")],1)])])])]),t._v(" "),n("h2",{attrs:{id:"🚪-传送门"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#🚪-传送门"}},[t._v("#")]),t._v(" 🚪 传送门")]),t._v(" "),n("p",[t._v("◾ 🏠 "),n("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("DB-TUTORIAL 首页"),n("OutboundLink")],1),t._v(" ◾ 🎯 "),n("a",{attrs:{href:"https://github.com/dunwu/blog",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的博客"),n("OutboundLink")],1),t._v(" ◾")])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/49.a7c3afed.js b/assets/js/49.a7c3afed.js new file mode 100644 index 0000000..cf020b5 --- /dev/null +++ b/assets/js/49.a7c3afed.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[49],{437:function(t,o,l){"use strict";l.r(o);var a=l(15),e=Object(a.a)({},(function(){var t=this,o=t.$createElement,l=t._self._c||o;return l("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[l("h1",{attrs:{id:"apollo"}},[l("a",{staticClass:"header-anchor",attrs:{href:"#apollo"}},[t._v("#")]),t._v(" Apollo")]),t._v(" "),l("blockquote",[l("p",[t._v("Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。")])]),t._v(" "),l("p",[t._v("官方 Github:https://github.com/ctripcorp/apollo")]),t._v(" "),l("p",[t._v("由于官方示例不能直接使用,所以我 Fork 后,略作修改:https://github.com/dunwu/apollo")])])}),[],!1,null,null,null);o.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/5.cb43ecfb.js b/assets/js/5.cb43ecfb.js new file mode 100644 index 0000000..742018a --- /dev/null +++ b/assets/js/5.cb43ecfb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{348:function(t,e,n){},379:function(t,e,n){"use strict";n(348)},394:function(t,e,n){"use strict";n.r(e);var o=n(32),a=n(0),u={"/":{message:"New content is available.",buttonText:"Refresh"},"/zh/":{message:"发现新内容可用",buttonText:"刷新"},"/ru/":{message:"Доступен новый контент.",buttonText:"Обновить"},"/uk/":{message:"Доступний новий контент.",buttonText:"Оновити"},"/ja/":{message:"新しいコンテンツがあります。",buttonText:"更新する"},"/es/":{message:"Hay nuevo contenido disponible.",buttonText:"Actualizar"}},s={name:"SWUpdatePopup",data:function(){return{rawPopupConfig:!0,updateEvent:null}},computed:{popupConfig:function(){return Object(a.g)(this,this.rawPopupConfig)},enabled:function(){return Boolean(this.popupConfig&&this.updateEvent)},message:function(){var t=this.popupConfig;return t&&t.message||u["/"].message},buttonText:function(){var t=this.popupConfig;return t&&t.buttonText||u["/"].buttonText}},created:function(){o.a.$on("sw-updated",this.onSWUpdated),this.rawPopupConfig=u},methods:{onSWUpdated:function(t){this.updateEvent=t},reload:function(){this.updateEvent&&(this.updateEvent.skipWaiting().then((function(){location.reload(!0)})),this.updateEvent=null)}}},i=(n(379),n(15)),p=Object(i.a)(s,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("transition",{attrs:{name:"sw-update-popup"}},[t._t("default",[t.enabled?n("div",{staticClass:"sw-update-popup"},[t._v("\n "+t._s(t.message)+"\n\n "),n("br"),t._v(" "),n("button",{on:{click:t.reload}},[t._v("\n "+t._s(t.buttonText)+"\n ")])]):t._e()],{reload:t.reload,enabled:t.enabled,message:t.message,buttonText:t.buttonText})],2)}),[],!1,null,"fec8b358",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/50.22d8c542.js b/assets/js/50.22d8c542.js new file mode 100644 index 0000000..93d5ff0 --- /dev/null +++ b/assets/js/50.22d8c542.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[50],{438:function(t,e,r){"use strict";r.r(e);var a=r(15),s=Object(a.a)({},(function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"elastic-技术栈"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#elastic-技术栈"}},[t._v("#")]),t._v(" Elastic 技术栈")]),t._v(" "),r("blockquote",[r("p",[r("strong",[t._v("Elastic 技术栈通常被用来作为日志中心。")])]),t._v(" "),r("p",[t._v("ELK 是 elastic 公司旗下三款产品 "),r("a",{attrs:{href:"https://www.elastic.co/products/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),r("OutboundLink")],1),t._v(" 、"),r("a",{attrs:{href:"https://www.elastic.co/products/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash"),r("OutboundLink")],1),t._v(" 、"),r("a",{attrs:{href:"https://www.elastic.co/products/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kibana"),r("OutboundLink")],1),t._v(" 的首字母组合。")]),t._v(" "),r("p",[r("a",{attrs:{href:"https://www.elastic.co/products/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),r("OutboundLink")],1),t._v(" 是一个基于 "),r("a",{attrs:{href:"http://lucene.apache.org/core/documentation.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Lucene"),r("OutboundLink")],1),t._v(" 构建的开源,分布式,RESTful 搜索引擎。")]),t._v(" "),r("p",[r("a",{attrs:{href:"https://www.elastic.co/products/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash"),r("OutboundLink")],1),t._v(" 传输和处理你的日志、事务或其他数据。")]),t._v(" "),r("p",[r("a",{attrs:{href:"https://www.elastic.co/products/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kibana"),r("OutboundLink")],1),t._v(" 将 Elasticsearch 的数据分析并渲染为可视化的报表。")]),t._v(" "),r("p",[t._v("Elastic 技术栈,在 ELK 的基础上扩展了一些新的产品,如:"),r("a",{attrs:{href:"https://www.elastic.co/products/beats",target:"_blank",rel:"noopener noreferrer"}},[t._v("Beats"),r("OutboundLink")],1),t._v(" 、"),r("a",{attrs:{href:"https://www.elastic.co/products/x-pack",target:"_blank",rel:"noopener noreferrer"}},[t._v("X-Pack"),r("OutboundLink")],1),t._v(" 。")])]),t._v(" "),r("h2",{attrs:{id:"目录"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#目录"}},[t._v("#")]),t._v(" 目录")]),t._v(" "),r("p",[r("RouterLink",{attrs:{to:"/linux/soft/elastic/elastic-quickstart.html"}},[t._v("Elastic 技术栈之入门指南")])],1),t._v(" "),r("p",[r("RouterLink",{attrs:{to:"/linux/soft/elastic/elastic-logstash.html"}},[t._v("Elastic 技术栈之 Logstash 基础")])],1),t._v(" "),r("h2",{attrs:{id:"资源"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#资源"}},[t._v("#")]),t._v(" 资源")]),t._v(" "),r("p",[r("strong",[t._v("官方资源")])]),t._v(" "),r("p",[r("a",{attrs:{href:"https://www.elastic.co/guide/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Elastic 官方文档"),r("OutboundLink")],1)]),t._v(" "),r("p",[r("strong",[t._v("第三方工具")])]),t._v(" "),r("p",[r("a",{attrs:{href:"https://github.com/logstash/logstash-logback-encoder",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash-logback-encoder"),r("OutboundLink")],1)]),t._v(" "),r("p",[r("strong",[t._v("教程")])]),t._v(" "),r("p",[r("a",{attrs:{href:"https://es.xiaoleilu.com/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Elasticsearch 权威指南(中文版)"),r("OutboundLink")],1)]),t._v(" "),r("p",[r("a",{attrs:{href:"https://github.com/chenryn/logstash-best-practice-cn",target:"_blank",rel:"noopener noreferrer"}},[t._v("ELK Stack权威指南"),r("OutboundLink")],1)]),t._v(" "),r("p",[r("strong",[t._v("博文")])]),t._v(" "),r("p",[r("a",{attrs:{href:"https://www.cnblogs.com/xing901022/p/4704319.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Elasticsearch+Logstash+Kibana教程"),r("OutboundLink")],1)]),t._v(" "),r("p",[r("a",{attrs:{href:"https://github.com/judasn/Linux-Tutorial/blob/master/ELK-Install-And-Settings.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("ELK(Elasticsearch、Logstash、Kibana)安装和配置"),r("OutboundLink")],1)])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/51.28055fcd.js b/assets/js/51.28055fcd.js new file mode 100644 index 0000000..83d5e48 --- /dev/null +++ b/assets/js/51.28055fcd.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[51],{439:function(t,a,e){"use strict";e.r(a);var s=e(15),n=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"elastic-技术栈之-filebeat"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#elastic-技术栈之-filebeat"}},[t._v("#")]),t._v(" Elastic 技术栈之 Filebeat")]),t._v(" "),e("h2",{attrs:{id:"简介"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#简介"}},[t._v("#")]),t._v(" 简介")]),t._v(" "),e("p",[t._v("Beats 是安装在服务器上的数据中转代理。")]),t._v(" "),e("p",[t._v("Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash 。")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://www.elastic.co/guide/en/beats/libbeat/current/images/beats-platform.png",alt:"img"}})]),t._v(" "),e("p",[t._v("Beats 有多种类型,可以根据实际应用需要选择合适的类型。")]),t._v(" "),e("p",[t._v("常用的类型有:")]),t._v(" "),e("ul",[e("li",[t._v("**Packetbeat:**网络数据包分析器,提供有关您的应用程序服务器之间交换的事务的信息。")]),t._v(" "),e("li",[t._v("**Filebeat:**从您的服务器发送日志文件。")]),t._v(" "),e("li",[t._v("**Metricbeat:**是一个服务器监视代理程序,它定期从服务器上运行的操作系统和服务收集指标。")]),t._v(" "),e("li",[t._v("**Winlogbeat:**提供Windows事件日志。")])]),t._v(" "),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多 Beats 类型可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/libbeat/current/community-beats.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("community-beats"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("strong",[t._v("说明")])]),t._v(" "),e("p",[t._v("由于本人工作中只应用了 FileBeat,所以后面内容仅介绍 FileBeat 。")])]),t._v(" "),e("h3",{attrs:{id:"filebeat-的作用"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#filebeat-的作用"}},[t._v("#")]),t._v(" FileBeat 的作用")]),t._v(" "),e("p",[t._v("相比 Logstash,FileBeat 更加轻量化。")]),t._v(" "),e("p",[t._v("在任何环境下,应用程序都有停机的可能性。 Filebeat 读取并转发日志行,如果中断,则会记住所有事件恢复联机状态时所在位置。")]),t._v(" "),e("p",[t._v("Filebeat带有内部模块(auditd,Apache,Nginx,System和MySQL),可通过一个指定命令来简化通用日志格式的收集,解析和可视化。")]),t._v(" "),e("p",[t._v("FileBeat 不会让你的管道超负荷。FileBeat 如果是向 Logstash 传输数据,当 Logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决,FileBeat 将恢复到原来的速度并继续传播。")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://www.elastic.co/guide/en/beats/filebeat/current/images/filebeat.png",alt:"img"}})]),t._v(" "),e("h2",{attrs:{id:"安装"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[t._v("#")]),t._v(" 安装")]),t._v(" "),e("p",[t._v("Unix / Linux 系统建议使用下面方式安装,因为比较通用。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.1-linux-x86_64.tar.gz\ntar -zxf filebeat-6.1.1-linux-x86_64.tar.gz\n")])])]),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("filebeat-installation"),e("OutboundLink")],1)])]),t._v(" "),e("h2",{attrs:{id:"配置"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#配置"}},[t._v("#")]),t._v(" 配置")]),t._v(" "),e("h3",{attrs:{id:"配置文件"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#配置文件"}},[t._v("#")]),t._v(" 配置文件")]),t._v(" "),e("p",[t._v("首先,需要知道的是:"),e("code",[t._v("filebeat.yml")]),t._v(" 是 filebeat 的配置文件。配置文件的路径会因为你安装方式的不同而变化。")]),t._v(" "),e("p",[t._v("Beat 所有系列产品的配置文件都基于 "),e("a",{attrs:{href:"http://www.yaml.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("YAML"),e("OutboundLink")],1),t._v(" 格式,FileBeat 当然也不例外。")]),t._v(" "),e("p",[t._v("filebeat.yml 部分配置示例:")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("filebeat")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("prospectors")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" log\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("paths")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" /var/log/"),e("span",{pre:!0,attrs:{class:"token important"}},[t._v("*.log")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("multiline")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("pattern")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("'^['")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("match")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" after\n")])])]),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多 filebeat 配置内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/configuring-howto-filebeat.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("配置 filebeat"),e("OutboundLink")],1)]),t._v(" "),e("p",[t._v("更多 filebeat.yml 文件格式内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/libbeat/6.1/config-file-format.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("filebeat.yml 文件格式"),e("OutboundLink")],1)])]),t._v(" "),e("h3",{attrs:{id:"重要配置项"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#重要配置项"}},[t._v("#")]),t._v(" 重要配置项")]),t._v(" "),e("h4",{attrs:{id:"filebeat-prospectors"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#filebeat-prospectors"}},[t._v("#")]),t._v(" filebeat.prospectors")]),t._v(" "),e("p",[t._v("(文件监视器)用于指定需要关注的文件。")]),t._v(" "),e("p",[e("strong",[t._v("示例")])]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("filebeat.prospectors")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" log\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("enabled")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("paths")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" /var/log/"),e("span",{pre:!0,attrs:{class:"token important"}},[t._v("*.log")]),t._v("\n")])])]),e("h4",{attrs:{id:"output-elasticsearch"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#output-elasticsearch"}},[t._v("#")]),t._v(" output.elasticsearch")]),t._v(" "),e("p",[t._v("如果你希望使用 filebeat 直接向 elasticsearch 输出数据,需要配置 output.elasticsearch 。")]),t._v(" "),e("p",[e("strong",[t._v("示例")])]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("output.elasticsearch")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"192.168.1.42:9200"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),e("h4",{attrs:{id:"output-logstash"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#output-logstash"}},[t._v("#")]),t._v(" output.logstash")]),t._v(" "),e("p",[t._v("如果你希望使用 filebeat 向 logstash输出数据,然后由 logstash 再向elasticsearch 输出数据,需要配置 output.logstash。")]),t._v(" "),e("blockquote",[e("p",[e("strong",[t._v("注意")])]),t._v(" "),e("p",[t._v("相比于向 elasticsearch 输出数据,个人更推荐向 logstash 输出数据。")]),t._v(" "),e("p",[t._v("因为 logstash 和 filebeat 一起工作时,如果 logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决,FileBeat 将恢复到原来的速度并继续传播。这样,可以减少管道超负荷的情况。")])]),t._v(" "),e("p",[e("strong",[t._v("示例")])]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("output.logstash")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1:5044"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n")])])]),e("p",[t._v("此外,还需要在 logstash 的配置文件(如 logstash.conf)中指定 beats input 插件:")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[t._v("input "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n beats "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n port ="),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(" 5044 "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 此端口需要与 filebeat.yml 中的端口相同")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# The filter part of this file is commented out to indicate that it is")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# optional.")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# filter {")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("#")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# }")]),t._v("\n\noutput "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n elasticsearch "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n hosts ="),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(' "localhost'),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v('9200"\n manage_template ='),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(" false\n index ="),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(' "%'),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("@metadata"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("beat"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("%"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("@metadata"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("version"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("%"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("+YYYY.MM.dd"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v('" \n document_type ='),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),t._v(' "%'),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("@metadata"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("type"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v('" \n '),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),e("h4",{attrs:{id:"setup-kibana"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#setup-kibana"}},[t._v("#")]),t._v(" setup.kibana")]),t._v(" "),e("p",[t._v("如果打算使用 Filebeat 提供的 Kibana 仪表板,需要配置 setup.kibana 。")]),t._v(" "),e("p",[e("strong",[t._v("示例")])]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("setup.kibana")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("host")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"localhost:5601"')]),t._v("\n")])])]),e("h4",{attrs:{id:"setup-template-settings"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#setup-template-settings"}},[t._v("#")]),t._v(" setup.template.settings")]),t._v(" "),e("p",[t._v("在 Elasticsearch 中,"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/elasticsearch/reference/6.1/indices-templates.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("索引模板"),e("OutboundLink")],1),t._v("用于定义设置和映射,以确定如何分析字段。")]),t._v(" "),e("p",[t._v("在 Filebeat 中,setup.template.settings 用于配置索引模板。")]),t._v(" "),e("p",[t._v("Filebeat 推荐的索引模板文件由 Filebeat 软件包安装。如果您接受 filebeat.yml 配置文件中的默认配置,Filebeat在成功连接到 Elasticsearch 后自动加载模板。")]),t._v(" "),e("p",[t._v("您可以通过在 Filebeat 配置文件中配置模板加载选项来禁用自动模板加载,或加载自己的模板。您还可以设置选项来更改索引和索引模板的名称。")]),t._v(" "),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-template.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("filebeat-template"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("strong",[t._v("说明")])]),t._v(" "),e("p",[t._v("如无必要,使用 Filebeat 配置文件中的默认索引模板即可。")])]),t._v(" "),e("h4",{attrs:{id:"setup-dashboards"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#setup-dashboards"}},[t._v("#")]),t._v(" setup.dashboards")]),t._v(" "),e("p",[t._v("Filebeat 附带了示例 Kibana 仪表板。在使用仪表板之前,您需要创建索引模式 "),e("code",[t._v("filebeat- *")]),t._v(",并将仪表板加载到Kibana 中。为此,您可以运行 "),e("code",[t._v("setup")]),t._v(" 命令或在 "),e("code",[t._v("filebeat.yml")]),t._v(" 配置文件中配置仪表板加载。")]),t._v(" "),e("p",[t._v("为了在 Kibana 中加载 Filebeat 的仪表盘,需要在 "),e("code",[t._v("filebeat.yml")]),t._v(" 配置中启动开关:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("setup.dashboards.enabled: true\n")])])]),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/configuration-dashboards.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("configuration-dashboards"),e("OutboundLink")],1)])]),t._v(" "),e("h2",{attrs:{id:"命令"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#命令"}},[t._v("#")]),t._v(" 命令")]),t._v(" "),e("p",[t._v("filebeat 提供了一系列命令来完成各种功能。")]),t._v(" "),e("p",[t._v("执行命令方式:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("./filebeat COMMAND\n")])])]),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多内容可以参考:"),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/command-line-options.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("command-line-options"),e("OutboundLink")],1)]),t._v(" "),e("p",[e("strong",[t._v("说明")])]),t._v(" "),e("p",[t._v("个人认为命令行没有必要一一掌握,因为绝大部分功能都可以通过配置来完成。且通过命令行指定功能这种方式要求每次输入同样参数,不利于固化启动方式。")]),t._v(" "),e("p",[t._v("最重要的当然是启动命令 run 了。")]),t._v(" "),e("p",[e("strong",[t._v("示例")]),t._v(" 指定配置文件启动")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("./filebeat run -e -c filebeat.yml -d "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"publish"')]),t._v("\n./filebeat -e -c filebeat.yml -d "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"publish"')]),t._v(" "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# run 可以省略")]),t._v("\n")])])])]),t._v(" "),e("h2",{attrs:{id:"模块"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#模块"}},[t._v("#")]),t._v(" 模块")]),t._v(" "),e("p",[t._v("Filebeat 提供了一套预构建的模块,让您可以快速实施和部署日志监视解决方案,并附带示例仪表板和数据可视化。这些模块支持常见的日志格式,例如Nginx,Apache2和MySQL 等。")]),t._v(" "),e("h3",{attrs:{id:"运行模块的步骤"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#运行模块的步骤"}},[t._v("#")]),t._v(" 运行模块的步骤")]),t._v(" "),e("ul",[e("li",[t._v("配置 elasticsearch 和 kibana")])]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v('output.elasticsearch:\n hosts: ["myEShost:9200"]\n username: "elastic"\n password: "elastic"\nsetup.kibana:\n host: "mykibanahost:5601"\n username: "elastic" \n password: "elastic\n')])])]),e("blockquote",[e("p",[t._v("username 和 password 是可选的,如果不需要认证则不填。")])]),t._v(" "),e("ul",[e("li",[t._v("初始化环境")])]),t._v(" "),e("p",[t._v("执行下面命令,filebeat 会加载推荐索引模板。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("./filebeat setup -e\n")])])]),e("ul",[e("li",[t._v("指定模块")])]),t._v(" "),e("p",[t._v("执行下面命令,指定希望加载的模块。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("./filebeat -e --modules system,nginx,mysql\n")])])]),e("blockquote",[e("p",[e("strong",[t._v("参考")])]),t._v(" "),e("p",[t._v("更多内容可以参考: "),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-modules.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("配置 filebeat 模块"),e("OutboundLink")],1),t._v(" | "),e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("filebeat 支持模块"),e("OutboundLink")],1)])]),t._v(" "),e("h2",{attrs:{id:"原理"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#原理"}},[t._v("#")]),t._v(" 原理")]),t._v(" "),e("p",[t._v("Filebeat 有两个主要组件:")]),t._v(" "),e("p",[t._v("harvester:负责读取一个文件的内容。它会逐行读取文件内容,并将内容发送到输出目的地。")]),t._v(" "),e("p",[t._v("prospector:负责管理 harvester 并找到所有需要读取的文件源。比如类型是日志,prospector 就会遍历制定路径下的所有匹配要求的文件。")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("filebeat.prospectors")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" log\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("paths")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" /var/log/"),e("span",{pre:!0,attrs:{class:"token important"}},[t._v("*.log")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" /var/path2/"),e("span",{pre:!0,attrs:{class:"token important"}},[t._v("*.log")]),t._v("\n")])])]),e("p",[t._v("Filebeat保持每个文件的状态,并经常刷新注册表文件中的磁盘状态。状态用于记住 harvester 正在读取的最后偏移量,并确保发送所有日志行。")]),t._v(" "),e("p",[t._v("Filebeat 将每个事件的传递状态存储在注册表文件中。所以它能保证事件至少传递一次到配置的输出,没有数据丢失。")]),t._v(" "),e("h2",{attrs:{id:"资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#资料"}},[t._v("#")]),t._v(" 资料")]),t._v(" "),e("p",[e("a",{attrs:{href:"https://www.elastic.co/guide/en/beats/libbeat/current/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Beats 官方文档"),e("OutboundLink")],1)])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/52.f8103df5.js b/assets/js/52.f8103df5.js new file mode 100644 index 0000000..4130208 --- /dev/null +++ b/assets/js/52.f8103df5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[52],{440:function(a,e,t){"use strict";t.r(e);var v=t(15),s=Object(v.a)({},(function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h1",{attrs:{id:"elastic-技术栈之-kibana"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#elastic-技术栈之-kibana"}},[a._v("#")]),a._v(" Elastic 技术栈之 Kibana")]),a._v(" "),t("h2",{attrs:{id:"discover"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#discover"}},[a._v("#")]),a._v(" Discover")]),a._v(" "),t("p",[a._v("单击侧面导航栏中的 "),t("code",[a._v("Discover")]),a._v(" ,可以显示 "),t("code",[a._v("Kibana")]),a._v(" 的数据查询功能功能。")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/current/images/tutorial-discover.png",alt:"img"}})]),a._v(" "),t("p",[a._v("在搜索栏中,您可以输入Elasticsearch查询条件来搜索您的数据。您可以在 "),t("code",[a._v("Discover")]),a._v(" 页面中浏览结果并在 "),t("code",[a._v("Visualize")]),a._v(" 页面中创建已保存搜索条件的可视化。")]),a._v(" "),t("p",[a._v("当前索引模式显示在查询栏下方。索引模式确定提交查询时搜索哪些索引。要搜索一组不同的索引,请从下拉菜单中选择不同的模式。要添加索引模式(index pattern),请转至 "),t("code",[a._v("Management/Kibana/Index Patterns")]),a._v(" 并单击 "),t("code",[a._v("Add New")]),a._v("。")]),a._v(" "),t("p",[a._v("您可以使用字段名称和您感兴趣的值构建搜索。对于数字字段,可以使用比较运算符,如大于(>),小于(<)或等于(=)。您可以将元素与逻辑运算符 "),t("code",[a._v("AND")]),a._v(","),t("code",[a._v("OR")]),a._v(" 和 "),t("code",[a._v("NOT")]),a._v(" 链接,全部使用大写。")]),a._v(" "),t("p",[a._v("默认情况下,每个匹配文档都显示所有字段。要选择要显示的文档字段,请将鼠标悬停在“可用字段”列表上,然后单击要包含的每个字段旁边的添加按钮。例如,如果只添加account_number,则显示将更改为包含五个帐号的简单列表:")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-discover-3.png",alt:"img"}})]),a._v(" "),t("h3",{attrs:{id:"查询语义"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#查询语义"}},[a._v("#")]),a._v(" 查询语义")]),a._v(" "),t("p",[a._v("kibana 的搜索栏遵循 "),t("a",{attrs:{href:"https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax",target:"_blank",rel:"noopener noreferrer"}},[a._v("query-string-syntax"),t("OutboundLink")],1),a._v(" 文档中所说明的查询语义。")]),a._v(" "),t("p",[a._v("这里说明一些最基本的查询语义。")]),a._v(" "),t("p",[a._v('查询字符串会被解析为一系列的术语和运算符。一个术语可以是一个单词(如:quick、brown)或用双引号包围的短语(如"quick brown")。')]),a._v(" "),t("p",[a._v("查询操作允许您自定义搜索 - 下面介绍了可用的选项。")]),a._v(" "),t("h4",{attrs:{id:"字段名称"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#字段名称"}},[a._v("#")]),a._v(" 字段名称")]),a._v(" "),t("p",[a._v("正如查询字符串查询中所述,将在搜索条件中搜索default_field,但可以在查询语法中指定其他字段:")]),a._v(" "),t("p",[a._v("例如:")]),a._v(" "),t("ul",[t("li",[a._v("查询 "),t("code",[a._v("status")]),a._v(" 字段中包含 "),t("code",[a._v("active")]),a._v(" 关键字")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("status:active\n")])])]),t("ul",[t("li",[t("code",[a._v("title")]),a._v(" 字段包含 "),t("code",[a._v("quick")]),a._v(" 或 "),t("code",[a._v("brown")]),a._v(" 关键字。如果您省略 "),t("code",[a._v("OR")]),a._v(" 运算符,则将使用默认运算符")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("title:(quick OR brown)\ntitle:(quick brown)\n")])])]),t("ul",[t("li",[a._v('author 字段查找精确的短语 "john smith",即精确查找。')])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v('author:"John Smith"\n')])])]),t("ul",[t("li",[a._v("任意字段 "),t("code",[a._v("book.title")]),a._v(","),t("code",[a._v("book.content")]),a._v(" 或 "),t("code",[a._v("book.date")]),a._v(" 都包含 "),t("code",[a._v("quick")]),a._v(" 或 "),t("code",[a._v("brown")]),a._v("(注意我们需要如何使用 "),t("code",[a._v("\\*")]),a._v(" 表示通配符)")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("book.\\*:(quick brown)\n")])])]),t("ul",[t("li",[a._v("title 字段包含任意非 null 值")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("_exists_:title\n")])])]),t("h4",{attrs:{id:"通配符"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#通配符"}},[a._v("#")]),a._v(" 通配符")]),a._v(" "),t("p",[a._v("ELK 提供了 ? 和 * 两个通配符。")]),a._v(" "),t("ul",[t("li",[t("code",[a._v("?")]),a._v(" 表示任意单个字符;")]),a._v(" "),t("li",[t("code",[a._v("*")]),a._v(" 表示任意零个或多个字符。")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("qu?ck bro*\n")])])]),t("blockquote",[t("p",[t("strong",[a._v("注意:通配符查询会使用大量的内存并且执行性能较为糟糕,所以请慎用。")]),a._v(" "),t("strong",[a._v("提示")]),a._v(":纯通配符 * 被写入 "),t("a",{attrs:{href:"https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("exsits"),t("OutboundLink")],1),a._v(" 查询,从而提高了查询效率。因此,通配符 "),t("code",[a._v("field:*")]),a._v(" 将匹配包含空值的文档,如:"),t("code",[a._v("{“field”:“”}")]),a._v(",但是如果字段丢失或显示将值置为null则不匹配,如:"),t("code",[a._v("“field”:null}")]),a._v(" "),t("strong",[a._v("提示")]),a._v(":在一个单词的开头(例如:"),t("code",[a._v("*ing")]),a._v(")使用通配符这种方式的查询量特别大,因为索引中的所有术语都需要检查,以防万一匹配。通过将 "),t("code",[a._v("allow_leading_wildcard")]),a._v(" 设置为 "),t("code",[a._v("false")]),a._v(",可以禁用。")])]),a._v(" "),t("h4",{attrs:{id:"正则表达式"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#正则表达式"}},[a._v("#")]),a._v(" 正则表达式")]),a._v(" "),t("p",[a._v("可以通过 "),t("code",[a._v("/")]),a._v(" 将正则表达式包裹在查询字符串中进行查询")]),a._v(" "),t("p",[a._v("例:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("name:/joh?n(ath[oa]n)/\n")])])]),t("p",[a._v("支持的正则表达式语义可以参考:"),t("a",{attrs:{href:"https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax",target:"_blank",rel:"noopener noreferrer"}},[a._v("Regular expression syntax"),t("OutboundLink")],1)]),a._v(" "),t("h4",{attrs:{id:"模糊查询"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#模糊查询"}},[a._v("#")]),a._v(" 模糊查询")]),a._v(" "),t("p",[a._v("我们可以使用 "),t("code",[a._v("~")]),a._v(" 运算符来进行模糊查询。")]),a._v(" "),t("p",[a._v("例:")]),a._v(" "),t("p",[a._v("假设我们实际想查询")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("quick brown forks\n")])])]),t("p",[a._v("但是,由于拼写错误,我们的查询关键字变成如下情况,依然可以查到想要的结果。")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("quikc\\~ brwn\\~ foks\\~\n")])])]),t("p",[a._v("这种模糊查询使用 Damerau-Levenshtein 距离来查找所有匹配最多两个更改的项。所谓的更改是指单个字符的插入,删除或替换,或者两个相邻字符的换位。")]),a._v(" "),t("p",[a._v("默认编辑距离为 "),t("code",[a._v("2")]),a._v(",但编辑距离为 "),t("code",[a._v("1")]),a._v(" 应足以捕捉所有人类拼写错误的80%。它可以被指定为:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("quikc\\~1\n")])])]),t("h4",{attrs:{id:"近似检索"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#近似检索"}},[a._v("#")]),a._v(" 近似检索")]),a._v(" "),t("p",[a._v("尽管短语查询(例如,"),t("code",[a._v("john smith")]),a._v(")期望所有的词条都是完全相同的顺序,但是近似查询允许指定的单词进一步分开或以不同的顺序排列。与模糊查询可以为单词中的字符指定最大编辑距离一样,近似搜索也允许我们指定短语中单词的最大编辑距离:")]),a._v(" "),t("p",[a._v("例")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v('"fox quick"\\~5\n')])])]),t("p",[a._v("字段中的文本越接近查询字符串中指定的原始顺序,该文档就越被认为是相关的。当与上面的示例查询相比时,短语 "),t("code",[a._v('"quick fox"')]),a._v(" 将被认为比 "),t("code",[a._v('"quick brown fox"')]),a._v(" 更近似查询条件。")]),a._v(" "),t("h4",{attrs:{id:"范围"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#范围"}},[a._v("#")]),a._v(" 范围")]),a._v(" "),t("p",[a._v("可以为日期,数字或字符串字段指定范围。闭区间范围用方括号 "),t("code",[a._v("[min TO max]")]),a._v(" 和开区间范围用花括号 "),t("code",[a._v("{min TO max}")]),a._v(" 来指定。")]),a._v(" "),t("p",[a._v("我们不妨来看一些示例。")]),a._v(" "),t("ul",[t("li",[a._v("2012 年的所有日子")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("date:[2012-01-01 TO 2012-12-31]\n")])])]),t("ul",[t("li",[a._v("数字 1 到 5")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("count:[1 TO 5]\n")])])]),t("ul",[t("li",[a._v("在 "),t("code",[a._v("alpha")]),a._v(" 和 "),t("code",[a._v("omega")]),a._v(" 之间的标签,不包括 "),t("code",[a._v("alpha")]),a._v(" 和 "),t("code",[a._v("omega")])])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("tag:{alpha TO omega}\n")])])]),t("ul",[t("li",[a._v("10 以上的数字")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("count:[10 TO *]\n")])])]),t("ul",[t("li",[a._v("2012 年以前的所有日期")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("date:{* TO 2012-01-01}\n")])])]),t("p",[a._v("此外,开区间和闭区间也可以组合使用")]),a._v(" "),t("ul",[t("li",[a._v("数组 1 到 5,但不包括 5")])]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("count:[1 TO 5}\n")])])]),t("p",[a._v("一边无界的范围也可以使用以下语法:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("age:>10\nage:>=10\nage:<10\nage:<=10\n")])])]),t("p",[a._v("当然,你也可以使用 AND 运算符来得到连个查询结果的交集")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("age:(>=10 AND <20)\nage:(+>=10 +<20)\n")])])]),t("h4",{attrs:{id:"boosting"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#boosting"}},[a._v("#")]),a._v(" Boosting")]),a._v(" "),t("p",[a._v("使用操作符 "),t("code",[a._v("^")]),a._v(" 使一个术语比另一个术语更相关。例如,如果我们想查找所有有关狐狸的文档,但我们对狐狸特别感兴趣:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("quick^2 fox\n")])])]),t("p",[a._v("默认提升值是1,但可以是任何正浮点数。 0到1之间的提升减少了相关性。")]),a._v(" "),t("p",[a._v("增强也可以应用于短语或组:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v('"john smith"^2 (foo bar)^4\n')])])]),t("h4",{attrs:{id:"布尔操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#布尔操作"}},[a._v("#")]),a._v(" 布尔操作")]),a._v(" "),t("p",[a._v("默认情况下,只要一个词匹配,所有词都是可选的。搜索 "),t("code",[a._v("foo bar baz")]),a._v(" 将查找包含 "),t("code",[a._v("foo")]),a._v(" 或 "),t("code",[a._v("bar")]),a._v(" 或 "),t("code",[a._v("baz")]),a._v(" 中的一个或多个的任何文档。我们已经讨论了上面的"),t("code",[a._v("default_operator")]),a._v(",它允许你强制要求所有的项,但也有布尔运算符可以在查询字符串本身中使用,以提供更多的控制。")]),a._v(" "),t("p",[a._v("首选的操作符是 "),t("code",[a._v("+")]),a._v("(此术语必须存在)和 "),t("code",[a._v("-")]),a._v(" (此术语不得存在)。所有其他条款是可选的。例如,这个查询:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("quick brown +fox -news\n")])])]),t("p",[a._v("这条查询意味着:")]),a._v(" "),t("ul",[t("li",[a._v("fox 必须存在")]),a._v(" "),t("li",[a._v("news 必须不存在")]),a._v(" "),t("li",[a._v("quick 和 brown 是可有可无的")])]),a._v(" "),t("p",[a._v("熟悉的运算符 "),t("code",[a._v("AND")]),a._v(","),t("code",[a._v("OR")]),a._v(" 和 "),t("code",[a._v("NOT")]),a._v("(也写成 "),t("code",[a._v("&&")]),a._v(","),t("code",[a._v("||")]),a._v(" 和 "),t("code",[a._v("!")]),a._v(")也被支持。然而,这些操作符有一定的优先级:"),t("code",[a._v("NOT")]),a._v(" 优先于 "),t("code",[a._v("AND")]),a._v(","),t("code",[a._v("AND")]),a._v(" 优先于 "),t("code",[a._v("OR")]),a._v("。虽然 "),t("code",[a._v("+")]),a._v(" 和 "),t("code",[a._v("-")]),a._v(" 仅影响运算符右侧的术语,但 "),t("code",[a._v("AND")]),a._v(" 和 "),t("code",[a._v("OR")]),a._v(" 会影响左侧和右侧的术语。")]),a._v(" "),t("h4",{attrs:{id:"分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组"}},[a._v("#")]),a._v(" 分组")]),a._v(" "),t("p",[a._v("多个术语或子句可以用圆括号组合在一起,形成子查询")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("(quick OR brown) AND fox\n")])])]),t("p",[a._v("可以使用组来定位特定的字段,或者增强子查询的结果:")]),a._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("status:(active OR pending) title:(full text search)^2\n")])])]),t("h4",{attrs:{id:"保留字"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#保留字"}},[a._v("#")]),a._v(" 保留字")]),a._v(" "),t("p",[a._v("如果你需要使用任何在你的查询本身中作为操作符的字符(而不是作为操作符),那么你应该用一个反斜杠来转义它们。例如,要搜索(1 + 1)= 2,您需要将查询写为 "),t("code",[a._v("\\(1\\+1\\)\\=2")])]),a._v(" "),t("p",[a._v("保留字符是:"),t("code",[a._v('+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \\ /')])]),a._v(" "),t("p",[a._v("无法正确地转义这些特殊字符可能会导致语法错误,从而阻止您的查询运行。")]),a._v(" "),t("h4",{attrs:{id:"空查询"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#空查询"}},[a._v("#")]),a._v(" 空查询")]),a._v(" "),t("p",[a._v("如果查询字符串为空或仅包含空格,则查询将生成一个空的结果集。")]),a._v(" "),t("h2",{attrs:{id:"visualize"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#visualize"}},[a._v("#")]),a._v(" Visualize")]),a._v(" "),t("p",[a._v("要想使用可视化的方式展示您的数据,请单击侧面导航栏中的 "),t("code",[a._v("Visualize")]),a._v("。")]),a._v(" "),t("p",[a._v("Visualize工具使您能够以多种方式(如饼图、柱状图、曲线图、分布图等)查看数据。要开始使用,请点击蓝色的 "),t("code",[a._v("Create a visualization")]),a._v(" 或 "),t("code",[a._v("+")]),a._v(" 按钮。")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png",alt:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png"}})]),a._v(" "),t("p",[a._v("有许多可视化类型可供选择。")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png",alt:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png"}})]),a._v(" "),t("p",[a._v("下面,我们来看创建几个图标示例:")]),a._v(" "),t("h3",{attrs:{id:"pie"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#pie"}},[a._v("#")]),a._v(" Pie")]),a._v(" "),t("p",[a._v("您可以从保存的搜索中构建可视化文件,也可以输入新的搜索条件。要输入新的搜索条件,首先需要选择一个索引模式来指定要搜索的索引。")]),a._v(" "),t("p",[a._v("默认搜索匹配所有文档。最初,一个“切片”包含整个饼图:")]),a._v(" "),t("p",[t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png",alt:"https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png"}})]),a._v(" "),t("p",[a._v("要指定在图表中展示哪些数据,请使用Elasticsearch存储桶聚合。分组汇总只是将与您的搜索条件相匹配的文档分类到不同的分类中,也称为分组。")]),a._v(" "),t("p",[a._v("为每个范围定义一个存储桶:")]),a._v(" "),t("ol",[t("li",[a._v("单击 "),t("code",[a._v("Split Slices")]),a._v("。")]),a._v(" "),t("li",[a._v("在 "),t("code",[a._v("Aggregation")]),a._v(" 列表中选择 "),t("code",[a._v("Terms")]),a._v("。"),t("em",[a._v("注意:这里的 Terms 是 Elk 采集数据时定义好的字段或标签。")])]),a._v(" "),t("li",[a._v("在 "),t("code",[a._v("Field")]),a._v(" 列表中选择 "),t("code",[a._v("level.keyword")]),a._v("。")]),a._v(" "),t("li",[a._v("点击 "),t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png",alt:"images/apply-changes-button.png"}}),a._v(" 按钮来更新图表。")])]),a._v(" "),t("p",[t("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-7fb2042dc6d59520.png",alt:"image.png"}})]),a._v(" "),t("p",[a._v("完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 "),t("code",[a._v("Save")]),a._v(" 按钮。")]),a._v(" "),t("h3",{attrs:{id:"vertical-bar"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#vertical-bar"}},[a._v("#")]),a._v(" Vertical Bar")]),a._v(" "),t("p",[a._v("我们在展示一下如何创建柱状图。")]),a._v(" "),t("ol",[t("li",[a._v("点击蓝色的 "),t("code",[a._v("Create a visualization")]),a._v(" 或 "),t("code",[a._v("+")]),a._v(" 按钮。选择 "),t("code",[a._v("Vertical Bar")])]),a._v(" "),t("li",[a._v("选择索引模式。由于您尚未定义任何 bucket ,因此您会看到一个大栏,显示与默认通配符查询匹配的文档总数。")]),a._v(" "),t("li",[a._v("指定 Y 轴所代表的字段")]),a._v(" "),t("li",[a._v("指定 X 轴所代表的字段")]),a._v(" "),t("li",[a._v("点击 "),t("img",{attrs:{src:"https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png",alt:"images/apply-changes-button.png"}}),a._v(" 按钮来更新图表。")])]),a._v(" "),t("p",[t("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-5aa7627284c19a56.png",alt:"image.png"}})]),a._v(" "),t("p",[a._v("完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 "),t("code",[a._v("Save")]),a._v(" 按钮。")]),a._v(" "),t("h2",{attrs:{id:"dashboard"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#dashboard"}},[a._v("#")]),a._v(" Dashboard")]),a._v(" "),t("p",[t("code",[a._v("Dashboard")]),a._v(" 可以整合和共享 "),t("code",[a._v("Visualize")]),a._v(" 集合。")]),a._v(" "),t("ol",[t("li",[a._v("点击侧面导航栏中的 Dashboard。")]),a._v(" "),t("li",[a._v("点击添加显示保存的可视化列表。")]),a._v(" "),t("li",[a._v("点击之前保存的 "),t("code",[a._v("Visualize")]),a._v(",然后点击列表底部的小向上箭头关闭可视化列表。")]),a._v(" "),t("li",[a._v("将鼠标悬停在可视化对象上会显示允许您编辑,移动,删除和调整可视化对象大小的容器控件。")])])])}),[],!1,null,null,null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/53.76541550.js b/assets/js/53.76541550.js new file mode 100644 index 0000000..9bd568a --- /dev/null +++ b/assets/js/53.76541550.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[53],{441:function(t,a,s){"use strict";s.r(a);var e=s(15),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"elastic-技术栈之-logstash-基础"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elastic-技术栈之-logstash-基础"}},[t._v("#")]),t._v(" Elastic 技术栈之 Logstash 基础")]),t._v(" "),s("blockquote",[s("p",[t._v("本文是 Elastic 技术栈(ELK)的 Logstash 应用。")]),t._v(" "),s("p",[t._v("如果不了解 Elastic 的安装、配置、部署,可以参考:"),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/docs/javatool/elastic/elastic-quickstart.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Elastic 技术栈之快速入门"),s("OutboundLink")],1)])]),t._v(" "),s("h2",{attrs:{id:"简介"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#简介"}},[t._v("#")]),t._v(" 简介")]),t._v(" "),s("p",[t._v("Logstash 可以传输和处理你的日志、事务或其他数据。")]),t._v(" "),s("h3",{attrs:{id:"功能"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#功能"}},[t._v("#")]),t._v(" 功能")]),t._v(" "),s("p",[t._v("Logstash 是 Elasticsearch 的最佳数据管道。")]),t._v(" "),s("p",[t._v("Logstash 是插件式管理模式,在输入、过滤、输出以及编码过程中都可以使用插件进行定制。Logstash 社区有超过 200 种可用插件。")]),t._v(" "),s("h3",{attrs:{id:"工作原理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#工作原理"}},[t._v("#")]),t._v(" 工作原理")]),t._v(" "),s("p",[t._v("Logstash 有两个必要元素:"),s("code",[t._v("input")]),t._v(" 和 "),s("code",[t._v("output")]),t._v(" ,一个可选元素:"),s("code",[t._v("filter")]),t._v("。")]),t._v(" "),s("p",[t._v("这三个元素,分别代表 Logstash 事件处理的三个阶段:输入 > 过滤器 > 输出。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://www.elastic.co/guide/en/logstash/current/static/images/basic_logstash_pipeline.png",alt:"img"}})]),t._v(" "),s("ul",[s("li",[t._v("input 负责从数据源采集数据。")]),t._v(" "),s("li",[t._v("filter 将数据修改为你指定的格式或内容。")]),t._v(" "),s("li",[t._v("output 将数据传输到目的地。")])]),t._v(" "),s("p",[t._v("在实际应用场景中,通常输入、输出、过滤器不止一个。Logstash 的这三个元素都使用插件式管理方式,用户可以根据应用需要,灵活的选用各阶段需要的插件,并组合使用。")]),t._v(" "),s("p",[t._v("后面将对插件展开讲解,暂且不表。")]),t._v(" "),s("h2",{attrs:{id:"设置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#设置"}},[t._v("#")]),t._v(" 设置")]),t._v(" "),s("h3",{attrs:{id:"设置文件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#设置文件"}},[t._v("#")]),t._v(" 设置文件")]),t._v(" "),s("ul",[s("li",[s("strong",[s("code",[t._v("logstash.yml")])]),t._v(":logstash 的默认启动配置文件")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("jvm.options")])]),t._v(":logstash 的 JVM 配置文件。")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("startup.options")])]),t._v(" (Linux):包含系统安装脚本在 "),s("code",[t._v("/usr/share/logstash/bin")]),t._v(" 中使用的选项为您的系统构建适当的启动脚本。安装 Logstash 软件包时,系统安装脚本将在安装过程结束时执行,并使用 "),s("code",[t._v("startup.options")]),t._v(" 中指定的设置来设置用户,组,服务名称和服务描述等选项。")])]),t._v(" "),s("h3",{attrs:{id:"logstash-yml-设置项"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logstash-yml-设置项"}},[t._v("#")]),t._v(" logstash.yml 设置项")]),t._v(" "),s("p",[t._v("节选部分设置项,更多项请参考:https://www.elastic.co/guide/en/logstash/current/logstash-settings-file.html")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("描述")]),t._v(" "),s("th",[t._v("默认值")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[s("code",[t._v("node.name")])]),t._v(" "),s("td",[t._v("节点名")]),t._v(" "),s("td",[t._v("机器的主机名")])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("path.data")])]),t._v(" "),s("td",[t._v("Logstash及其插件用于任何持久性需求的目录。")]),t._v(" "),s("td",[s("code",[t._v("LOGSTASH_HOME/data")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("pipeline.workers")])]),t._v(" "),s("td",[t._v("同时执行管道的过滤器和输出阶段的工作任务数量。如果发现事件正在备份,或CPU未饱和,请考虑增加此数字以更好地利用机器处理能力。")]),t._v(" "),s("td",[t._v("Number of the host’s CPU cores")])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("pipeline.batch.size")])]),t._v(" "),s("td",[t._v("尝试执行过滤器和输出之前,单个工作线程从输入收集的最大事件数量。较大的批量处理大小一般来说效率更高,但是以增加的内存开销为代价。您可能必须通过设置 "),s("code",[t._v("LS_HEAP_SIZE")]),t._v(" 变量来有效使用该选项来增加JVM堆大小。")]),t._v(" "),s("td",[s("code",[t._v("125")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("pipeline.batch.delay")])]),t._v(" "),s("td",[t._v("创建管道事件批处理时,在将一个尺寸过小的批次发送给管道工作任务之前,等待每个事件需要多长时间(毫秒)。")]),t._v(" "),s("td",[s("code",[t._v("5")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("pipeline.unsafe_shutdown")])]),t._v(" "),s("td",[t._v("如果设置为true,则即使在内存中仍存在inflight事件时,也会强制Logstash在关闭期间退出。默认情况下,Logstash将拒绝退出,直到所有接收到的事件都被推送到输出。启用此选项可能会导致关机期间数据丢失。")]),t._v(" "),s("td",[s("code",[t._v("false")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("path.config")])]),t._v(" "),s("td",[t._v("主管道的Logstash配置路径。如果您指定一个目录或通配符,配置文件将按字母顺序从目录中读取。")]),t._v(" "),s("td",[t._v("Platform-specific. See ["),s("a",{attrs:{href:"https://github.com/elastic/logstash/blob/6.1/docs/static/settings-file.asciidoc#dir-layout",target:"_blank",rel:"noopener noreferrer"}},[t._v("dir-layout]"),s("OutboundLink")],1),t._v(".")])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.string")])]),t._v(" "),s("td",[t._v("包含用于主管道的管道配置的字符串。使用与配置文件相同的语法。")]),t._v(" "),s("td",[t._v("None")])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.test_and_exit")])]),t._v(" "),s("td",[t._v("设置为true时,检查配置是否有效,然后退出。请注意,使用此设置不会检查grok模式的正确性。 Logstash可以从目录中读取多个配置文件。如果将此设置与log.level:debug结合使用,则Logstash将记录组合的配置文件,并注掉其源文件的配置块。")]),t._v(" "),s("td",[s("code",[t._v("false")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.reload.automatic")])]),t._v(" "),s("td",[t._v("设置为true时,定期检查配置是否已更改,并在配置更改时重新加载配置。这也可以通过SIGHUP信号手动触发。")]),t._v(" "),s("td",[s("code",[t._v("false")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.reload.interval")])]),t._v(" "),s("td",[t._v("Logstash 检查配置文件更改的时间间隔。")]),t._v(" "),s("td",[s("code",[t._v("3s")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.debug")])]),t._v(" "),s("td",[t._v("设置为true时,将完全编译的配置显示为调试日志消息。您还必须设置"),s("code",[t._v("log.level:debug")]),t._v("。警告:日志消息将包括任何传递给插件配置作为明文的“密码”选项,并可能导致明文密码出现在您的日志!")]),t._v(" "),s("td",[s("code",[t._v("false")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("config.support_escapes")])]),t._v(" "),s("td",[t._v("当设置为true时,带引号的字符串将处理转义字符。")]),t._v(" "),s("td",[s("code",[t._v("false")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("modules")])]),t._v(" "),s("td",[t._v("配置时,模块必须处于上表所述的嵌套YAML结构中。")]),t._v(" "),s("td",[t._v("None")])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("http.host")])]),t._v(" "),s("td",[t._v("绑定地址")]),t._v(" "),s("td",[s("code",[t._v('"127.0.0.1"')])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("http.port")])]),t._v(" "),s("td",[t._v("绑定端口")]),t._v(" "),s("td",[s("code",[t._v("9600")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("log.level")])]),t._v(" "),s("td",[t._v("日志级别。有效选项:fatal > error > warn > info > debug > trace")]),t._v(" "),s("td",[s("code",[t._v("info")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("log.format")])]),t._v(" "),s("td",[t._v("日志格式。json (JSON 格式)或 plain (原对象)")]),t._v(" "),s("td",[s("code",[t._v("plain")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("path.logs")])]),t._v(" "),s("td",[t._v("Logstash 自身日志的存储路径")]),t._v(" "),s("td",[s("code",[t._v("LOGSTASH_HOME/logs")])])]),t._v(" "),s("tr",[s("td",[s("code",[t._v("path.plugins")])]),t._v(" "),s("td",[t._v("在哪里可以找到自定义的插件。您可以多次指定此设置以包含多个路径。")]),t._v(" "),s("td")])])]),t._v(" "),s("h2",{attrs:{id:"启动"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#启动"}},[t._v("#")]),t._v(" 启动")]),t._v(" "),s("h3",{attrs:{id:"命令行"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#命令行"}},[t._v("#")]),t._v(" 命令行")]),t._v(" "),s("p",[t._v("通过命令行启动 logstash 的方式如下:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("bin/logstash [options]\n")])])]),s("p",[t._v("其中 [options] 是您可以指定用于控制 Logstash 执行的命令行标志。")]),t._v(" "),s("p",[t._v("在命令行上设置的任何标志都会覆盖 Logstash 设置文件("),s("code",[t._v("logstash.yml")]),t._v(")中的相应设置,但设置文件本身不会更改。")]),t._v(" "),s("blockquote",[s("p",[s("strong",[t._v("注")])]),t._v(" "),s("p",[t._v("虽然可以通过指定命令行参数的方式,来控制 logstash 的运行方式,但显然这么做很麻烦。")]),t._v(" "),s("p",[t._v("建议通过指定配置文件的方式,来控制 logstash 运行,启动命令如下:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("bin/logstash -f logstash.conf\n")])])]),s("p",[t._v("若想了解更多的命令行参数细节,请参考:https://www.elastic.co/guide/en/logstash/current/running-logstash-command-line.html")])]),t._v(" "),s("h3",{attrs:{id:"配置文件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置文件"}},[t._v("#")]),t._v(" 配置文件")]),t._v(" "),s("p",[t._v("上节,我们了解到,logstash 可以执行 "),s("code",[t._v("bin/logstash -f logstash.conf")]),t._v(" ,按照配置文件中的参数去覆盖默认设置文件("),s("code",[t._v("logstash.yml")]),t._v(")中的设置。")]),t._v(" "),s("p",[t._v("这节,我们就来学习一下这个配置文件如何配置参数。")]),t._v(" "),s("h4",{attrs:{id:"配置文件结构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置文件结构"}},[t._v("#")]),t._v(" 配置文件结构")]),t._v(" "),s("p",[t._v("在工作原理一节中,我们已经知道了 Logstash 主要有三个工作阶段 input 、filter、output。而 logstash 配置文件文件结构也与之相对应:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("input {}\n\nfilter {}\n\noutput {}\n")])])]),s("blockquote",[s("p",[t._v("每个部分都包含一个或多个插件的配置选项。如果指定了多个过滤器,则会按照它们在配置文件中的显示顺序应用它们。")])]),t._v(" "),s("h4",{attrs:{id:"插件配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#插件配置"}},[t._v("#")]),t._v(" 插件配置")]),t._v(" "),s("p",[t._v("插件的配置由插件名称和插件的一个设置块组成。")]),t._v(" "),s("p",[t._v("下面的例子中配置了两个输入文件配置:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input {\n file {\n path => "/var/log/messages"\n type => "syslog"\n }\n\n file {\n path => "/var/log/apache/access.log"\n type => "apache"\n }\n}\n')])])]),s("p",[t._v("您可以配置的设置因插件类型而异。你可以参考: "),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/input-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Input Plugins"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/output-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Output Plugins"),s("OutboundLink")],1),t._v(", "),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/filter-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Filter Plugins"),s("OutboundLink")],1),t._v(", 和 "),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/codec-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Codec Plugins"),s("OutboundLink")],1),t._v(" 。")]),t._v(" "),s("h4",{attrs:{id:"值类型"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#值类型"}},[t._v("#")]),t._v(" 值类型")]),t._v(" "),s("p",[t._v("一个插件可以要求设置的值是一个特定的类型,比如布尔值,列表或哈希值。以下值类型受支持。")]),t._v(" "),s("ul",[s("li",[t._v("Array")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" users => [ {id => 1, name => bob}, {id => 2, name => jane} ]\n")])])]),s("ul",[s("li",[t._v("Lists")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' path => [ "/var/log/messages", "/var/log/*.log" ]\n uris => [ "http://elastic.co", "http://example.net" ]\n')])])]),s("ul",[s("li",[t._v("Boolean")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" ssl_enable => true\n")])])]),s("ul",[s("li",[t._v("Bytes")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' my_bytes => "1113" # 1113 bytes\n my_bytes => "10MiB" # 10485760 bytes\n my_bytes => "100kib" # 102400 bytes\n my_bytes => "180 mb" # 180000000 bytes\n')])])]),s("ul",[s("li",[t._v("Codec")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' codec => "json"\n')])])]),s("ul",[s("li",[t._v("Hash")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('match => {\n "field1" => "value1"\n "field2" => "value2"\n ...\n}\n')])])]),s("ul",[s("li",[t._v("Number")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" port => 33\n")])])]),s("ul",[s("li",[t._v("Password")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' my_password => "password"\n')])])]),s("ul",[s("li",[t._v("URI")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' my_uri => "http://foo:bar@example.net"\n')])])]),s("ul",[s("li",[t._v("Path")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(' my_path => "/tmp/logstash"\n')])])]),s("ul",[s("li",[s("p",[t._v("String")])]),t._v(" "),s("li",[s("p",[t._v("转义字符")])])]),t._v(" "),s("h2",{attrs:{id:"插件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#插件"}},[t._v("#")]),t._v(" 插件")]),t._v(" "),s("h3",{attrs:{id:"input"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#input"}},[t._v("#")]),t._v(" input")]),t._v(" "),s("blockquote",[s("p",[t._v("Logstash 支持各种输入选择 ,可以在同一时间从众多常用来源捕捉事件。能够以连续的流式传输方式,轻松地从您的日志、指标、Web 应用、数据存储以及各种 AWS 服务采集数据。")])]),t._v(" "),s("h4",{attrs:{id:"常用-input-插件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常用-input-插件"}},[t._v("#")]),t._v(" 常用 input 插件")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("file")]),t._v(":从文件系统上的文件读取,就像UNIX命令 "),s("code",[t._v("tail -0F")]),t._v(" 一样")]),t._v(" "),s("li",[t._v("**syslog:**在众所周知的端口514上侦听系统日志消息,并根据RFC3164格式进行解析")]),t._v(" "),s("li",[t._v("**redis:**从redis服务器读取,使用redis通道和redis列表。 Redis经常用作集中式Logstash安装中的“代理”,它将来自远程Logstash“托运人”的Logstash事件排队。")]),t._v(" "),s("li",[t._v("**beats:**处理由Filebeat发送的事件。")])]),t._v(" "),s("p",[t._v("更多详情请见:"),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/input-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Input Plugins"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"filter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#filter"}},[t._v("#")]),t._v(" filter")]),t._v(" "),s("blockquote",[s("p",[t._v("过滤器是Logstash管道中的中间处理设备。如果符合特定条件,您可以将条件过滤器组合在一起,对事件执行操作。")])]),t._v(" "),s("h4",{attrs:{id:"常用-filter-插件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常用-filter-插件"}},[t._v("#")]),t._v(" 常用 filter 插件")]),t._v(" "),s("ul",[s("li",[s("p",[t._v("**grok:**解析和结构任意文本。 Grok目前是Logstash中将非结构化日志数据解析为结构化和可查询的最佳方法。")])]),t._v(" "),s("li",[s("p",[t._v("**mutate:**对事件字段执行一般转换。您可以重命名,删除,替换和修改事件中的字段。")])]),t._v(" "),s("li",[s("p",[t._v("**drop:**完全放弃一个事件,例如调试事件。")])]),t._v(" "),s("li",[s("p",[t._v("**clone:**制作一个事件的副本,可能会添加或删除字段。")])]),t._v(" "),s("li",[s("p",[t._v("**geoip:**添加有关IP地址的地理位置的信息(也可以在Kibana中显示惊人的图表!)")])])]),t._v(" "),s("p",[t._v("更多详情请见:"),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/filter-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Filter Plugins"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"output"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#output"}},[t._v("#")]),t._v(" output")]),t._v(" "),s("blockquote",[s("p",[t._v("输出是Logstash管道的最后阶段。一个事件可以通过多个输出,但是一旦所有输出处理完成,事件就完成了执行。")])]),t._v(" "),s("h4",{attrs:{id:"常用-output-插件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常用-output-插件"}},[t._v("#")]),t._v(" 常用 output 插件")]),t._v(" "),s("ul",[s("li",[t._v("**elasticsearch:**将事件数据发送给 Elasticsearch(推荐模式)。")]),t._v(" "),s("li",[t._v("**file:**将事件数据写入文件或磁盘。")]),t._v(" "),s("li",[t._v("**graphite:**将事件数据发送给 graphite(一个流行的开源工具,存储和绘制指标。 http://graphite.readthedocs.io/en/latest/)。")]),t._v(" "),s("li",[t._v("**statsd:**将事件数据发送到 statsd (这是一种侦听统计数据的服务,如计数器和定时器,通过UDP发送并将聚合发送到一个或多个可插入的后端服务)。")])]),t._v(" "),s("p",[t._v("更多详情请见:"),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/output-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Output Plugins"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"codec"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#codec"}},[t._v("#")]),t._v(" codec")]),t._v(" "),s("p",[t._v("用于格式化对应的内容。")]),t._v(" "),s("h4",{attrs:{id:"常用-codec-插件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常用-codec-插件"}},[t._v("#")]),t._v(" 常用 codec 插件")]),t._v(" "),s("ul",[s("li",[t._v("**json:**以JSON格式对数据进行编码或解码。")]),t._v(" "),s("li",[t._v("**multiline:**将多行文本事件(如java异常和堆栈跟踪消息)合并为单个事件。")])]),t._v(" "),s("p",[t._v("更多插件请见:"),s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/codec-plugins.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Codec Plugins"),s("OutboundLink")],1)]),t._v(" "),s("h2",{attrs:{id:"实战"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#实战"}},[t._v("#")]),t._v(" 实战")]),t._v(" "),s("p",[t._v("前面的内容都是对 Logstash 的介绍和原理说明。接下来,我们来实战一些常见的应用场景。")]),t._v(" "),s("h3",{attrs:{id:"传输控制台数据"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#传输控制台数据"}},[t._v("#")]),t._v(" 传输控制台数据")]),t._v(" "),s("blockquote",[s("p",[t._v("stdin input 插件从标准输入读取事件。这是最简单的 input 插件,一般用于测试场景。")])]),t._v(" "),s("p",[s("strong",[t._v("应用")])]),t._v(" "),s("p",[t._v("(1)创建 "),s("code",[t._v("logstash-input-stdin.conf")]),t._v(" :")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input { stdin { } }\noutput {\n elasticsearch { hosts => ["localhost:9200"] }\n stdout { codec => rubydebug }\n}\n')])])]),s("p",[t._v("更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-stdin.html")]),t._v(" "),s("p",[t._v("(2)执行 logstash,使用 "),s("code",[t._v("-f")]),t._v(" 来指定你的配置文件:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("bin/logstash -f logstash-input-stdin.conf\n")])])]),s("h3",{attrs:{id:"传输-logback-日志"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#传输-logback-日志"}},[t._v("#")]),t._v(" 传输 logback 日志")]),t._v(" "),s("blockquote",[s("p",[t._v("elk 默认使用的 Java 日志工具是 log4j2 ,并不支持 logback 和 log4j。")]),t._v(" "),s("p",[t._v("想使用 logback + logstash ,可以使用 "),s("a",{attrs:{href:"https://github.com/logstash/logstash-logback-encoder",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash-logback-encoder"),s("OutboundLink")],1),t._v(" 。"),s("a",{attrs:{href:"https://github.com/logstash/logstash-logback-encoder",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash-logback-encoder"),s("OutboundLink")],1),t._v(" 提供了 UDP / TCP / 异步方式来传输日志数据到 logstash。")]),t._v(" "),s("p",[t._v("如果你使用的是 log4j ,也不是不可以用这种方式,只要引入桥接 jar 包即可。如果你对 log4j 、logback ,或是桥接 jar 包不太了解,可以参考我的这篇博文:"),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("细说 Java 主流日志工具库"),s("OutboundLink")],1),t._v(" 。")])]),t._v(" "),s("h4",{attrs:{id:"tcp-应用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#tcp-应用"}},[t._v("#")]),t._v(" TCP 应用")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("logstash 配置")]),t._v(" "),s("p",[t._v("(1)创建 "),s("code",[t._v("logstash-input-tcp.conf")]),t._v(" :")])])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input {\ntcp {\n port => 9251\n codec => json_lines\n mode => server\n}\n}\noutput {\n elasticsearch { hosts => ["localhost:9200"] }\n stdout { codec => rubydebug }\n}\n')])])]),s("p",[t._v("更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-tcp.html")]),t._v(" "),s("p",[t._v("(2)执行 logstash,使用 "),s("code",[t._v("-f")]),t._v(" 来指定你的配置文件:"),s("code",[t._v("bin/logstash -f logstash-input-udp.conf")])]),t._v(" "),s("ol",{attrs:{start:"2"}},[s("li",[s("p",[t._v("java 应用配置")]),t._v(" "),s("p",[t._v("(1)在 Java 应用的 pom.xml 中引入 jar 包:")])])]),t._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("net.logstash.logback"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("logstash-logback-encoder"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("version")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("4.11"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!-- logback 依赖包 --\x3e")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("ch.qos.logback"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("logback-core"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("version")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("1.2.3"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("ch.qos.logback"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("logback-classic"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("version")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("1.2.3"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("ch.qos.logback"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("logback-access"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("version")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("1.2.3"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("p",[t._v("(2)接着,在 logback.xml 中添加 appender")]),t._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("ELK-TCP"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("net.logstash.logback.appender.LogstashTcpSocketAppender"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--\n destination 是 logstash 服务的 host:port,\n 相当于和 logstash 建立了管道,将日志数据定向传输到 logstash\n --\x3e")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("destination")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("192.168.28.32:9251"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("encoder")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("charset")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("UTF-8"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("net.logstash.logback.encoder.LogstashEncoder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("/>")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("io.github.dunwu.spring"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("level")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("TRACE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("additivity")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("false"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender-ref")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("ref")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("ELK-TCP"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("/>")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("p",[t._v("(3)接下来,就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:"),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("细说 Java 主流日志工具库"),s("OutboundLink")],1),t._v(" 。")]),t._v(" "),s("p",[s("strong",[t._v("实例:")]),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的logback.xml"),s("OutboundLink")],1)]),t._v(" "),s("h4",{attrs:{id:"udp-应用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#udp-应用"}},[t._v("#")]),t._v(" UDP 应用")]),t._v(" "),s("p",[t._v("UDP 和 TCP 的使用方式大同小异。")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("logstash 配置")]),t._v(" "),s("p",[t._v("(1)创建 "),s("code",[t._v("logstash-input-udp.conf")]),t._v(" :")])])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input {\nudp {\n port => 9250\n codec => json\n}\n}\noutput {\n elasticsearch { hosts => ["localhost:9200"] }\n stdout { codec => rubydebug }\n}\n')])])]),s("p",[t._v("更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-udp.html")]),t._v(" "),s("p",[t._v("(2)执行 logstash,使用 "),s("code",[t._v("-f")]),t._v(" 来指定你的配置文件:"),s("code",[t._v("bin/logstash -f logstash-input-udp.conf")])]),t._v(" "),s("ol",{attrs:{start:"2"}},[s("li",[s("p",[t._v("java 应用配置")]),t._v(" "),s("p",[t._v("(1)在 Java 应用的 pom.xml 中引入 jar 包:")]),t._v(" "),s("p",[t._v("与 "),s("strong",[t._v("TCP 应用")]),t._v(" 一节中的引入依赖包完全相同。")]),t._v(" "),s("p",[t._v("(2)接着,在 logback.xml 中添加 appender")])])]),t._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("ELK-UDP"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("net.logstash.logback.appender.LogstashSocketAppender"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("host")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("192.168.28.32"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("9250"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("io.github.dunwu.spring"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("level")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("TRACE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("additivity")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("false"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender-ref")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("ref")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("ELK-UDP"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("/>")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("p",[t._v("(3)接下来,就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:"),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("细说 Java 主流日志工具库"),s("OutboundLink")],1),t._v(" 。")]),t._v(" "),s("p",[s("strong",[t._v("实例:")]),s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的logback.xml"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"传输文件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#传输文件"}},[t._v("#")]),t._v(" 传输文件")]),t._v(" "),s("blockquote",[s("p",[t._v("在 Java Web 领域,需要用到一些重要的工具,例如 Tomcat 、Nginx 、Mysql 等。这些不属于业务应用,但是它们的日志数据对于定位问题、分析统计同样很重要。这时无法使用 logback 方式将它们的日志传输到 logstash。")]),t._v(" "),s("p",[t._v("如何采集这些日志文件呢?别急,你可以使用 logstash 的 file input 插件。")]),t._v(" "),s("p",[t._v("需要注意的是,传输文件这种方式,必须在日志所在的机器上部署 logstash 。")])]),t._v(" "),s("p",[s("strong",[t._v("应用")])]),t._v(" "),s("p",[t._v("logstash 配置")]),t._v(" "),s("p",[t._v("(1)创建 "),s("code",[t._v("logstash-input-file.conf")]),t._v(" :")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input {\n\tfile {\n\t\tpath => ["/var/log/nginx/access.log"]\n\t\ttype => "nginx-access-log"\n\t\tstart_position => "beginning"\n\t}\n}\n\noutput {\n\tif [type] == "nginx-access-log" {\n\t\telasticsearch {\n\t\t\thosts => ["localhost:9200"]\n\t\t\tindex => "nginx-access-log"\n\t\t}\n\t}\n}\n')])])]),s("p",[t._v("(2)执行 logstash,使用 "),s("code",[t._v("-f")]),t._v(" 来指定你的配置文件:"),s("code",[t._v("bin/logstash -f logstash-input-file.conf")])]),t._v(" "),s("p",[t._v("更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html")]),t._v(" "),s("h2",{attrs:{id:"小技巧"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#小技巧"}},[t._v("#")]),t._v(" 小技巧")]),t._v(" "),s("h3",{attrs:{id:"启动、终止应用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#启动、终止应用"}},[t._v("#")]),t._v(" 启动、终止应用")]),t._v(" "),s("p",[t._v("如果你的 logstash 每次都是通过指定配置文件方式启动。不妨建立一个启动脚本。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("# cd xxx 进入 logstash 安装目录下的 bin 目录\nlogstash -f logstash.conf\n")])])]),s("p",[t._v("如果你的 logstash 运行在 linux 系统下,不妨使用 nohup 来启动一个守护进程。这样做的好处在于,即使关闭终端,应用仍会运行。")]),t._v(" "),s("p",[s("strong",[t._v("创建 startup.sh")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nohup ./logstash -f logstash.conf >> nohup.out 2>&1 &\n")])])]),s("p",[t._v("终止应用没有什么好方法,你只能使用 ps -ef | grep logstash ,查出进程,将其kill 。不过,我们可以写一个脚本来干这件事:")]),t._v(" "),s("p",[s("strong",[t._v("创建 shutdown.sh")])]),t._v(" "),s("p",[t._v("脚本不多解释,请自行领会作用。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("PID=`ps -ef | grep logstash | awk '{ print $2}' | head -n 1`\nkill -9 ${PID}\n")])])]),s("h2",{attrs:{id:"资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#资料"}},[t._v("#")]),t._v(" 资料")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://www.elastic.co/guide/en/logstash/current/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash 官方文档"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/logstash/logstash-logback-encoder",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash-logback-encoder"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/chenryn/logstash-best-practice-cn",target:"_blank",rel:"noopener noreferrer"}},[t._v("ELK Stack权威指南"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/judasn/Linux-Tutorial/blob/master/ELK-Install-And-Settings.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("ELK(Elasticsearch、Logstash、Kibana)安装和配置"),s("OutboundLink")],1)])]),t._v(" "),s("h2",{attrs:{id:"推荐阅读"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#推荐阅读"}},[t._v("#")]),t._v(" 推荐阅读")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://github.com/dunwu/JavaStack/blob/master/docs/javatool/elastic/README.md",target:"_blank",rel:"noopener noreferrer"}},[t._v("Elastic 技术栈"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/dunwu/JavaStack",target:"_blank",rel:"noopener noreferrer"}},[t._v("JavaStack"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/54.e78d2776.js b/assets/js/54.e78d2776.js new file mode 100644 index 0000000..b54b899 --- /dev/null +++ b/assets/js/54.e78d2776.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[54],{442:function(t,a,s){"use strict";s.r(a);var e=s(15),n=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"elastic-技术栈之快速入门"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elastic-技术栈之快速入门"}},[t._v("#")]),t._v(" Elastic 技术栈之快速入门")]),t._v(" "),s("h2",{attrs:{id:"概念"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概念"}},[t._v("#")]),t._v(" 概念")]),t._v(" "),s("h3",{attrs:{id:"elk-是什么"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elk-是什么"}},[t._v("#")]),t._v(" ELK 是什么")]),t._v(" "),s("p",[t._v("ELK 是 elastic 公司旗下三款产品 "),s("a",{attrs:{href:"https://www.elastic.co/products/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),s("OutboundLink")],1),t._v(" 、"),s("a",{attrs:{href:"https://www.elastic.co/products/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash"),s("OutboundLink")],1),t._v(" 、"),s("a",{attrs:{href:"https://www.elastic.co/products/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kibana"),s("OutboundLink")],1),t._v(" 的首字母组合。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),s("OutboundLink")],1),t._v(" 是一个基于 "),s("a",{attrs:{href:"http://lucene.apache.org/core/documentation.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Lucene"),s("OutboundLink")],1),t._v(" 构建的开源,分布式,RESTful 搜索引擎。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash"),s("OutboundLink")],1),t._v(" 传输和处理你的日志、事务或其他数据。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kibana"),s("OutboundLink")],1),t._v(" 将 Elasticsearch 的数据分析并渲染为可视化的报表。")]),t._v(" "),s("h3",{attrs:{id:"为什么使用-elk"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#为什么使用-elk"}},[t._v("#")]),t._v(" 为什么使用 ELK ?")]),t._v(" "),s("p",[t._v("对于有一定规模的公司来说,通常会很多个应用,并部署在大量的服务器上。运维和开发人员常常需要通过查看日志来定位问题。如果应用是集群化部署,试想如果登录一台台服务器去查看日志,是多么费时费力。")]),t._v(" "),s("p",[t._v("而通过 ELK 这套解决方案,可以同时实现日志收集、日志搜索和日志分析的功能。")]),t._v(" "),s("h3",{attrs:{id:"elastic-架构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elastic-架构"}},[t._v("#")]),t._v(" Elastic 架构")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://www.elastic.co/guide/en/logstash/current/static/images/deploy3.png",alt:"img"}})]),t._v(" "),s("blockquote",[s("p",[s("strong",[t._v("说明")])]),t._v(" "),s("p",[t._v("以上是 ELK 技术栈的一个架构图。从图中可以清楚的看到数据流向。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/beats",target:"_blank",rel:"noopener noreferrer"}},[t._v("Beats"),s("OutboundLink")],1),t._v(" 是单一用途的数据传输平台,它可以将多台机器的数据发送到 Logstash 或 ElasticSearch。但 Beats 并不是不可或缺的一环,所以本文中暂不介绍。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("Logstash"),s("OutboundLink")],1),t._v(" 是一个动态数据收集管道。支持以 TCP/UDP/HTTP 多种方式收集数据(也可以接受 Beats 传输来的数据),并对数据做进一步丰富或提取字段处理。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("ElasticSearch"),s("OutboundLink")],1),t._v(" 是一个基于 JSON 的分布式的搜索和分析引擎。作为 ELK 的核心,它集中存储数据。")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://www.elastic.co/products/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("Kibana"),s("OutboundLink")],1),t._v(" 是 ELK 的用户界面。它将收集的数据进行可视化展示(各种报表、图形化数据),并提供配置、管理 ELK 的界面。")])]),t._v(" "),s("h2",{attrs:{id:"安装"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[t._v("#")]),t._v(" 安装")]),t._v(" "),s("h3",{attrs:{id:"准备"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#准备"}},[t._v("#")]),t._v(" 准备")]),t._v(" "),s("p",[t._v("ELK 要求本地环境中安装了 JDK 。如果不确定是否已安装,可使用下面的命令检查:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[t._v("java -version\n")])])]),s("blockquote",[s("p",[s("strong",[t._v("注意")])]),t._v(" "),s("p",[t._v("本文使用的 ELK 是 6.0.0,要求 jdk 版本不低于 JDK8。")]),t._v(" "),s("p",[t._v("友情提示:安装 ELK 时,三个应用请选择统一的版本,避免出现一些莫名其妙的问题。例如:由于版本不统一,导致三个应用间的通讯异常。")])]),t._v(" "),s("h3",{attrs:{id:"elasticsearch"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elasticsearch"}},[t._v("#")]),t._v(" Elasticsearch")]),t._v(" "),s("p",[t._v("安装步骤如下:")]),t._v(" "),s("ol",[s("li",[s("a",{attrs:{href:"https://www.elastic.co/downloads/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("elasticsearch 官方下载地址"),s("OutboundLink")],1),t._v("下载所需版本包并解压到本地。")]),t._v(" "),s("li",[t._v("运行 "),s("code",[t._v("bin/elasticsearch")]),t._v(" (Windows 上运行 "),s("code",[t._v("bin\\elasticsearch.bat")]),t._v(")")]),t._v(" "),s("li",[t._v("验证运行成功:linux 上可以执行 "),s("code",[t._v("curl http://localhost:9200/")]),t._v(" ;windows 上可以用访问 REST 接口的方式来访问 http://localhost:9200/")])]),t._v(" "),s("blockquote",[s("p",[s("strong",[t._v("说明")])]),t._v(" "),s("p",[t._v("Linux 上可以执行下面的命令来下载压缩包:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.tar.gz\n")])])]),s("p",[t._v("Mac 上可以执行以下命令来进行安装:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("brew install elasticsearch\n")])])]),s("p",[t._v("Windows 上可以选择 MSI 可执行安装程序,将应用安装到本地。")])]),t._v(" "),s("h3",{attrs:{id:"logstash"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#logstash"}},[t._v("#")]),t._v(" Logstash")]),t._v(" "),s("p",[t._v("安装步骤如下:")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("在 "),s("a",{attrs:{href:"https://www.elastic.co/downloads/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash 官方下载地址"),s("OutboundLink")],1),t._v("下载所需版本包并解压到本地。")])]),t._v(" "),s("li",[s("p",[t._v("添加一个 "),s("code",[t._v("logstash.conf")]),t._v(" 文件,指定要使用的插件以及每个插件的设置。举个简单的例子:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input { stdin { } }\noutput {\n elasticsearch { hosts => ["localhost:9200"] }\n stdout { codec => rubydebug }\n}\n')])])])]),t._v(" "),s("li",[s("p",[t._v("运行 "),s("code",[t._v("bin/logstash -f logstash.conf")]),t._v(" (Windows 上运行"),s("code",[t._v("bin/logstash.bat -f logstash.conf")]),t._v(")")])])]),t._v(" "),s("h3",{attrs:{id:"kibana"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#kibana"}},[t._v("#")]),t._v(" Kibana")]),t._v(" "),s("p",[t._v("安装步骤如下:")]),t._v(" "),s("ol",[s("li",[t._v("在 "),s("a",{attrs:{href:"https://www.elastic.co/downloads/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("kibana 官方下载地址"),s("OutboundLink")],1),t._v("下载所需版本包并解压到本地。")]),t._v(" "),s("li",[t._v("修改 "),s("code",[t._v("config/kibana.yml")]),t._v(" 配置文件,设置 "),s("code",[t._v("elasticsearch.url")]),t._v(" 指向 Elasticsearch 实例。")]),t._v(" "),s("li",[t._v("运行 "),s("code",[t._v("bin/kibana")]),t._v(" (Windows 上运行 "),s("code",[t._v("bin\\kibana.bat")]),t._v(")")]),t._v(" "),s("li",[t._v("在浏览器上访问 http://localhost:5601")])]),t._v(" "),s("h3",{attrs:{id:"安装-faq"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装-faq"}},[t._v("#")]),t._v(" 安装 FAQ")]),t._v(" "),s("h4",{attrs:{id:"elasticsearch-不允许以-root-权限来运行"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#elasticsearch-不允许以-root-权限来运行"}},[t._v("#")]),t._v(" elasticsearch 不允许以 root 权限来运行")]),t._v(" "),s("p",[t._v("**问题:**在 Linux 环境中,elasticsearch 不允许以 root 权限来运行。")]),t._v(" "),s("p",[t._v("如果以 root 身份运行 elasticsearch,会提示这样的错误:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("can not run elasticsearch as root\n")])])]),s("p",[t._v("**解决方法:**使用非 root 权限账号运行 elasticsearch")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 创建用户组")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("groupadd")]),t._v(" elk\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 创建新用户,-g elk 设置其用户组为 elk,-p elk 设置其密码为 elk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("useradd")]),t._v(" elk -g elk -p elk\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 更改 /opt 文件夹及内部文件的所属用户及组为 elk:elk")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R elk:elk /opt "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 假设你的 elasticsearch 安装在 opt 目录下")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 切换账号")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("su")]),t._v(" elk\n")])])]),s("h4",{attrs:{id:"vm-max-map-count-不低于-262144"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#vm-max-map-count-不低于-262144"}},[t._v("#")]),t._v(" vm.max_map_count 不低于 262144")]),t._v(" "),s("p",[s("strong",[t._v("问题:")]),s("code",[t._v("vm.max_map_count")]),t._v(" 表示虚拟内存大小,它是一个内核参数。elasticsearch 默认要求 "),s("code",[t._v("vm.max_map_count")]),t._v(" 不低于 262144。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]\n")])])]),s("p",[s("strong",[t._v("解决方法:")])]),t._v(" "),s("p",[t._v("你可以执行以下命令,设置 "),s("code",[t._v("vm.max_map_count")]),t._v(" ,但是重启后又会恢复为原值。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sysctl -w vm.max_map_count=262144\n")])])]),s("p",[t._v("持久性的做法是在 "),s("code",[t._v("/etc/sysctl.conf")]),t._v(" 文件中修改 "),s("code",[t._v("vm.max_map_count")]),t._v(" 参数:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('echo "vm.max_map_count=262144" > /etc/sysctl.conf\nsysctl -p\n')])])]),s("blockquote",[s("p",[s("strong",[t._v("注意")])]),t._v(" "),s("p",[t._v("如果运行环境为 docker 容器,可能会限制执行 sysctl 来修改内核参数。")]),t._v(" "),s("p",[t._v("这种情况下,你只能选择直接修改宿主机上的参数了。")])]),t._v(" "),s("h4",{attrs:{id:"nofile-不低于-65536"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nofile-不低于-65536"}},[t._v("#")]),t._v(" nofile 不低于 65536")]),t._v(" "),s("p",[s("strong",[t._v("问题:")]),t._v(" "),s("code",[t._v("nofile")]),t._v(" 表示进程允许打开的最大文件数。elasticsearch 进程要求可以打开的最大文件数不低于 65536。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]\n")])])]),s("p",[s("strong",[t._v("解决方法:")])]),t._v(" "),s("p",[t._v("在 "),s("code",[t._v("/etc/security/limits.conf")]),t._v(" 文件中修改 "),s("code",[t._v("nofile")]),t._v(" 参数:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('echo "* soft nofile 65536" > /etc/security/limits.conf\necho "* hard nofile 131072" > /etc/security/limits.conf\n')])])]),s("h4",{attrs:{id:"nproc-不低于-2048"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nproc-不低于-2048"}},[t._v("#")]),t._v(" nproc 不低于 2048")]),t._v(" "),s("p",[s("strong",[t._v("问题:")]),t._v(" "),s("code",[t._v("nproc")]),t._v(" 表示最大线程数。elasticsearch 要求最大线程数不低于 2048。")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("max number of threads [1024] for user [user] is too low, increase to at least [2048]\n")])])]),s("p",[s("strong",[t._v("解决方法:")])]),t._v(" "),s("p",[t._v("在 "),s("code",[t._v("/etc/security/limits.conf")]),t._v(" 文件中修改 "),s("code",[t._v("nproc")]),t._v(" 参数:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('echo "* soft nproc 2048" > /etc/security/limits.conf\necho "* hard nproc 4096" > /etc/security/limits.conf\n')])])]),s("h4",{attrs:{id:"kibana-no-default-index-pattern-warning"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#kibana-no-default-index-pattern-warning"}},[t._v("#")]),t._v(" Kibana No Default Index Pattern Warning")]),t._v(" "),s("p",[t._v("**问题:**安装 ELK 后,访问 kibana 页面时,提示以下错误信息:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Warning No default index pattern. You must select or create one to continue.\n...\nUnable to fetch mapping. Do you have indices matching the pattern?\n")])])]),s("p",[t._v("这就说明 logstash 没有把日志写入到 elasticsearch。")]),t._v(" "),s("p",[s("strong",[t._v("解决方法:")])]),t._v(" "),s("p",[t._v("检查 logstash 与 elasticsearch 之间的通讯是否有问题,一般问题就出在这。")]),t._v(" "),s("h2",{attrs:{id:"使用"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#使用"}},[t._v("#")]),t._v(" 使用")]),t._v(" "),s("p",[t._v("本人使用的 Java 日志方案为 slf4j + logback,所以这里以 logback 来讲解。")]),t._v(" "),s("h3",{attrs:{id:"java-应用输出日志到-elk"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#java-应用输出日志到-elk"}},[t._v("#")]),t._v(" Java 应用输出日志到 ELK")]),t._v(" "),s("p",[s("strong",[t._v("修改 logstash.conf 配置")])]),t._v(" "),s("p",[t._v("首先,我们需要修改一下 logstash 服务端 logstash.conf 中的配置")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('input { \n # stdin { }\n tcp { \n # host:port就是上面appender中的 destination,\n\t# 这里其实把logstash作为服务,开启9250端口接收logback发出的消息 \n host => "127.0.0.1" port => 9250 mode => "server" tags => ["tags"] codec => json_lines \n }\n}\noutput {\n elasticsearch { hosts => ["localhost:9200"] }\n stdout { codec => rubydebug }\n}\n')])])]),s("blockquote",[s("p",[s("strong",[t._v("说明")])]),t._v(" "),s("p",[t._v("这个 input 中的配置其实是 logstash 服务端监听 9250 端口,接收传递来的日志数据。")])]),t._v(" "),s("p",[t._v("然后,在 Java 应用的 pom.xml 中引入 jar 包:")]),t._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("net.logstash.logback"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("logstash-logback-encoder"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("version")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("4.11"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("p",[t._v("接着,在 logback.xml 中添加 appender")]),t._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("LOGSTASH"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("net.logstash.logback.appender.LogstashTcpSocketAppender"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--\n destination 是 logstash 服务的 host:port,\n 相当于和 logstash 建立了管道,将日志数据定向传输到 logstash\n --\x3e")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("destination")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("127.0.0.1:9250"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("encoder")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("charset")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("UTF-8"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("net.logstash.logback.encoder.LogstashEncoder"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("/>")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("logger")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("name")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("io.github.dunwu.spring"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("level")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("TRACE"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("additivity")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("false"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("appender-ref")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("ref")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[s("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("LOGSTASH"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("/>")])]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("p",[t._v("大功告成,此后,"),s("code",[t._v("io.github.dunwu.spring")]),t._v(" 包中的 TRACE 及以上级别的日志信息都会被定向输出到 logstash 服务。")]),t._v(" "),s("p",[s("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-cd876d79a14955b0.png",alt:"img"}})]),t._v(" "),s("h2",{attrs:{id:"资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#资料"}},[t._v("#")]),t._v(" 资料")]),t._v(" "),s("ul",[s("li",[s("p",[s("a",{attrs:{href:"https://www.elastic.co/guide/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("elastic 官方文档"),s("OutboundLink")],1)])]),t._v(" "),s("li",[s("p",[s("a",{attrs:{href:"https://github.com/elastic/elasticsearch",target:"_blank",rel:"noopener noreferrer"}},[t._v("elasticsearch github"),s("OutboundLink")],1)])]),t._v(" "),s("li",[s("p",[s("a",{attrs:{href:"https://github.com/elastic/logstash",target:"_blank",rel:"noopener noreferrer"}},[t._v("logstash github"),s("OutboundLink")],1)])]),t._v(" "),s("li",[s("p",[s("a",{attrs:{href:"https://github.com/elastic/kibana",target:"_blank",rel:"noopener noreferrer"}},[t._v("kibana github"),s("OutboundLink")],1)])])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/55.3ce3079c.js b/assets/js/55.3ce3079c.js new file mode 100644 index 0000000..0a2a4e2 --- /dev/null +++ b/assets/js/55.3ce3079c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[55],{443:function(r,t,e){"use strict";e.r(t);var a=e(15),s=Object(a.a)({},(function(){var r=this,t=r.$createElement,e=r._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":r.$parent.slotKey}},[e("h1",{attrs:{id:"fastdfs"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#fastdfs"}},[r._v("#")]),r._v(" FastDFS")]),r._v(" "),e("h2",{attrs:{id:"简介"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#简介"}},[r._v("#")]),r._v(" 简介")]),r._v(" "),e("p",[r._v("FastDFS 是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。\nFastDFS 为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。")]),r._v(" "),e("h2",{attrs:{id:"概念"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概念"}},[r._v("#")]),r._v(" 概念")]),r._v(" "),e("p",[r._v("FastDFS 服务端有三个角色:跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)。")]),r._v(" "),e("p",[e("strong",[r._v("tracker server")]),r._v(":跟踪服务器,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的枢纽。相比 GFS 中的 master 更为精简,不记录文件索引信息,占用的内存量很少。")]),r._v(" "),e("p",[r._v("Tracker 是 FastDFS 的协调者,负责管理所有的 storage server 和 group,每个 storage 在启动后会连接 Tracker,告知自己所属的 group 等信息,并保持周期性的心跳,tracker 根据 storage 的心跳信息,建立 group==>[storage server list]的映射表。")]),r._v(" "),e("p",[r._v("Tracker 需要管理的元信息很少,会全部存储在内存中;另外 tracker 上的元信息都是由 storage 汇报的信息生成的,本身不需要持久化任何数据,这样使得 tracker 非常容易扩展,直接增加 tracker 机器即可扩展为 tracker cluster 来服务,cluster 里每个 tracker 之间是完全对等的,所有的 tracker 都接受 stroage 的心跳信息,生成元数据信息来提供读写服务。")]),r._v(" "),e("p",[e("strong",[r._v("storage server")]),r._v(":存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。Storage server 直接利用 OS 的文件系统调用管理文件。")]),r._v(" "),e("p",[r._v("Storage server(后简称 storage)以组(卷,group 或 volume)为单位组织,一个 group 内包含多台 storage 机器,数据互为备份,存储空间以 group 内容量最小的 storage 为准,所以建议 group 内的多个 storage 尽量配置相同,以免造成存储空间的浪费。")]),r._v(" "),e("p",[r._v("以 group 为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group 内 storage server 数量即为该 group 的副本数),比如将不同应用数据存到不同的 group 就能隔离应用数据,同时还可根据应用的访问特性来将应用分配到不同的 group 来做负载均衡;缺点是 group 的容量受单机存储容量的限制,同时当 group 内有机器坏掉时,数据恢复只能依赖 group 内地其他机器,使得恢复时间会很长。")]),r._v(" "),e("p",[r._v("group 内每个 storage 的存储依赖于本地文件系统,storage 可配置多个数据存储目录,比如有 10 块磁盘,分别挂载在"),e("code",[r._v("/data/disk1-/data/disk10")]),r._v(",则可将这 10 个目录都配置为 storage 的数据存储目录。")]),r._v(" "),e("p",[r._v("storage 接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在 storage 第一次启动时,会在每个数据存储目录里创建 2 级子目录,每级 256 个,总共 65536 个文件,新写的文件会以 hash 的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。")]),r._v(" "),e("p",[e("strong",[r._v("client")]),r._v(":客户端,作为业务请求的发起方,通过专有接口,使用 TCP/IP 协议与跟踪器服务器或存储节点进行数据交互。FastDFS 向使用者提供基本文件访问接口,比如 upload、download、append、delete 等,以客户端库的方式提供给用户使用。")]),r._v(" "),e("p",[r._v("另外两个概念:")]),r._v(" "),e("p",[e("strong",[r._v("group")]),r._v(" :组, 也可称为卷。 同组内服务器上的文件是完全相同的 ,同一组内的 storage server 之间是对等的, 文件上传、 删除等操作可以在任意一台 storage server 上进行 。")]),r._v(" "),e("p",[e("strong",[r._v("meta data")]),r._v(" :文件相关属性,键值对( Key Value Pair) 方式,如:width=1024,heigth=768 。")]),r._v(" "),e("p",[e("img",{attrs:{src:"http://www.ityouknow.com/assets/images/2018/fastdfs/fastdfs_arch.png",alt:"img"}})]),r._v(" "),e("p",[r._v("Tracker 相当于 FastDFS 的大脑,不论是上传还是下载都是通过 tracker 来分配资源;客户端一般可以使用 ngnix 等静态服务器来调用或者做一部分的缓存;存储服务器内部分为卷(或者叫做组),卷于卷之间是平行的关系,可以根据资源的使用情况随时增加,卷内服务器文件相互同步备份,以达到容灾的目的。")]),r._v(" "),e("h2",{attrs:{id:"参考资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[r._v("#")]),r._v(" 参考资料")]),r._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"https://github.com/happyfish100/fastdfs",target:"_blank",rel:"noopener noreferrer"}},[r._v("FastDFS 官方 Github"),e("OutboundLink")],1)]),r._v(" "),e("li",[e("a",{attrs:{href:"https://github.com/happyfish100/fastdfs/wiki",target:"_blank",rel:"noopener noreferrer"}},[r._v("FastDFS 官方 wiki"),e("OutboundLink")],1)]),r._v(" "),e("li",[e("a",{attrs:{href:"https://www.cnblogs.com/ityouknow/p/8240976.html",target:"_blank",rel:"noopener noreferrer"}},[r._v("分布式文件系统 FastDFS 详解"),e("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/56.832958c9.js b/assets/js/56.832958c9.js new file mode 100644 index 0000000..341705b --- /dev/null +++ b/assets/js/56.832958c9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[56],{444:function(t,a,s){"use strict";s.r(a);var e=s(15),r=Object(e.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"gitlab-运维"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-运维"}},[t._v("#")]),t._v(" Gitlab 运维")]),t._v(" "),s("h2",{attrs:{id:"一、gitlab-安装"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#一、gitlab-安装"}},[t._v("#")]),t._v(" 一、gitlab 安装")]),t._v(" "),s("h3",{attrs:{id:"gitlab-的普通安装"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-的普通安装"}},[t._v("#")]),t._v(" Gitlab 的普通安装")]),t._v(" "),s("h4",{attrs:{id:"下载"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#下载"}},[t._v("#")]),t._v(" 下载")]),t._v(" "),s("p",[t._v("进入官方下载地址:https://about.gitlab.com/install/ ,如下图,选择合适的版本。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190129155838.png",alt:"img"}})]),t._v(" "),s("p",[t._v("以 CentOS7 为例:")]),t._v(" "),s("h4",{attrs:{id:"安装和配置必要依赖"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装和配置必要依赖"}},[t._v("#")]),t._v(" 安装和配置必要依赖")]),t._v(" "),s("p",[t._v("在系统防火墙中启用 HTTP 和 SSH")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo yum install -y curl policycoreutils-python openssh-server\nsudo systemctl enable sshd\nsudo systemctl start sshd\nsudo firewall-cmd --permanent --add-service=http\nsudo systemctl reload firewalld\n")])])]),s("p",[t._v("安装 Postfix ,使得 Gitlab 可以发送通知邮件")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo yum install postfix\nsudo systemctl enable postfix\nsudo systemctl start postfix\n")])])]),s("h4",{attrs:{id:"添加-gitlab-yum-仓库并安装包"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#添加-gitlab-yum-仓库并安装包"}},[t._v("#")]),t._v(" 添加 Gitlab yum 仓库并安装包")]),t._v(" "),s("p",[t._v("添加 Gitlab yum 仓库")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash\n")])])]),s("p",[t._v("通过 yum 安装 gitlab-ce")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v('sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce\n')])])]),s("p",[t._v("安装完成后,即可通过默认的 root 账户进行登录。更多细节可以参考:"),s("a",{attrs:{href:"https://docs.gitlab.com/omnibus/README.html#installation-and-configuration-using-omnibus-package",target:"_blank",rel:"noopener noreferrer"}},[t._v("documentation for detailed instructions on installing and configuration"),s("OutboundLink")],1)]),t._v(" "),s("h3",{attrs:{id:"gitlab-的-docker-安装"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-的-docker-安装"}},[t._v("#")]),t._v(" Gitlab 的 Docker 安装")]),t._v(" "),s("p",[t._v("拉取镜像")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker pull docker.io/gitlab/gitlab-ce\n")])])]),s("p",[t._v("启动")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker run -d \\\n --hostname gitlab.zp.io \\\n --publish 8443:443 --publish 80:80 --publish 2222:22 \\\n --name gitlab \\\n --restart always \\\n --volume $GITLAB_HOME/config:/etc/gitlab \\\n --volume $GITLAB_HOME/logs:/var/log/gitlab \\\n --volume $GITLAB_HOME/data:/var/opt/gitlab \\\n gitlab/gitlab-ce\n")])])]),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190131150515.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"自签名证书"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#自签名证书"}},[t._v("#")]),t._v(" 自签名证书")]),t._v(" "),s("p",[t._v("首先,创建认证目录")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo mkdir -p /etc/gitlab/ssl\nsudo chmod 700 /etc/gitlab/ssl\n")])])]),s("p",[t._v("(1)创建 Private Key")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo openssl genrsa -des3 -out /etc/gitlab/ssl/gitlab.domain.com.key 2048\n")])])]),s("p",[t._v("会提示输入密码,请记住")]),t._v(" "),s("p",[t._v("(2)生成 Certificate Request")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo openssl req -new -key /etc/gitlab/ssl/gitlab.domain.com.key -out /etc/gitlab/ssl/gitlab.domain.com.csr\n")])])]),s("p",[t._v("根据提示,输入信息")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Country Name (2 letter code) [XX]:CN\nState or Province Name (full name) []:JS\nLocality Name (eg, city) [Default City]:NJ\nOrganization Name (eg, company) [Default Company Ltd]:xxxxx\nOrganizational Unit Name (eg, section) []:\nCommon Name (eg, your name or your server's hostname) []:gitlab.xxxx.io\nEmail Address []:\n\nPlease enter the following 'extra' attributes\nto be sent with your certificate request\nA challenge password []:\nAn optional company name []:\n")])])]),s("p",[t._v("(3)移除 Private Key 中的密码短语")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo cp -v /etc/gitlab/ssl/gitlab.domain.com.{key,original}\nsudo openssl rsa -in /etc/gitlab/ssl/gitlab.domain.com.original -out /etc/gitlab/ssl/gitlab.domain.com.key\nsudo rm -v /etc/gitlab/ssl/gitlab.domain.com.original\n")])])]),s("p",[t._v("(4)设置文件权限")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo chmod 600 /etc/gitlab/ssl/gitlab.domain.com.*\n")])])]),s("h2",{attrs:{id:"二、gitlab-ci-multi-runner-安装"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二、gitlab-ci-multi-runner-安装"}},[t._v("#")]),t._v(" 二、gitlab-ci-multi-runner 安装")]),t._v(" "),s("blockquote",[s("p",[t._v("参考:https://docs.gitlab.com/runner/install/")])]),t._v(" "),s("h3",{attrs:{id:"常规安装-gitlab-ci-multi-runner"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常规安装-gitlab-ci-multi-runner"}},[t._v("#")]),t._v(" 常规安装 gitlab-ci-multi-runner")]),t._v(" "),s("h4",{attrs:{id:"下载-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#下载-2"}},[t._v("#")]),t._v(" 下载")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64\n")])])]),s("h4",{attrs:{id:"配置执行权限"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置执行权限"}},[t._v("#")]),t._v(" 配置执行权限")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo chmod +x /usr/local/bin/gitlab-runner\n")])])]),s("h4",{attrs:{id:"如果想使用-docker-安装-docker-可选的"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#如果想使用-docker-安装-docker-可选的"}},[t._v("#")]),t._v(" 如果想使用 Docker,安装 Docker(可选的)")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("curl -sSL https://get.docker.com/ | sh\n")])])]),s("h4",{attrs:{id:"创建-ci-用户"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建-ci-用户"}},[t._v("#")]),t._v(" 创建 CI 用户")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash\n")])])]),s("h4",{attrs:{id:"安装并启动服务"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装并启动服务"}},[t._v("#")]),t._v(" 安装并启动服务")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner\nsudo gitlab-runner start\n")])])]),s("h4",{attrs:{id:"注册-runner"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#注册-runner"}},[t._v("#")]),t._v(" 注册 Runner")]),t._v(" "),s("p",[t._v("(1)执行命令:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo gitlab-runner register\n")])])]),s("p",[t._v("(2)输入 Gitlab URL 和 令牌")]),t._v(" "),s("p",[t._v("URL 和令牌信息在 Gitlab 的 Runner 管理页面获取:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190129163100.png",alt:"img"}})]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )\nhttps://gitlab.com\n\nPlease enter the gitlab-ci token for this runner\nxxx\n")])])]),s("p",[t._v("(3)输入 Runner 的描述")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" Please enter the gitlab-ci description for this runner\n [hostame] my-runner\n")])])]),s("p",[t._v("(4)输入 Runner 相关的标签")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" Please enter the gitlab-ci tags for this runner (comma separated):\n my-tag,another-tag\n")])])]),s("p",[t._v("(5)输入 Runner 执行器")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:\n docker\n")])])]),s("p",[t._v("如果想选择 Docker 作为执行器,你需要指定默认镜像( "),s("code",[t._v(".gitlab-ci.yml")]),t._v(" 中没有此配置)")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v(" Please enter the Docker image (eg. ruby:2.1):\n alpine:latest\n")])])]),s("h3",{attrs:{id:"docker-安装-gitlab-ci-multi-runner"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#docker-安装-gitlab-ci-multi-runner"}},[t._v("#")]),t._v(" Docker 安装 gitlab-ci-multi-runner")]),t._v(" "),s("p",[t._v("拉取镜像")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker pull docker.io/gitlab/gitlab-runner\n")])])]),s("p",[t._v("启动")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("docker run -d --name gitlab-runner --restart always \\\n -v /srv/gitlab-runner/config:/etc/gitlab-runner \\\n -v /var/run/docker.sock:/var/run/docker.sock \\\n gitlab/gitlab-runner:latest\n")])])]),s("h2",{attrs:{id:"三、gitlab-配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#三、gitlab-配置"}},[t._v("#")]),t._v(" 三、gitlab 配置")]),t._v(" "),s("h3",{attrs:{id:"基本配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#基本配置"}},[t._v("#")]),t._v(" 基本配置")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo vim /etc/gitlab/gitlab.rb\nexternal_url 'https://gitlab.domain.com'\n")])])]),s("h4",{attrs:{id:"gitlab-网站-https"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-网站-https"}},[t._v("#")]),t._v(" gitlab 网站 https:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("nginx['redirect_http_to_https'] = true\n")])])]),s("h4",{attrs:{id:"gitlab-ci-网站-https"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-ci-网站-https"}},[t._v("#")]),t._v(" gitlab ci 网站 https:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("ci_nginx['redirect_http_to_https'] = true\n")])])]),s("h4",{attrs:{id:"复制证书到-gitlab-目录"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#复制证书到-gitlab-目录"}},[t._v("#")]),t._v(" 复制证书到 gitlab 目录:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo cp /etc/gitlab/ssl/gitlab.domain.com.crt /etc/gitlab/trusted-certs/\n")])])]),s("h4",{attrs:{id:"gitlab-重新配置-更新"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#gitlab-重新配置-更新"}},[t._v("#")]),t._v(" gitlab 重新配置+更新:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("sudo gitlab-ctl reconfigure\nsudo gitlab-ctl restart\n")])])]),s("h3",{attrs:{id:"创建你的-ssh-key"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建你的-ssh-key"}},[t._v("#")]),t._v(" 创建你的 SSH key")]),t._v(" "),s("ol",[s("li",[s("p",[t._v("使用 Gitlab 的第一步是生成你自己的 SSH 密钥对(Github 也类似)。")])]),t._v(" "),s("li",[s("p",[t._v("登录 Gitlab")])]),t._v(" "),s("li",[s("p",[t._v("打开 "),s("strong",[t._v("Profile settings")]),t._v(".")])])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/gitlab-basics/img/profile_settings.png",alt:"img"}})]),t._v(" "),s("ol",{attrs:{start:"4"}},[s("li",[t._v("跳转到 "),s("strong",[t._v("SSH keys")]),t._v(" tab 页")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/gitlab-basics/img/profile_settings_ssh_keys.png",alt:"img"}})]),t._v(" "),s("ol",{attrs:{start:"5"}},[s("li",[t._v("黏贴你的 SSH 公钥内容到 Key 文本框")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/gitlab-basics/img/profile_settings_ssh_keys_paste_pub.png",alt:"img"}})]),t._v(" "),s("ol",{attrs:{start:"6"}},[s("li",[t._v("为了便于识别,你可以为其命名")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/gitlab-basics/img/profile_settings_ssh_keys_title.png",alt:"img"}})]),t._v(" "),s("ol",{attrs:{start:"7"}},[s("li",[t._v("点击 "),s("strong",[t._v("Add key")]),t._v(" 将 SSH 公钥添加到 GitLab")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/gitlab-basics/img/profile_settings_ssh_keys_single_key.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"创建项目"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建项目"}},[t._v("#")]),t._v(" 创建项目")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190131150658.png",alt:"img"}})]),t._v(" "),s("p",[t._v("输入项目信息,点击 Create project 按钮,在 Gitlab 创建项目。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190131150759.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"克隆项目到本地"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#克隆项目到本地"}},[t._v("#")]),t._v(" 克隆项目到本地")]),t._v(" "),s("p",[t._v("可以选择 SSH 或 HTTPS 方式克隆项目到本地(推荐 SSH)")]),t._v(" "),s("p",[t._v("拷贝项目地址,然后在本地执行 "),s("code",[t._v("git clone ")])]),t._v(" "),s("h3",{attrs:{id:"创建-issue"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建-issue"}},[t._v("#")]),t._v(" 创建 Issue")]),t._v(" "),s("p",[t._v("依次点击 "),s("strong",[t._v("Project’s Dashboard")]),t._v(" > "),s("strong",[t._v("Issues")]),t._v(" > "),s("strong",[t._v("New Issue")]),t._v(" 可以新建 Issue")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/user/project/issues/img/new_issue_from_tracker_list.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在项目中直接添加 issue")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/user/project/issues/img/new_issue.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在未关闭 issue 中,点击 "),s("strong",[t._v("New Issue")]),t._v(" 添加 issue")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/user/project/issues/img/new_issue_from_open_issue.png",alt:"img"}})]),t._v(" "),s("p",[t._v("通过项目面板添加 issue")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/user/project/issues/img/new_issue_from_projects_dashboard.png",alt:"img"}})]),t._v(" "),s("p",[t._v("通过 issue 面板添加 issue")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://docs.gitlab.com/ce/user/project/issues/img/new_issue_from_issue_board.png",alt:"img"}})]),t._v(" "),s("h2",{attrs:{id:"四、gitlab-权限配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#四、gitlab-权限配置"}},[t._v("#")]),t._v(" 四、gitlab 权限配置")]),t._v(" "),s("h3",{attrs:{id:"用户组的权限"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#用户组的权限"}},[t._v("#")]),t._v(" 用户组的权限")]),t._v(" "),s("ul",[s("li",[t._v("用户组有这几种权限的概念:"),s("code",[t._v("Guest、Reporter、Developer、Master、Owner")])]),t._v(" "),s("li",[t._v("这个概念在设置用户组的时候会遇到,叫做:"),s("code",[t._v("Add user(s) to the group")]),t._v(",比如链接:"),s("code",[t._v("https:///")])])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("行为")]),t._v(" "),s("th",[t._v("Guest")]),t._v(" "),s("th",[t._v("Reporter")]),t._v(" "),s("th",[t._v("Developer")]),t._v(" "),s("th",[t._v("Master")]),t._v(" "),s("th",[t._v("Owner")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("浏览组")]),t._v(" "),s("td",[t._v("✓")]),t._v(" "),s("td",[t._v("✓")]),t._v(" "),s("td",[t._v("✓")]),t._v(" "),s("td",[t._v("✓")]),t._v(" "),s("td",[t._v("✓")])]),t._v(" "),s("tr",[s("td",[t._v("编辑组")]),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td",[t._v("✓")])]),t._v(" "),s("tr",[s("td",[t._v("创建项目")]),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td",[t._v("✓")]),t._v(" "),s("td",[t._v("✓")])]),t._v(" "),s("tr",[s("td",[t._v("管理组成员")]),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td",[t._v("✓")])]),t._v(" "),s("tr",[s("td",[t._v("移除组")]),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td"),t._v(" "),s("td")])])]),t._v(" "),s("h2",{attrs:{id:"五、备份-迁移-升级"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#五、备份-迁移-升级"}},[t._v("#")]),t._v(" 五、备份/迁移/升级")]),t._v(" "),s("h3",{attrs:{id:"备份"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#备份"}},[t._v("#")]),t._v(" 备份")]),t._v(" "),s("h4",{attrs:{id:"手动备份"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#手动备份"}},[t._v("#")]),t._v(" 手动备份")]),t._v(" "),s("p",[t._v("执行 "),s("code",[t._v("gitlab-rake gitlab:backup:create")]),t._v(" 开始备份全量数据,成功后,会在 "),s("code",[t._v("/var/opt/gitlab/backups")]),t._v(" 下生产一个名称类似 "),s("code",[t._v("1585910556_2020_04_03_11.3.0_gitlab_backup.tar")]),t._v(" 的压缩包。")]),t._v(" "),s("h3",{attrs:{id:"定时自动备份"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#定时自动备份"}},[t._v("#")]),t._v(" 定时自动备份")]),t._v(" "),s("p",[t._v("可以利用 crontab 来定时执行备份命令。")]),t._v(" "),s("p",[t._v("执行 "),s("code",[t._v("vim /etc/crontab")]),t._v(" 或 "),s("code",[t._v("crontab -e")]),t._v(" 手动编辑定时任务。")]),t._v(" "),s("h3",{attrs:{id:"迁移"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#迁移"}},[t._v("#")]),t._v(" 迁移")]),t._v(" "),s("blockquote",[s("p",[t._v("迁移前,需要确保新老机器的 Gitlab 版本号一致。")])]),t._v(" "),s("p",[t._v("将备份的压缩包拷贝到新机器的备份路径下(默认为 "),s("code",[t._v("/var/opt/gitlab/backups")]),t._v(")。")]),t._v(" "),s("p",[t._v("(1)将备份文件权限修改为 777,不然可能恢复的时候会出现权限不够,不能解压的问题")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("chmod")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("777")]),t._v(" 1585910556_2020_04_03_11.3.0_gitlab_backup.tar\n")])])]),s("p",[t._v("(2)停止相关数据连接服务")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[t._v("gitlab-ctl stop unicorn\ngitlab-ctl stop sidekiq\n")])])]),s("p",[t._v("(3)从备份文件中恢复 Gitlab")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# gitlab-rake gitlab:backup:restore BACKUP=备份文件编号")]),t._v("\ngitlab-rake gitlab:backup:restore "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("BACKUP")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("1585910556_2020_04_03_11.3.0\n")])])]),s("h3",{attrs:{id:"升级"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#升级"}},[t._v("#")]),t._v(" 升级")]),t._v(" "),s("p",[t._v("升级前,一定要做好备份,记录当前 gitlab 的版本号。")]),t._v(" "),s("p",[t._v("第一步还是使用官方命令进行升级。")]),t._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" yum "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" -y gitlab-ce\n")])])]),s("p",[t._v("如果下载速度理想,就无需手动升级安装。不理想就需要"),s("code",[t._v("停止自动更新")]),t._v(",并手动下载安装包")]),t._v(" "),s("p",[t._v("访问官方地址,下载对应"),s("code",[t._v("版本")]),t._v(",对应"),s("code",[t._v("系统")]),t._v("的安装包。")]),t._v(" "),s("p",[t._v("注:可以根据"),s("code",[t._v("自动升级时下载的版本")]),t._v(",选择对应文件。")]),t._v(" "),s("div",{staticClass:"language-http extra-class"},[s("pre",{pre:!0,attrs:{class:"language-http"}},[s("code",[s("span",{pre:!0,attrs:{class:"token header-name keyword"}},[t._v("https:")]),t._v("//packages.gitlab.com/gitlab/gitlab-ce\n")])])]),s("p",[t._v("安装包手动上传至服务器,并"),s("code",[t._v("替换")]),t._v("下载未完成的安装包。下面是升级缓存地址:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("/var/cache/yum/x86_64/7/gitlab_gitlab-ce/packages/\n")])])]),s("p",[t._v("再次执行官方升级命令即可完成自动安装。")]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),s("ul",[s("li",[t._v("官网:https://about.gitlab.com/")]),t._v(" "),s("li",[t._v("中文网:https://www.gitlab.com.cn/")]),t._v(" "),s("li",[t._v("官网下载:https://about.gitlab.com/downloads/")]),t._v(" "),s("li",[t._v("官网安装说明:https://about.gitlab.com/installation/#centos-7")]),t._v(" "),s("li",[s("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[t._v("操作系统、运维部署总结系列"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/57.961ce896.js b/assets/js/57.961ce896.js new file mode 100644 index 0000000..7522bf2 --- /dev/null +++ b/assets/js/57.961ce896.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[57],{456:function(a,t,v){"use strict";v.r(t);var s=v(15),_=Object(s.a)({},(function(){var a=this,t=a.$createElement,v=a._self._c||t;return v("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[v("h1",{attrs:{id:"jdk-安装"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#jdk-安装"}},[a._v("#")]),a._v(" JDK 安装")]),a._v(" "),v("blockquote",[v("p",[a._v("关键词:JDK, JAVA_HOME, CLASSPATH, PATH")])]),a._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"#jdk-%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4"}},[a._v("JDK 安装步骤")])]),a._v(" "),v("li",[v("a",{attrs:{href:"#windows-%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95"}},[a._v("Windows 系统安装方法")])]),a._v(" "),v("li",[v("a",{attrs:{href:"#linux-%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95"}},[a._v("Linux 系统安装方法")]),a._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"#redhat-%E5%8F%91%E8%A1%8C%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8-rpm-%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95"}},[a._v("RedHat 发行版本使用 rpm 安装方法")])])])]),a._v(" "),v("li",[v("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[a._v("参考资料")])])]),a._v(" "),v("h2",{attrs:{id:"jdk-安装步骤"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#jdk-安装步骤"}},[a._v("#")]),a._v(" JDK 安装步骤")]),a._v(" "),v("p",[a._v("JDK 安装步骤:")]),a._v(" "),v("p",[a._v("(1)下载 JDK")]),a._v(" "),v("p",[a._v("a. 进入 "),v("a",{attrs:{href:"https://www.oracle.com/technetwork/java/javase/downloads/index.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("Java 官网下载页面"),v("OutboundLink")],1),a._v(";")]),a._v(" "),v("p",[a._v("b. 选择需要的版本:")]),a._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20180920181010164121.png",alt:"img"}})]),a._v(" "),v("p",[a._v("c. 选择对应操作系统的安装包:")]),a._v(" "),v("p",[a._v("Windows 系统选择 exe 安装包;Mac 系统选择 dmp 安装包;Linux 系统选择 tar.gz 压缩包(RedHat 发行版可以安装 rpm 包)。")]),a._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20180920181010164308.png",alt:"img"}})]),a._v(" "),v("p",[a._v("(2)运行安装包,按提示逐步安装")]),a._v(" "),v("p",[a._v("(3)配置系统环境变量:"),v("code",[a._v("JAVA_HOME")]),a._v(", "),v("code",[a._v("CLASSPATH")]),a._v(", "),v("code",[a._v("PATH")])]),a._v(" "),v("p",[a._v("(4)验证 Java 是否安装成功")]),a._v(" "),v("h2",{attrs:{id:"windows-系统安装方法"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#windows-系统安装方法"}},[a._v("#")]),a._v(" Windows 系统安装方法")]),a._v(" "),v("p",[a._v("(1)下载 JDK")]),a._v(" "),v("p",[a._v("需要根据 Windows 系统实际情况,选择 exe 安装文件:")]),a._v(" "),v("ul",[v("li",[a._v("32 位计算机选择 Windows x86")]),a._v(" "),v("li",[a._v("64 位计算机选择 Windows x64")])]),a._v(" "),v("p",[a._v("(2)运行安装包,按提示逐步安装")]),a._v(" "),v("p",[a._v("(3)配置系统环境变量")]),a._v(" "),v("p",[a._v('a. 安装完成后,右击"我的电脑",点击"属性",选择"高级系统设置";')]),a._v(" "),v("p",[v("img",{attrs:{src:"https://www.runoob.com/wp-content/uploads/2013/12/win-java1.png",alt:"img"}})]),a._v(" "),v("p",[a._v('b. 选择"高级"选项卡,点击"环境变量";')]),a._v(" "),v("p",[v("img",{attrs:{src:"https://www.runoob.com/wp-content/uploads/2013/12/java-win2.png",alt:"img"}})]),a._v(" "),v("p",[a._v("然后就会出现如下图所示的画面:")]),a._v(" "),v("p",[a._v('在"系统变量"中设置 3 项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击"编辑",不存在则点击"新建"。')]),a._v(" "),v("p",[a._v("变量设置参数如下:")]),a._v(" "),v("ul",[v("li",[v("p",[a._v("变量名:"),v("strong",[a._v("JAVA_HOME")])])]),a._v(" "),v("li",[v("p",[a._v("变量值:"),v("strong",[a._v("C:\\Program Files (x86)\\Java\\jdk1.8.0_91")]),a._v(" // 要根据自己的实际路径配置")])]),a._v(" "),v("li",[v("p",[a._v("变量名:"),v("strong",[a._v("CLASSPATH")])])]),a._v(" "),v("li",[v("p",[a._v("变量值:"),v("strong",[a._v(".;%JAVA_HOME%\\lib\\dt.jar;%JAVA_HOME%\\lib\\tools.jar;")]),a._v(' //记得前面有个"."')])]),a._v(" "),v("li",[v("p",[a._v("变量名:"),v("strong",[a._v("Path")])])]),a._v(" "),v("li",[v("p",[a._v("变量值:"),v("strong",[a._v("%JAVA_HOME%\\bin;%JAVA_HOME%\\jre\\bin;")])])])]),a._v(" "),v("p",[a._v("(4)验证 Java 是否安装成功")]),a._v(" "),v("p",[a._v('a. "开始"->"运行",键入"cmd";')]),a._v(" "),v("p",[a._v("b. 键入命令: "),v("strong",[a._v("java -version")]),a._v("、"),v("strong",[a._v("java")]),a._v("、"),v("strong",[a._v("javac")]),a._v(" 几个命令,出现以下信息,说明环境变量配置成功;")]),a._v(" "),v("p",[v("img",{attrs:{src:"https://www.runoob.com/wp-content/uploads/2013/12/java-win9.png",alt:"img"}})]),a._v(" "),v("h2",{attrs:{id:"linux-系统安装方法"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#linux-系统安装方法"}},[a._v("#")]),a._v(" Linux 系统安装方法")]),a._v(" "),v("p",[a._v("(1)下载 JDK")]),a._v(" "),v("p",[a._v("需要根据 Linux 系统实际情况,选择 tar.gz 压缩包:")]),a._v(" "),v("ul",[v("li",[a._v("32 位计算机选择 Linux x86")]),a._v(" "),v("li",[a._v("64 位计算机选择 Linux x64")])]),a._v(" "),v("p",[a._v("(2)解压压缩包到本地")]),a._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[a._v("$ "),v("span",{pre:!0,attrs:{class:"token function"}},[a._v("tar")]),a._v(" -zxf jdk-8u162-linux-x64.tar.gz\n")])])]),v("p",[a._v("(3)配置系统环境变量")]),a._v(" "),v("p",[a._v("执行 "),v("code",[a._v("/etc/profile")]),a._v(" 命令,添加以下内容:")]),a._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[v("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# JDK 的根路径")]),a._v("\n"),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("export")]),a._v(" "),v("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("JAVA_HOME")]),v("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("/opt/java/jdk1.8.0_162\n"),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("export")]),a._v(" "),v("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("CLASSPATH")]),v("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),v("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$CLASSPATH")]),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(":")]),v("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$JAVA_HOME")]),a._v("/lib:"),v("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$JAVA_HOME")]),a._v("/jre/lib\n"),v("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("export")]),a._v(" "),v("span",{pre:!0,attrs:{class:"token assign-left variable"}},[v("span",{pre:!0,attrs:{class:"token environment constant"}},[a._v("PATH")])]),v("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),v("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$JAVA_HOME")]),a._v("/bin:"),v("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$JAVA_HOME")]),a._v("/jre/bin:"),v("span",{pre:!0,attrs:{class:"token environment constant"}},[a._v("$PATH")]),a._v("\n")])])]),v("p",[a._v("执行 "),v("code",[a._v("source /etc/profile")]),a._v(" ,立即生效")]),a._v(" "),v("p",[a._v("(4)验证 Java 是否安装成功")]),a._v(" "),v("p",[a._v("执行 "),v("code",[a._v("java -version")]),a._v(" 命令,验证安装是否成功。")]),a._v(" "),v("h3",{attrs:{id:"redhat-发行版本使用-rpm-安装方法"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#redhat-发行版本使用-rpm-安装方法"}},[a._v("#")]),a._v(" RedHat 发行版本使用 rpm 安装方法")]),a._v(" "),v("p",[a._v("(1)下载 JDK")]),a._v(" "),v("p",[a._v("下载 rpm 安装包")]),a._v(" "),v("p",[a._v("(2)选择一个合适的版本安装")]),a._v(" "),v("div",{staticClass:"language-bash extra-class"},[v("pre",{pre:!0,attrs:{class:"language-bash"}},[v("code",[a._v("$ "),v("span",{pre:!0,attrs:{class:"token function"}},[a._v("rpm")]),a._v(" -ivh jdk-8u181-linux-x64.rpm\n")])])]),v("p",[a._v("安装成功后,默认安装路径在 "),v("code",[a._v("/usr/local")]),a._v(" 下:")]),a._v(" "),v("p",[a._v("(3)设置环境变量,同压缩包安装。")]),a._v(" "),v("p",[a._v("(4)检验是否安装成功,执行 "),v("code",[a._v("java -version")]),a._v(" 命令")]),a._v(" "),v("h2",{attrs:{id:"更多内容"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#更多内容"}},[a._v("#")]),a._v(" 更多内容")]),a._v(" "),v("ul",[v("li",[v("strong",[a._v("引申")]),a._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[a._v("操作系统、运维部署总结系列"),v("OutboundLink")],1)])])]),a._v(" "),v("li",[v("strong",[a._v("引用")])]),a._v(" "),v("li",[a._v("http://www.runoob.com/java/java-environment-setup.html")]),a._v(" "),v("li",[a._v("https://blog.csdn.net/deliciousion/article/details/78046007")])])])}),[],!1,null,null,null);t.default=_.exports}}]); \ No newline at end of file diff --git a/assets/js/58.6d6fbc82.js b/assets/js/58.6d6fbc82.js new file mode 100644 index 0000000..f4ad6ee --- /dev/null +++ b/assets/js/58.6d6fbc82.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[58],{457:function(t,s,a){"use strict";a.r(s);var e=a(15),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"jenkins-运维"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-运维"}},[t._v("#")]),t._v(" Jenkins 运维")]),t._v(" "),a("blockquote",[a("p",[t._v("环境要求")]),t._v(" "),a("ul",[a("li",[t._v("JDK:JDK7+,官网推荐是 JDK 8")]),t._v(" "),a("li",[t._v("Jenkins:2.190.1")])])]),t._v(" "),a("h2",{attrs:{id:"jenkins-简介"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-简介"}},[t._v("#")]),t._v(" Jenkins 简介")]),t._v(" "),a("h3",{attrs:{id:"jenkins-是什么"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-是什么"}},[t._v("#")]),t._v(" Jenkins 是什么")]),t._v(" "),a("p",[t._v("Jenkins 是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。")]),t._v(" "),a("p",[t._v("Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。")]),t._v(" "),a("h3",{attrs:{id:"ci-cd-是什么"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ci-cd-是什么"}},[t._v("#")]),t._v(" CI/CD 是什么")]),t._v(" "),a("p",[t._v("CI(Continuous integration,中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。借用网络图片对 CI 加以理解。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310174528.png",alt:"img"}})]),t._v(" "),a("p",[t._v("CD(Continuous Delivery, 中文意思持续交付)是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。下图反应的是 CI/CD 的大概工作模式。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310174544.png",alt:"img"}})]),t._v(" "),a("h2",{attrs:{id:"jenkins-安装"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-安装"}},[t._v("#")]),t._v(" Jenkins 安装")]),t._v(" "),a("blockquote",[a("p",[t._v("更详细内容请参考:"),a("a",{attrs:{href:"https://jenkins.io/zh/doc/book/installing/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Jenkins 官方安装文档"),a("OutboundLink")],1)])]),t._v(" "),a("h3",{attrs:{id:"war-包部署"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#war-包部署"}},[t._v("#")]),t._v(" War 包部署")]),t._v(" "),a("p",[t._v("安装步骤如下:")]),t._v(" "),a("p",[t._v("(1)下载并解压到本地")]),t._v(" "),a("p",[t._v("进入"),a("a",{attrs:{href:"https://jenkins.io/zh/download/",target:"_blank",rel:"noopener noreferrer"}},[t._v("官网下载地址"),a("OutboundLink")],1),t._v(",选择合适的版本下载。")]),t._v(" "),a("p",[t._v("我选择的是最新稳定 war 版本 2.89.4:http://mirrors.jenkins.io/war-stable/latest/jenkins.war")]),t._v(" "),a("p",[t._v("我个人喜欢存放在:"),a("code",[t._v("/opt/software/jenkins")])]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("mkdir")]),t._v(" -p /opt/software/jenkins\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("wget")]),t._v(" -O /opt/software/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.wa\n")])])]),a("p",[t._v("(2)启动")]),t._v(" "),a("p",[t._v("如果你和我一样,选择 war 版本,那么你可以将 war 移到 Tomcat 的 webapps 目录下,通过 Tomcat 来启动。")]),t._v(" "),a("p",[t._v("当然,也可以通过 "),a("code",[t._v("java -jar")]),t._v(" 方式来启动。")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" /opt/software/jenkins\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("nohup")]),t._v(" java -jar jenkins.war --httpPort"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("8080")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">>")]),t._v(" nohup.out "),a("span",{pre:!0,attrs:{class:"token operator"}},[a("span",{pre:!0,attrs:{class:"token file-descriptor important"}},[t._v("2")]),t._v(">")]),a("span",{pre:!0,attrs:{class:"token file-descriptor important"}},[t._v("&1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("\n")])])]),a("h3",{attrs:{id:"rpm-包部署"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rpm-包部署"}},[t._v("#")]),t._v(" rpm 包部署")]),t._v(" "),a("p",[t._v("(1)下载安装")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("wget")]),t._v(" -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sudo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rpm")]),t._v(" --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key\nyum "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" jenkins\n")])])]),a("p",[t._v("(2)启动")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[t._v("systemctl start jenkins\n")])])]),a("h3",{attrs:{id:"访问"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#访问"}},[t._v("#")]),t._v(" 访问")]),t._v(" "),a("ol",[a("li",[t._v("打开浏览器进入链接 "),a("code",[t._v("http://localhost:8080")]),t._v(".")]),t._v(" "),a("li",[t._v("按照说明完成安装.")])]),t._v(" "),a("h2",{attrs:{id:"jenkins-基本使用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-基本使用"}},[t._v("#")]),t._v(" Jenkins 基本使用")]),t._v(" "),a("p",[t._v("Jenkins 是一个强大的 CI 工具,虽然本身使用 Java 开发,但也能用来做其他语言开发的项目 CI。下面讲解如何使用 Jenkins 创建一个构建任务。")]),t._v(" "),a("p",[t._v("登录 Jenkins, 点击左侧的新建,创建新的构建任务。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-22b3c49af599565d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/374/format/webp",alt:"img"}})]),t._v(" "),a("p",[t._v("跳转到如下界面。任务名称可以自行设定,但需要全局唯一。输入名称后选择构建一个自由风格的软件项目(其他选项不作介绍)。并点击下方的确定按钮即创建了一个构建任务。之后会自动跳转到该 job 的配置页面。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-0febc0bc4ca3cadd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1044/format/webp",alt:"img"}})]),t._v(" "),a("p",[t._v("新建自由风格的软件项目")]),t._v(" "),a("p",[t._v('下图是构建任务设置界面,可以看到上方的几个选项**"General", "源码管理", "构建触发器","构建环境", "构建", "构建后操作"**。下面逐一介绍。')]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-77998a3e6a70b83f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1032/format/webp",alt:"img"}})]),t._v(" "),a("h3",{attrs:{id:"general"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#general"}},[t._v("#")]),t._v(" General")]),t._v(" "),a("p",[t._v("General 是构建任务的一些基本配置。名称,描述之类的。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310221814.png",alt:"img"}})]),t._v(" "),a("p",[t._v("重要配置项:")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Description")]),t._v(":对构建任务的描述。")]),t._v(" "),a("li",[a("strong",[t._v("Discard old builds")]),t._v(':服务器资源是有限的,有时候保存了太多的历史构建,会导致 Jenkins 速度变慢,并且服务器硬盘资源也会被占满。当然下方的"保持构建天数" 和 保持构建的最大个数是可以自定义的,需要根据实际情况确定一个合理的值。')])]),t._v(" "),a("p",[t._v("点击右方的问号图标可以查看帮助信息。")]),t._v(" "),a("h3",{attrs:{id:"source-code-management"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#source-code-management"}},[t._v("#")]),t._v(" Source Code Management")]),t._v(" "),a("p",[a("strong",[t._v("Source Code Management")]),t._v(",即源码管理,就是配置你代码的存放位置。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310222110.png",alt:"img"}})]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Git:")]),t._v(" 支持主流的 Github 和 Gitlab 代码仓库。因我们的研发团队使用的是 gitlab,所以下面我只会对该项进行介绍。")]),t._v(" "),a("li",[a("strong",[t._v("Repository URL")]),t._v(":仓库地址。")]),t._v(" "),a("li",[a("strong",[t._v("Credentials")]),t._v(':凭证。可以使用 HTTP 方式的用户名密码,也可以是 RSA 文件。 但要通过后面的"ADD"按钮添加凭证。')]),t._v(" "),a("li",[a("strong",[t._v("Branches to build")]),t._v(":构建的分支。"),a("code",[t._v("*/master")]),t._v(" 表示 master 分支,也可以设置为其他分支。")]),t._v(" "),a("li",[a("strong",[t._v("Repository browser")]),t._v(":你所使用的代码仓库管理工具,如 Github、Gitlab.")]),t._v(" "),a("li",[a("strong",[t._v("Subversion")]),t._v(":即 SVN,这里不作介绍。")])]),t._v(" "),a("h3",{attrs:{id:"build-triggers"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#build-triggers"}},[t._v("#")]),t._v(" Build Triggers")]),t._v(" "),a("p",[a("strong",[t._v("Build Triggers")]),t._v(",即构建触发器,用于构建任务的触发器。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310222608.png",alt:"img"}})]),t._v(" "),a("p",[t._v("配置说明:")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Trigger builds remotely (e.g., from scripts)")]),t._v(":触发远程构建(例如,使用脚本)。该选项会提供一个接口,可以用来在代码层面触发构建。")]),t._v(" "),a("li",[a("strong",[t._v("Build after other projects are built")]),t._v(':该选项意思是"在其他项目构建后再构建"。')]),t._v(" "),a("li",[a("strong",[t._v("Build periodically")]),t._v(":周期性的构建。就是每隔一段时间进行构建。日程表类似 linux crontab 书写格式。如:"),a("code",[t._v("H/30 * * * *")]),t._v(",表示每隔 30 分钟进行一次构建。")]),t._v(" "),a("li",[t._v("**Build when a change is pushed to GitLab:**当有 git push 到 Gitlab 仓库,即触发构建。后面会有一个触发构建的地址,一般被称为 webhooks。需要将这个地址配置到 gitlab 中,webhooks 如何配置后面介绍。这个是常用的构建触发器。")]),t._v(" "),a("li",[t._v("**Poll SCM:**该选项是配合上面这个选项使用的。当代码仓库发生改动,jenkins 并不知道。需要配置这个选项,周期性的去检查代码仓库是否发生改动。")])]),t._v(" "),a("h3",{attrs:{id:"build-environment"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#build-environment"}},[t._v("#")]),t._v(" Build Environment")]),t._v(" "),a("p",[a("strong",[t._v("Build Environment")]),t._v(",即构建环境,配置构建前的一些准备工作,如指定构建工具。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310223004.png",alt:"img"}})]),t._v(" "),a("h3",{attrs:{id:"build"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#build"}},[t._v("#")]),t._v(" Build")]),t._v(" "),a("p",[t._v("Build,即构建。")]),t._v(" "),a("p",[t._v("点击下图中的 Add build step 按钮,会弹出一个构建任务菜单,可以根据实际需要来选择。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310223241.png",alt:"img"}})]),t._v(" "),a("p",[t._v("【说明】")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Copy artifacts from another project")]),t._v(":从其他项目获取构建。一般当本任务有上游任务,需要获取上游任务的构件时使用。比如:有个 Java Web 项目,需要依赖于上一个前端构建任务输出的静态文件压缩包。")]),t._v(" "),a("li",[t._v("Eexcute NodeJS script:执行 Nodejs 脚本。默认支持 nodejs、npm 命令。")]),t._v(" "),a("li",[a("strong",[t._v("Eexcute shell")]),t._v(": 执行 shell 脚本。用于 Linux 环境。")]),t._v(" "),a("li",[a("strong",[t._v("Execute Windows batch command")]),t._v(":执行 batch 脚本。用于 Windows 环境。")]),t._v(" "),a("li",[a("strong",[t._v("Invoke Ant")]),t._v(":Ant 是一款 java 项目构建工具。")]),t._v(" "),a("li",[a("strong",[t._v("Invoke Gradle script")]),t._v(":Gradle 构建项目。")]),t._v(" "),a("li",[a("strong",[t._v("Invoke top-level Maven targets")]),t._v(":Maven 构建项目。")])]),t._v(" "),a("h3",{attrs:{id:"post-build-actions"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#post-build-actions"}},[t._v("#")]),t._v(" Post-build Actions")]),t._v(" "),a("p",[a("strong",[t._v("Post-build Actions")]),t._v(",即构建后操作,用于构建完本项目的一些后续操作,比如生成相应的代码测试报告。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310224106.png",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310224254.png",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310224331.png",alt:"img"}})]),t._v(" "),a("p",[t._v("个人较常用的配置:")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Archive the artifacts")]),t._v(":归档构件。")]),t._v(" "),a("li",[a("strong",[t._v("Build other projects")]),t._v(":构建其他项目。")]),t._v(" "),a("li",[a("strong",[t._v("Trigger parameterized build on other projects")]),t._v(":构建其他项目,并传输构建参数。")]),t._v(" "),a("li",[a("strong",[t._v("Publish JUnit test result report")]),t._v(":发布 Junit 测试报告。")]),t._v(" "),a("li",[a("strong",[t._v("E-mail Notification")]),t._v(":邮件通知,构建完成后发邮件到指定的邮箱。")])]),t._v(" "),a("hr"),t._v(" "),a("p",[a("strong",[t._v("以上配置完成后,点击保存即可。")])]),t._v(" "),a("h3",{attrs:{id:"开始构建"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#开始构建"}},[t._v("#")]),t._v(" 开始构建")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310224927.png",alt:"img"}})]),t._v(" "),a("p",[t._v("如上图所示,一切配置好后,即可点击 "),a("strong",[t._v("Build Now")]),t._v(" 开始构建。")]),t._v(" "),a("h3",{attrs:{id:"构建结果"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#构建结果"}},[t._v("#")]),t._v(" 构建结果")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200310225234.png",alt:"img"}})]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("构建状态")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("Successful 蓝色")]),t._v(":构建完成,并且被认为是稳定的。")]),t._v(" "),a("li",[a("strong",[t._v("Unstable 黄色")]),t._v(":构建完成,但被认为是不稳定的。")]),t._v(" "),a("li",[a("strong",[t._v("Failed 红色")]),t._v(":构建失败。")]),t._v(" "),a("li",[a("strong",[t._v("Disable 灰色")]),t._v(":构建已禁用")])])]),t._v(" "),a("li",[a("strong",[t._v("构建稳定性")]),t._v(" "),a("ul",[a("li",[t._v("构建稳定性用天气表示:"),a("strong",[t._v("晴、晴转多云、多云、小雨、雷阵雨")]),t._v("。天气越好表示构建越稳定,反之亦然。")])])]),t._v(" "),a("li",[t._v("构建历史界面\n"),a("ul",[a("li",[a("strong",[t._v("console output")]),t._v(":输出构建的日志信息")])])])]),t._v(" "),a("h2",{attrs:{id:"其他相关配置"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#其他相关配置"}},[t._v("#")]),t._v(" 其他相关配置")]),t._v(" "),a("h3",{attrs:{id:"ssh-server-配置"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#ssh-server-配置"}},[t._v("#")]),t._v(" SSH Server 配置")]),t._v(" "),a("p",[t._v("登录 jenkins -> 系统管理 -> 系统设置")]),t._v(" "),a("p",[t._v("配置请看下图:")]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-15476f9e273daa58.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1108/format/webp",alt:"img"}})]),t._v(" "),a("p",[t._v("重要配置:")]),t._v(" "),a("ul",[a("li",[a("p",[a("strong",[t._v("SSH Servers:")]),t._v(" 由于 jenkins 服务器公钥文件我已经配置好,所以之后新增 SSH Servers 只需要配置这一项即可。")])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("Name:")]),t._v(" 自定义,需要全局唯一。")])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("HostName:")]),t._v(" 主机名,直接用 ip 地址即可。")])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("Username:")]),t._v(" 新增 Server 的用户名,这里配置的是 root。")])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("Remote Directory:")]),t._v(" 远程目录。jenkins 服务器发送文件给新增的 server 默认是在这个目录。")])])]),t._v(" "),a("h3",{attrs:{id:"配置-gitlab-webhooks"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-gitlab-webhooks"}},[t._v("#")]),t._v(" 配置 Gitlab webhooks")]),t._v(" "),a("p",[t._v("在 gitlab 的 project 页面 打开"),a("strong",[t._v("settings")]),t._v(",再打开 "),a("strong",[t._v("web hooks")]),t._v(' 。点击**"ADD WEB HOOK"** 添加 webhook。把之前 jenkins 配置中的那个 url 添加到这里,添加完成后,点击**"TEST HOOK"**进行测试,如果显示 SUCCESS 则表示添加成功。')]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-9f8d04a1400556f9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/246/format/webp",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-154a62db330c819b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/240/format/webp",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-e4d1ea1e1dbde812.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1036/format/webp",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-c7a687207b2c26fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1106/format/webp",alt:"img"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-ce8ae810bc2cb0d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1154/format/webp",alt:"img"}})]),t._v(" "),a("p",[t._v("配置 phpunit.xml")]),t._v(" "),a("p",[t._v('phpunit.xml 是 phpunit 这个工具用来单元测试所需要的配置文件。这个文件的名称同样也是可以自定义的,但是要在"build.xml"中配置好名字就行。默认情况下,用"phpunit.xml", 则不需要在"build.xml"中配置文件名。')]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-aa212d3b3eaff548.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/798/format/webp",alt:"img"}})]),t._v(" "),a("p",[t._v("build.xml 中 phpunit 配置")]),t._v(" "),a("p",[t._v("fileset dir 指定单元测试文件所在路径,include 指定包含哪些文件,支持通配符匹配。当然也可以用 exclude 关键字指定不包含的文件。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https:////upload-images.jianshu.io/upload_images/6464255-dbc0084f6d50a240.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1200/format/webp",alt:"img"}})]),t._v(" "),a("h3",{attrs:{id:"jenkins-权限管理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-权限管理"}},[t._v("#")]),t._v(" jenkins 权限管理")]),t._v(" "),a("p",[t._v("由于 jenkins 默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,本文将使用 Role Strategy Plugin。基于这个插件的权限管理设置请参考这篇文章:"),a("a",{attrs:{href:"https://link.jianshu.com?t=http%3A%2F%2Fblog.csdn.net%2Fruss44%2Farticle%2Fdetails%2F52276222",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://blog.csdn.net/russ44/article/details/52276222"),a("OutboundLink")],1),t._v(",这里不作详细介绍。")]),t._v(" "),a("p",[t._v("至此,就可以用 jenkins 周而复始的进行 CI 了,当然 jenkins 是一个强大的工具,功能绝不仅仅是以上这些,其他方面要是以后用到,我会更新到这篇文章中。有疑问欢迎在下方留言。")]),t._v(" "),a("h2",{attrs:{id:"jenkins-faq"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jenkins-faq"}},[t._v("#")]),t._v(" Jenkins FAQ")]),t._v(" "),a("h3",{attrs:{id:"登录密码"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#登录密码"}},[t._v("#")]),t._v(" 登录密码")]),t._v(" "),a("p",[t._v("如果不知道初始登录密码,可以通过以下方式查看:")]),t._v(" "),a("p",[t._v("执行命令 "),a("code",[t._v("cat /root/.jenkins/secrets/initialAdminPassword")]),t._v(",打印出来的即是初始登录密码。")]),t._v(" "),a("h3",{attrs:{id:"忘记密码"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#忘记密码"}},[t._v("#")]),t._v(" 忘记密码")]),t._v(" "),a("p",[t._v("1.执行 "),a("code",[t._v("vim /root/.jenkins/config.xml")]),t._v(" ,删除以下内容")]),t._v(" "),a("div",{staticClass:"language-xml extra-class"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("useSecurity")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("authorizationStrategy")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("hudson.security.FullControlOnceLoggedInAuthorizationStrategy"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("denyAnonymousReadAccess")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("securityRealm")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("hudson.security.HudsonPrivateSecurityRealm"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("disableSignup")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("enableCaptcha")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("false"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),a("p",[t._v("2.重启 Jenkins 服务;")]),t._v(" "),a("p",[t._v("3.进入首页>“系统管理”>“Configure Global Security”;")]),t._v(" "),a("p",[t._v("4.勾选“启用安全”;")]),t._v(" "),a("p",[t._v("5.点选“Jenkins 专有用户数据库”,并点击“保存”;")]),t._v(" "),a("p",[t._v("6.重新点击首页>“系统管理”,发现此时出现“管理用户”;")]),t._v(" "),a("p",[t._v("7.点击进入展示“用户列表”;")]),t._v(" "),a("p",[t._v("8.点击右侧进入修改密码页面,修改后即可重新登录。")]),t._v(" "),a("h3",{attrs:{id:"卡在-check-页面"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#卡在-check-页面"}},[t._v("#")]),t._v(" 卡在 check 页面")]),t._v(" "),a("p",[a("strong",[t._v("现象")]),t._v(":输入密码后,卡在 check 页面")]),t._v(" "),a("p",[a("strong",[t._v("原因")]),t._v(":jenkins 在安装插件前总是尝试连接 www.google.com,来判断网络是否连通。谷歌的网站在大陆是连不上的,所以会出现这个问题。")]),t._v(" "),a("p",[a("strong",[t._v("解决方案")]),t._v(":执行"),a("code",[t._v("vim /root/.jenkins/updates/default.json")]),t._v(",将 "),a("code",[t._v("connectionCheckUrl")]),t._v(" 后的 "),a("code",[t._v("www.google.com")]),t._v(" 改为 "),a("code",[t._v("www.baidu.com")]),t._v(" 。然后重启即可。")]),t._v(" "),a("p",[t._v("或者直接执行命令:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sed")]),t._v(" -i "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'s/www.google.com/www.baidu.com/g'")]),t._v(" /root/.jenkins/updates/default.json\n")])])]),a("h3",{attrs:{id:"卡在-getting-startted-页面"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#卡在-getting-startted-页面"}},[t._v("#")]),t._v(" 卡在 getting startted 页面")]),t._v(" "),a("p",[a("strong",[t._v("现象")]),t._v(":卡在 getting startted 页面")]),t._v(" "),a("p",[a("strong",[t._v("原因")]),t._v(":jenkins 默认的插件下载服务器地址在国外,如果不翻墙下载不了。")]),t._v(" "),a("p",[a("strong",[t._v("解决方案")]),t._v(":执行"),a("code",[t._v("vim /root/.jenkins/hudson.model.UpdateCenter.xml")]),t._v(",将 "),a("code",[t._v("")]),t._v(" 改为 "),a("code",[t._v("http://mirror.xmission.com/jenkins/updates/update-center.json")]),t._v(" 。然后重启即可。")]),t._v(" "),a("p",[t._v("或者直接执行命令:")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("sed")]),t._v(" -i "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'/^/s/.*/http:\\/\\/mirror.xmission.com\\/jenkins\\/updates\\/update-center.json<\\/url>/g'")]),t._v(" /root/.jenkins/hudson.model.UpdateCenter.xml\n")])])]),a("h3",{attrs:{id:"以-root-用户运行"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#以-root-用户运行"}},[t._v("#")]),t._v(" 以 root 用户运行")]),t._v(" "),a("p",[t._v("(1)修改 jenkins 用户")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("vim")]),t._v(" /etc/sysconfig/jenkins\n")])])]),a("p",[t._v("修改用户")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token variable"}},[t._v("$JENKINS_USER")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"root"')]),t._v("\n")])])]),a("p",[t._v("(2)修改 "),a("code",[t._v("Jenkins")]),t._v(" 相关文件夹用户权限")]),t._v(" "),a("div",{staticClass:"language-bash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-bash"}},[a("code",[a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R root:root /var/lib/jenkins\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R root:root /var/cache/jenkins\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("chown")]),t._v(" -R root:root /var/log/jenkins\n")])])]),a("p",[t._v("(3)重启 Jenkins")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("systemctl restart jenkins\n")])])]),a("h2",{attrs:{id:"参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),a("ul",[a("li",[a("p",[a("strong",[t._v("官方")])]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://jenkins.io/zh/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Jenkins 官网"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://jenkins.io/zh/doc/tutorials/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Jenkins 中文文档"),a("OutboundLink")],1)])])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("引申")])]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[t._v("操作系统、运维部署总结系列"),a("OutboundLink")],1)])])]),t._v(" "),a("li",[a("p",[a("strong",[t._v("文章")])]),t._v(" "),a("ul",[a("li",[t._v("https://jenkins.io/doc/pipeline/tour/getting-started/")]),t._v(" "),a("li",[t._v("https://www.cnblogs.com/austinspark-jessylu/p/6894944.html")]),t._v(" "),a("li",[t._v("http://blog.csdn.net/jlminghui/article/details/54952148")]),t._v(" "),a("li",[a("a",{attrs:{href:"https://www.jianshu.com/p/5f671aca2b5a",target:"_blank",rel:"noopener noreferrer"}},[t._v("Jenkins 详细教程"),a("OutboundLink")],1)])])])])])}),[],!1,null,null,null);s.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/59.d5e48112.js b/assets/js/59.d5e48112.js new file mode 100644 index 0000000..bfeb857 --- /dev/null +++ b/assets/js/59.d5e48112.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[59],{455:function(e,a,t){"use strict";t.r(a);var s=t(15),r=Object(s.a)({},(function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"kafka-安装部署"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#kafka-安装部署"}},[e._v("#")]),e._v(" Kafka 安装部署")]),e._v(" "),t("blockquote",[t("p",[e._v("环境要求:")]),e._v(" "),t("ul",[t("li",[e._v("JDK8")]),e._v(" "),t("li",[e._v("ZooKeeper")])])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"#%E4%B8%8B%E8%BD%BD%E8%A7%A3%E5%8E%8B"}},[e._v("下载解压")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%E5%99%A8"}},[e._v("启动服务器")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%81%9C%E6%AD%A2%E6%9C%8D%E5%8A%A1%E5%99%A8"}},[e._v("停止服务器")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E5%88%9B%E5%BB%BA%E4%B8%BB%E9%A2%98"}},[e._v("创建主题")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A7%E6%B6%88%E6%81%AF"}},[e._v("生产者生产消息")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E6%B6%88%E8%B4%B9%E8%80%85%E6%B6%88%E8%B4%B9%E6%B6%88%E6%81%AF"}},[e._v("消费者消费消息")])]),e._v(" "),t("li",[t("a",{attrs:{href:"#%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2"}},[e._v("集群部署")])])]),e._v(" "),t("h2",{attrs:{id:"下载解压"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#下载解压"}},[e._v("#")]),e._v(" 下载解压")]),e._v(" "),t("p",[e._v("进入官方下载地址:http://kafka.apache.org/downloads,选择合适版本。")]),e._v(" "),t("p",[e._v("解压到本地:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> tar -xzf kafka_2.11-1.1.0.tgz\n> cd kafka_2.11-1.1.0\n")])])]),t("p",[e._v("现在您已经在您的机器上下载了最新版本的 Kafka。")]),e._v(" "),t("h2",{attrs:{id:"启动服务器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#启动服务器"}},[e._v("#")]),e._v(" 启动服务器")]),e._v(" "),t("p",[e._v("由于 Kafka 依赖于 ZooKeeper,所以运行前需要先启动 ZooKeeper")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/zookeeper-server-start.sh config/zookeeper.properties\n[2013-04-22 15:01:37,495] INFO Reading configuration from: config/zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)\n...\n")])])]),t("p",[e._v("然后,启动 Kafka")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-server-start.sh config/server.properties\n[2013-04-22 15:01:47,028] INFO Verifying properties (kafka.utils.VerifiableProperties)\n[2013-04-22 15:01:47,051] INFO Property socket.send.buffer.bytes is overridden to 1048576 (kafka.utils.VerifiableProperties)\n...\n")])])]),t("h2",{attrs:{id:"停止服务器"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#停止服务器"}},[e._v("#")]),e._v(" 停止服务器")]),e._v(" "),t("p",[e._v("执行所有操作后,可以使用以下命令停止服务器")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("$ bin/kafka-server-stop.sh config/server.properties\n")])])]),t("h2",{attrs:{id:"创建主题"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#创建主题"}},[e._v("#")]),e._v(" 创建主题")]),e._v(" "),t("p",[e._v("创建一个名为 test 的 Topic,这个 Topic 只有一个分区以及一个备份:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test\n")])])]),t("h2",{attrs:{id:"生产者生产消息"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#生产者生产消息"}},[e._v("#")]),e._v(" 生产者生产消息")]),e._v(" "),t("p",[e._v("运行生产者,然后可以在控制台中输入一些消息,这些消息会发送到服务器:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test\nThis is a message\nThis is another message\n")])])]),t("h2",{attrs:{id:"消费者消费消息"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#消费者消费消息"}},[e._v("#")]),e._v(" 消费者消费消息")]),e._v(" "),t("p",[e._v("启动消费者,然后获得服务器中 Topic 下的消息:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning\nThis is a message\nThis is another message\n")])])]),t("h2",{attrs:{id:"集群部署"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#集群部署"}},[e._v("#")]),e._v(" 集群部署")]),e._v(" "),t("p",[e._v("复制配置为多份(Windows 使用 copy 命令代理):")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> cp config/server.properties config/server-1.properties\n> cp config/server.properties config/server-2.properties\n")])])]),t("p",[e._v("修改配置:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("config/server-1.properties:\n broker.id=1\n listeners=PLAINTEXT://:9093\n log.dir=/tmp/kafka-logs-1\n\nconfig/server-2.properties:\n broker.id=2\n listeners=PLAINTEXT://:9094\n log.dir=/tmp/kafka-logs-2\n")])])]),t("p",[e._v("其中,broker.id 这个参数必须是唯一的。")]),e._v(" "),t("p",[e._v("端口故意配置的不一致,是为了可以在一台机器启动多个应用节点。")]),e._v(" "),t("p",[e._v("根据这两份配置启动三个服务器节点:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-server-start.sh config/server.properties &\n...\n> bin/kafka-server-start.sh config/server-1.properties &\n...\n> bin/kafka-server-start.sh config/server-2.properties &\n...\n")])])]),t("p",[e._v("创建一个新的 Topic 使用 三个备份:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic\n")])])]),t("p",[e._v("查看主题:")]),e._v(" "),t("div",{staticClass:"language- extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[e._v("> bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic\nTopic:my-replicated-topic PartitionCount:1 ReplicationFactor:3 Configs:\n Topic: my-replicated-topic Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0\n")])])]),t("ul",[t("li",[e._v("leader - 负责指定分区的所有读取和写入的节点。每个节点将成为随机选择的分区部分的领导者。")]),e._v(" "),t("li",[e._v("replicas - 是复制此分区日志的节点列表,无论它们是否为领导者,或者即使它们当前处于活动状态。")]),e._v(" "),t("li",[e._v("isr - 是“同步”复制品的集合。这是副本列表的子集,该列表当前处于活跃状态并且已经被领导者捕获。")])]),e._v(" "),t("h2",{attrs:{id:"更多内容"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#更多内容"}},[e._v("#")]),e._v(" 更多内容")]),e._v(" "),t("ul",[t("li",[t("strong",[e._v("引申")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[e._v("操作系统、运维部署总结系列"),t("OutboundLink")],1)])])])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/6.c8f4721c.js b/assets/js/6.c8f4721c.js new file mode 100644 index 0000000..5a13ff9 --- /dev/null +++ b/assets/js/6.c8f4721c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{345:function(t,e,n){},376:function(t,e,n){"use strict";n(345)},458:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(376),n(15)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/60.7927b23b.js b/assets/js/60.7927b23b.js new file mode 100644 index 0000000..c01542d --- /dev/null +++ b/assets/js/60.7927b23b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[60],{445:function(t,e,a){"use strict";a.r(e);var v=a(15),r=Object(v.a)({},(function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"maven-安装"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#maven-安装"}},[t._v("#")]),t._v(" Maven 安装")]),t._v(" "),a("blockquote",[a("p",[t._v("环境要求:")]),t._v(" "),a("ul",[a("li",[t._v("JDK")])])]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"#%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95"}},[t._v("安装方法")])]),t._v(" "),a("li",[a("a",{attrs:{href:"#%E8%84%9A%E6%9C%AC"}},[t._v("脚本")])])]),t._v(" "),a("h2",{attrs:{id:"安装方法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#安装方法"}},[t._v("#")]),t._v(" 安装方法")]),t._v(" "),a("p",[t._v("安装步骤如下:")]),t._v(" "),a("p",[t._v("(1)下载")]),t._v(" "),a("p",[t._v("进入官网下载地址:https://maven.apache.org/download.cgi ,选择合适的版本下载。")]),t._v(" "),a("p",[t._v("我选择的是最新 Maven3 版本:http://mirrors.hust.edu.cn/apache/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz")]),t._v(" "),a("p",[t._v("(2)解压到本地")]),t._v(" "),a("p",[t._v("我个人喜欢存放在:"),a("code",[t._v("/opt/maven")])]),t._v(" "),a("p",[t._v("(3)设置环境变量")]),t._v(" "),a("p",[t._v("输入 "),a("code",[t._v("vi /etc/profile")]),t._v(" ,添加环境变量如下:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("# MAVEN 的根路径\nexport MAVEN_HOME=/opt/maven/apache-maven-3.5.2\nexport PATH=\\$MAVEN_HOME/bin:\\$PATH\n")])])]),a("p",[t._v("执行 "),a("code",[t._v("source /etc/profile")]),t._v(" ,立即生效")]),t._v(" "),a("p",[t._v("(4)检验是否安装成功,执行 "),a("code",[t._v("mvn -v")]),t._v(" 命令")]),t._v(" "),a("h2",{attrs:{id:"脚本"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),a("p",[t._v("以上两种安装方式,我都写了脚本去执行:")]),t._v(" "),a("p",[t._v("| "),a("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft",target:"_blank",rel:"noopener noreferrer"}},[t._v("安装脚本"),a("OutboundLink")],1),t._v(" |")])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/61.ee233f24.js b/assets/js/61.ee233f24.js new file mode 100644 index 0000000..ff94130 --- /dev/null +++ b/assets/js/61.ee233f24.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[61],{446:function(t,a,o){"use strict";o.r(a);var n=o(15),s=Object(n.a)({},(function(){var t=this,a=t.$createElement,o=t._self._c||a;return o("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[o("h1",{attrs:{id:"mongodb-安装"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#mongodb-安装"}},[t._v("#")]),t._v(" Mongodb 安装")]),t._v(" "),o("ul",[o("li",[o("a",{attrs:{href:"#%E5%AE%89%E8%A3%85"}},[t._v("安装")])]),t._v(" "),o("li",[o("a",{attrs:{href:"#%E5%90%AF%E5%8A%A8"}},[t._v("启动")])]),t._v(" "),o("li",[o("a",{attrs:{href:"#%E8%84%9A%E6%9C%AC"}},[t._v("脚本")])])]),t._v(" "),o("h2",{attrs:{id:"安装"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[t._v("#")]),t._v(" 安装")]),t._v(" "),o("p",[t._v("安装步骤如下:")]),t._v(" "),o("p",[t._v("(1)下载并解压到本地")]),t._v(" "),o("p",[t._v("进入官网下载地址:https://www.mongodb.com/download-center#community ,选择合适的版本下载。")]),t._v(" "),o("p",[t._v("我选择的是最新稳定版本 3.6.3:https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz")]),t._v(" "),o("p",[t._v("我个人喜欢存放在:"),o("code",[t._v("/opt/mongodb")])]),t._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",{pre:!0,attrs:{class:"language-text"}},[o("code",[t._v("wget -O /opt/mongodb/mongodb-linux-x86_64-3.6.3.tgz https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz\ncd /opt/mongodb\ntar zxvf mongodb-linux-x86_64-3.6.3.tgz\nmv mongodb-linux-x86_64-3.6.3 mongodb-3.6.3\nmkdir -p /data/db\n")])])]),o("h2",{attrs:{id:"启动"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#启动"}},[t._v("#")]),t._v(" 启动")]),t._v(" "),o("p",[o("strong",[t._v("启动 mongodb 服务")])]),t._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",{pre:!0,attrs:{class:"language-text"}},[o("code",[t._v("cd /opt/mongodb/mongodb-3.6.3/bin\n./mongod --dbpath=/data/db\n")])])]),o("p",[o("strong",[t._v("启动 mongodb 客户端")])]),t._v(" "),o("div",{staticClass:"language- extra-class"},[o("pre",{pre:!0,attrs:{class:"language-text"}},[o("code",[t._v("cd /opt/mongodb/mongodb-3.6.3/bin\n./mongo\n")])])]),o("h2",{attrs:{id:"脚本"}},[o("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),o("p",[t._v("| "),o("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft",target:"_blank",rel:"noopener noreferrer"}},[t._v("安装脚本"),o("OutboundLink")],1),t._v(" |")])])}),[],!1,null,null,null);a.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/62.6ba50cc7.js b/assets/js/62.6ba50cc7.js new file mode 100644 index 0000000..f12ef4e --- /dev/null +++ b/assets/js/62.6ba50cc7.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[62],{447:function(a,t,s){"use strict";s.r(t);var e=s(15),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"nacos-安装配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#nacos-安装配置"}},[a._v("#")]),a._v(" Nacos 安装配置")]),a._v(" "),s("blockquote",[s("p",[s("a",{attrs:{href:"https://nacos.io/zh-cn/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Nacos"),s("OutboundLink")],1),a._v(" 是一款发现、配置和管理微服务的软件。")])]),a._v(" "),s("h2",{attrs:{id:"_1-预备环境准备"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_1-预备环境准备"}},[a._v("#")]),a._v(" 1.预备环境准备")]),a._v(" "),s("p",[a._v("Nacos 依赖 "),s("a",{attrs:{href:"https://docs.oracle.com/cd/E19182-01/820-7851/inst_cli_jdk_javahome_t/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Java"),s("OutboundLink")],1),a._v(" 环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置 "),s("a",{attrs:{href:"https://maven.apache.org/index.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("Maven"),s("OutboundLink")],1),a._v("环境,请确保是在以下版本环境中安装使用:")]),a._v(" "),s("ol",[s("li",[a._v("64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。")]),a._v(" "),s("li",[a._v("64 bit JDK 1.8+;"),s("a",{attrs:{href:"http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("下载"),s("OutboundLink")],1),a._v(" & "),s("a",{attrs:{href:"https://docs.oracle.com/cd/E19182-01/820-7851/inst_cli_jdk_javahome_t/",target:"_blank",rel:"noopener noreferrer"}},[a._v("配置"),s("OutboundLink")],1),a._v("。")]),a._v(" "),s("li",[a._v("Maven 3.2.x+;"),s("a",{attrs:{href:"https://maven.apache.org/download.cgi",target:"_blank",rel:"noopener noreferrer"}},[a._v("下载"),s("OutboundLink")],1),a._v(" & "),s("a",{attrs:{href:"https://maven.apache.org/settings.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("配置"),s("OutboundLink")],1),a._v("。")])]),a._v(" "),s("h2",{attrs:{id:"_2-下载源码或者安装包"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_2-下载源码或者安装包"}},[a._v("#")]),a._v(" 2.下载源码或者安装包")]),a._v(" "),s("p",[a._v("你可以通过源码和发行包两种方式来获取 Nacos。")]),a._v(" "),s("h3",{attrs:{id:"从-github-上下载源码方式"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#从-github-上下载源码方式"}},[a._v("#")]),a._v(" 从 Github 上下载源码方式")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("git")]),a._v(" clone https://github.com/alibaba/nacos.git\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("cd")]),a._v(" nacos/\nmvn -Prelease-nacos clean "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("install")]),a._v(" -U \n"),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("ls")]),a._v(" -al distribution/target/\n\n// change the "),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$version")]),a._v(" to your actual path\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("cd")]),a._v(" distribution/target/nacos-server-"),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$version")]),a._v("/nacos/bin\n")])])]),s("h3",{attrs:{id:"下载编译后压缩包方式"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#下载编译后压缩包方式"}},[a._v("#")]),a._v(" 下载编译后压缩包方式")]),a._v(" "),s("p",[a._v("您可以从 "),s("a",{attrs:{href:"https://github.com/alibaba/nacos/releases",target:"_blank",rel:"noopener noreferrer"}},[a._v("最新稳定版本"),s("OutboundLink")],1),a._v(" 下载 "),s("code",[a._v("nacos-server-$version.zip")]),a._v(" 包。")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("unzip")]),a._v(" nacos-server-"),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$version")]),a._v(".zip 或者 "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("tar")]),a._v(" -xvf nacos-server-"),s("span",{pre:!0,attrs:{class:"token variable"}},[a._v("$version")]),a._v(".tar.gz\n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("cd")]),a._v(" nacos/bin\n")])])]),s("h2",{attrs:{id:"_3-启动服务器"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_3-启动服务器"}},[a._v("#")]),a._v(" 3.启动服务器")]),a._v(" "),s("h3",{attrs:{id:"linux-unix-mac"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#linux-unix-mac"}},[a._v("#")]),a._v(" Linux/Unix/Mac")]),a._v(" "),s("p",[a._v("启动命令(standalone代表着单机模式运行,非集群模式):")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("sh startup.sh -m standalone\n")])])]),s("h3",{attrs:{id:"windows"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#windows"}},[a._v("#")]),a._v(" Windows")]),a._v(" "),s("p",[a._v("启动命令:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("cmd startup.cmd\n")])])]),s("p",[a._v("或者双击startup.cmd运行文件。")]),a._v(" "),s("h2",{attrs:{id:"_4-服务注册-发现和配置管理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_4-服务注册-发现和配置管理"}},[a._v("#")]),a._v(" 4.服务注册&发现和配置管理")]),a._v(" "),s("h3",{attrs:{id:"服务注册"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#服务注册"}},[a._v("#")]),a._v(" 服务注册")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'\n")])])]),s("h3",{attrs:{id:"服务发现"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#服务发现"}},[a._v("#")]),a._v(" 服务发现")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=nacos.naming.serviceName'\n")])])]),s("h3",{attrs:{id:"发布配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布配置"}},[a._v("#")]),a._v(" 发布配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v('curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"\n')])])]),s("h3",{attrs:{id:"获取配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#获取配置"}},[a._v("#")]),a._v(" 获取配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v('curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"\n')])])]),s("h2",{attrs:{id:"_5-关闭服务器"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#_5-关闭服务器"}},[a._v("#")]),a._v(" 5.关闭服务器")]),a._v(" "),s("h3",{attrs:{id:"linux-unix-mac-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#linux-unix-mac-2"}},[a._v("#")]),a._v(" Linux/Unix/Mac")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("sh shutdown.sh\n")])])]),s("h3",{attrs:{id:"windows-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#windows-2"}},[a._v("#")]),a._v(" Windows")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("cmd shutdown.cmd\n")])])]),s("p",[a._v("或者双击shutdown.cmd运行文件。")]),a._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[a._v("#")]),a._v(" 参考资料")]),a._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://nacos.io/zh-cn/docs/quick-start.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("Nacos Quick Start"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/63.9cbf9f2b.js b/assets/js/63.9cbf9f2b.js new file mode 100644 index 0000000..4dc0cd9 --- /dev/null +++ b/assets/js/63.9cbf9f2b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[63],{448:function(t,s,a){"use strict";a.r(s);var n=a(15),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"nexus-运维"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nexus-运维"}},[t._v("#")]),t._v(" Nexus 运维")]),t._v(" "),a("blockquote",[a("p",[t._v("Nexus 是一个强大的 Maven 仓库管理器,可以用来搭建 Maven 私服。")]),t._v(" "),a("p",[t._v("关键词:maven, nexus")]),t._v(" "),a("p",[t._v("部署环境:")]),t._v(" "),a("ul",[a("li",[t._v("Nexus 3.13.0")]),t._v(" "),a("li",[t._v("JDK 1.8")]),t._v(" "),a("li",[t._v("Maven 3.5.4")])])]),t._v(" "),a("h2",{attrs:{id:"一、nexus-安装"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#一、nexus-安装"}},[t._v("#")]),t._v(" 一、Nexus 安装")]),t._v(" "),a("p",[t._v("进入"),a("a",{attrs:{href:"https://www.sonatype.com/download-oss-sonatype",target:"_blank",rel:"noopener noreferrer"}},[t._v("官方下载地址"),a("OutboundLink")],1),t._v(",选择合适版本下载。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203029.png",alt:"img"}})]),t._v(" "),a("p",[t._v("本人将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。")]),t._v(" "),a("p",[t._v("这里,如果想通过命令方式直接下载(比如用脚本安装),可以在"),a("a",{attrs:{href:"https://help.sonatype.com/repomanager3/download/download-archives---repository-manager-3",target:"_blank",rel:"noopener noreferrer"}},[t._v("官方历史发布版本页面"),a("OutboundLink")],1),t._v("中找到合适版本,然后执行以下命令:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 个人习惯将 nexus 安装在 /opt/maven 目录下")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("wget")]),t._v(" -O /opt/maven/nexus-unix.tar.gz http://download.sonatype.com/nexus/3/nexus-3.13.0-01-unix.tar.gz\n\n")])])]),a("ul",[a("li",[t._v("【解压】执行 "),a("code",[t._v("tar -zxf nexus-unix.tar.gz")]),t._v(" 命令,会解压出两个目录:\n"),a("ul",[a("li",[a("code",[t._v("nexus-")]),t._v(" - 程序目录。包含了 Nexus 运行所需要的文件。是 Nexus 运行必须的。\n"),a("ul",[a("li",[a("code",[t._v("nexus-/etc")]),t._v(" - 配置目录。\n"),a("ul",[a("li",[a("code",[t._v("nexus-/etc/nexus.properties")]),t._v(" - nexus 核心配置文件(默认 etc 目录下有 "),a("code",[t._v("nexus-default.properties")]),t._v(",可以基于此修改)。")])])])])]),t._v(" "),a("li",[a("code",[t._v("sonatype-work")]),t._v(" - 仓库目录。包含了 Nexus 生成的配置文件、日志文件、仓库文件等。当我们需要备份 Nexus 的时候默认备份此目录即可。")])])]),t._v(" "),a("li",[t._v("[修改环境变量】执行 "),a("code",[t._v("vim /etc/profile")]),t._v(",在文件尾部添加以下内容:")])]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("NEXUS_HOME=/usr/program/nexus2.11.4\nexport NEXUS_HOME\n")])])]),a("p",[t._v("刷新环境变量:"),a("code",[t._v("source /etc/profile")])]),t._v(" "),a("ul",[a("li",[t._v("【检查安装是否成功】执行 "),a("code",[t._v("nexus -version")]),t._v(" 查看是否安装成功。")]),t._v(" "),a("li",[t._v("【防火墙】\n"),a("ul",[a("li",[t._v("iptabes\n"),a("ul",[a("li",[t._v("添加规则:"),a("code",[t._v("iptables -I INPUT -p tcp -m tcp --dport 8081 -j ACCEPT")])]),t._v(" "),a("li",[t._v("载入规则:"),a("code",[t._v("/etc/rc.d/init.d/iptables save")])]),t._v(" "),a("li",[t._v("重启 iptables:"),a("code",[t._v("service iptables restart")])])])]),t._v(" "),a("li",[t._v("firewalld\n"),a("ul",[a("li",[t._v("添加规则:"),a("code",[t._v("firewall-cmd --zone=public --add-port=8081/tcp --permanent")])]),t._v(" "),a("li",[t._v("载入规则:"),a("code",[t._v("firewall-cmd --reload")])])])])])])]),t._v(" "),a("h2",{attrs:{id:"二、nexus-使用"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#二、nexus-使用"}},[t._v("#")]),t._v(" 二、Nexus 使用")]),t._v(" "),a("h3",{attrs:{id:"启动-停止-nexus"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#启动-停止-nexus"}},[t._v("#")]),t._v(" 启动/停止 Nexus")]),t._v(" "),a("p",[t._v("进入 "),a("code",[t._v("nexus-3.13.0-01/bin")]),t._v(" 目录,有一个可执行脚本 nexus。")]),t._v(" "),a("p",[t._v("执行 "),a("code",[t._v("./nexus")]),t._v(",可以查看允许执行的参数,如下所示,含义可谓一目了然:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("$ ./nexus\nUsage: ./nexus "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("start"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("stop"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("run"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("run-redirect"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("status"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("restart"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v("force-reload"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("ul",[a("li",[t._v("启动 nexus - "),a("code",[t._v("./nexus start")])]),t._v(" "),a("li",[t._v("停止 nexus - "),a("code",[t._v("./nexus stop")])]),t._v(" "),a("li",[t._v("重启 nexus - "),a("code",[t._v("./nexus restart")])])]),t._v(" "),a("p",[t._v("Nexus 的默认启动端口为 "),a("code",[t._v("8081")]),t._v(",启动成功后,在浏览器中访问 "),a("code",[t._v("http://:8081")]),t._v(",欢迎页面如下图所示:")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203131.png",alt:"img"}})]),t._v(" "),a("p",[t._v("点击右上角 Sign in 登录,默认用户名/密码为:"),a("code",[t._v("admin/admin123")]),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"配置-maven-仓库"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-maven-仓库"}},[t._v("#")]),t._v(" 配置 maven 仓库")]),t._v(" "),a("p",[t._v("Nexus 中的仓库有以下类型:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("hosted")]),t._v(" - 宿主仓库。主要用于部署无法从公共仓库获取的构件(如 oracle 的 JDBC 驱动)以及自己或第三方的项目构件;")]),t._v(" "),a("li",[a("code",[t._v("proxy")]),t._v(" - 代理仓库。代理公共的远程仓库;")]),t._v(" "),a("li",[a("code",[t._v("virtual")]),t._v(" - 虚拟仓库。用于适配 Maven 1;")]),t._v(" "),a("li",[a("code",[t._v("group")]),t._v(" - 仓库组。Nexus 通过仓库组的概念统一管理多个仓库,这样我们在项目中直接请求仓库组即可请求到仓库组管理的多个仓库。")])]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/maven/nexus.png",alt:"img"}})]),t._v(" "),a("p",[t._v("建议配置如下:")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("hosted 仓库")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("maven-releases")]),t._v(" - 存储私有仓库的发行版 jar 包")]),t._v(" "),a("li",[a("strong",[t._v("maven-snapshots")]),t._v(" - 存储私有仓库的快照版(调试版本) jar 包")])])]),t._v(" "),a("li",[a("strong",[t._v("proxy 仓库")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("maven-central-maven")]),t._v(" - 中央库(如果没有配置 mirror,默认就从这里下载 jar 包),从 https://repo1.maven.org/maven2/ 获取资源")]),t._v(" "),a("li",[a("strong",[t._v("maven-aliyun")]),t._v(" - 国内 maven 仓库,提高访问速度。")])])]),t._v(" "),a("li",[a("strong",[t._v("group 仓库")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("maven-public")]),t._v(" - 私有仓库的公共空间,把上面三个仓库组合在一起对外提供服务,在本地 maven 基础配置 settings.xml 中使用。")])])])]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203156.png",alt:"img"}})]),t._v(" "),a("blockquote",[a("p",[t._v("其中:")]),t._v(" "),a("p",[a("strong",[t._v("maven-central")]),t._v("、"),a("strong",[t._v("maven-public")]),t._v("、"),a("strong",[t._v("maven-release")]),t._v("、"),a("strong",[t._v("maven-snapshot")]),t._v(" 仓库是默认配置好的 maven 仓库。maven-central 配置的是 "),a("code",[t._v("https://repo1.maven.org/maven2/")]),t._v(" 的代理仓库,即 maven 中央仓库地址。")])]),t._v(" "),a("p",[t._v("参考配置如下:")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200403165258.png",alt:"img"}})]),t._v(" "),a("p",[t._v("推荐配置的代理仓库:")]),t._v(" "),a("ul",[a("li",[t._v("OSS SNAPSHOT 仓库:"),a("code",[t._v("http://oss.jfrog.org/artifactory/oss-snapshot-local/")])]),t._v(" "),a("li",[t._v("aliyun 仓库(受限于国内网络,可以通过它来加速):"),a("code",[t._v("http://maven.aliyun.com/nexus/content/groups/public/")])])]),t._v(" "),a("h3",{attrs:{id:"配置-yum-仓库"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-yum-仓库"}},[t._v("#")]),t._v(" 配置 yum 仓库")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200403201609.png",alt:"img"}})]),t._v(" "),a("p",[t._v("推荐配置的 yum 代理仓库:")]),t._v(" "),a("ul",[a("li",[t._v("aliyun yum 仓库:"),a("code",[t._v("http://mirrors.aliyun.com/centos")])])]),t._v(" "),a("p",[t._v("配置本地 yum:")]),t._v(" "),a("p",[t._v("(1)新增 nexus.repo 文件,内容如下:")]),t._v(" "),a("div",{staticClass:"language-ini extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ini"}},[a("code",[a("span",{pre:!0,attrs:{class:"token selector"}},[t._v("[base]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("name")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("Nexus")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("baseurl")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v(" http://:/repository/yum-aliyun/$releasever/os/$basearch/")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("enabled")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("gpgcheck")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("0")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("priority")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("1")]),t._v("\n")])])]),a("p",[t._v("(2)更新 yum 缓存,执行以下命令:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[t._v("yum clean all\nyum makecache\n")])])]),a("h3",{attrs:{id:"定时任务"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#定时任务"}},[t._v("#")]),t._v(" 定时任务")]),t._v(" "),a("p",[t._v("随着 jar 包越来越多,尤其是 SNAPSHOT 包由于不限制重复上传,尤其容易导致磁盘空间膨胀。所以,需要定期进行清理或修复。")]),t._v(" "),a("p",[t._v("Nexus 内置了多个定时任务,可以执行清理。")]),t._v(" "),a("p",[t._v("【示例】定期清理 SNAPSHOST")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20200403173030.png",alt:"img"}})]),t._v(" "),a("h2",{attrs:{id:"三、开机自启动"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#三、开机自启动"}},[t._v("#")]),t._v(" 三、开机自启动")]),t._v(" "),a("p",[t._v("作为常用服务,有必要将 Nexus 设为 "),a("code",[t._v("systemd")]),t._v(" 服务,以便在断电恢复后自动重启。")]),t._v(" "),a("p",[t._v("配置方法如下:")]),t._v(" "),a("p",[t._v("在 "),a("code",[t._v("/lib/systemd/system")]),t._v(" 目录下创建 "),a("code",[t._v("nexus.service")]),t._v(" 文件,内容如下:")]),t._v(" "),a("div",{staticClass:"language-ini extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ini"}},[a("code",[a("span",{pre:!0,attrs:{class:"token selector"}},[t._v("[Unit]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Description")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("nexus")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("After")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("network.target")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token selector"}},[t._v("[Service]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Type")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("forking")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("LimitNOFILE")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("65536 #警告处理")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Environment")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("RUN_AS_USER=root")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("ExecStart")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("/opt/maven/nexus-3.13.0-01/bin/nexus start")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("ExecReload")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("/opt/maven/nexus-3.13.0-01/bin/nexus restart")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("ExecStop")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("/opt/maven/nexus-3.13.0-01/bin/nexus stop")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("Restart")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("on-failure")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("PrivateTmp")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("true")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token selector"}},[t._v("[Install]")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("WantedBy")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("=")]),t._v("multi-user.target")]),t._v("\n")])])]),a("p",[t._v("保存后,可以使用以下命令应用 nexus 服务:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("systemctl enable nexus")]),t._v(" - 启动 nexus 开机启动")]),t._v(" "),a("li",[a("code",[t._v("systemctl disable nexus")]),t._v(" - 关闭 nexus 开机启动")]),t._v(" "),a("li",[a("code",[t._v("systemctl start nexus")]),t._v(" - 启动 nexus 服务")]),t._v(" "),a("li",[a("code",[t._v("systemctl stop nexus")]),t._v(" - 停止 nexus 服务")]),t._v(" "),a("li",[a("code",[t._v("systemctl restart nexus")]),t._v(" - 重启 nexus 服务")])]),t._v(" "),a("blockquote",[a("p",[t._v("执行 "),a("code",[t._v("systemctl enable nexus")]),t._v(" 后,再执行 reboot 重启,重连后,可以检测是否成功开机自动重启。")])]),t._v(" "),a("h2",{attrs:{id:"四、nexus-和-maven"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#四、nexus-和-maven"}},[t._v("#")]),t._v(" 四、Nexus 和 Maven")]),t._v(" "),a("p",[t._v("Nexus 是 maven 私服。现在,Nexus 服务器已经部署好了,如何配合 maven 使用呢?")]),t._v(" "),a("h3",{attrs:{id:"配置-settings-xml"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-settings-xml"}},[t._v("#")]),t._v(" 配置 settings.xml")]),t._v(" "),a("p",[t._v("如果要使用 Nexus,还必须在 "),a("code",[t._v("settings.xml")]),t._v(" 和 "),a("code",[t._v("pom.xml")]),t._v(" 中配置认证信息。")]),t._v(" "),a("p",[t._v("一份完整的 "),a("code",[t._v("settings.xml")]),t._v(":")]),t._v(" "),a("div",{staticClass:"language-xml extra-class"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token prolog"}},[t._v('')]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("settings")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[t._v("xmlns")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("http://maven.apache.org/SETTINGS/1.0.0"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("xmlns:")]),t._v("xsi")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("http://www.w3.org/2001/XMLSchema-instance"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token attr-name"}},[a("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("xsi:")]),t._v("schemaLocation")]),a("span",{pre:!0,attrs:{class:"token attr-value"}},[a("span",{pre:!0,attrs:{class:"token punctuation attr-equals"}},[t._v("=")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')]),t._v("http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v('"')])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("pluginGroups")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("pluginGroup")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("org.sonatype.plugins"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--设置本地 maven 仓库--\x3e")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("localRepository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("D:\\Tools\\maven\\.m2"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--Maven 私服账号信息--\x3e")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("servers")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("releases"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("username")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("admin"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("password")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("admin123"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("server")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("username")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("admin"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("password")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("admin123"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--Maven 镜像地址--\x3e")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("mirrors")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("mirror")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("public"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("mirrorOf")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("*"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("\x3c!--Nexus 服务器地址--\x3e")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("http://10.255.255.224:8081/repository/maven-public/"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("profiles")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("profile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("zp"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("repositories")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("repository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("central"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("http://central"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("releases")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("enabled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("snapshots")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("enabled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("pluginRepositories")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("pluginRepository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("central"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("http://central"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("releases")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("enabled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("snapshots")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("enabled")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("true"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("updatePolicy")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("always"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("activeProfiles")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("activeProfile")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("zp"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),a("h3",{attrs:{id:"配置-pom-xml"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-pom-xml"}},[t._v("#")]),t._v(" 配置 pom.xml")]),t._v(" "),a("p",[t._v("在 "),a("code",[t._v("pom.xml")]),t._v(" 中添加如下配置,这样就可以执行 "),a("code",[t._v("mvn deploy")]),t._v(",将本地构建的 jar、war 等包发布到私服上。")]),t._v(" "),a("div",{staticClass:"language-xml extra-class"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[t._v(" "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("distributionManagement")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("repository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("releases"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("name")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Releases"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("http://10.255.255.224:8081/repository/maven-releases"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("snapshotRepository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("name")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("Snapshot"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),t._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("http://10.255.255.224:8081/repository/maven-snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),a("blockquote",[a("p",[t._v("🔔 注意:")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("")]),t._v(" 和 "),a("code",[t._v("")]),t._v(" 的 id 必须和 "),a("code",[t._v("settings.xml")]),t._v(" 配置文件中的 "),a("code",[t._v("")]),t._v(" 标签中的 id 匹配。")]),t._v(" "),a("li",[a("code",[t._v("")]),t._v(" 标签的地址需要和 maven 私服的地址匹配。")])])]),t._v(" "),a("h3",{attrs:{id:"执行-maven-构建"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#执行-maven-构建"}},[t._v("#")]),t._v(" 执行 maven 构建")]),t._v(" "),a("p",[t._v("如果要使用 "),a("code",[t._v("settings.xml")]),t._v(" 中的私服配置,必须通过指定 "),a("code",[t._v("-P zp")]),t._v(" 来激活 profile。")]),t._v(" "),a("p",[t._v("示例:")]),t._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 编译并打包 maven 项目")]),t._v("\n$ mvn clean package -Dmaven.skip.test"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("true -P zp\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 编译并上传 maven 交付件(jar 包)")]),t._v("\n$ mvn clean deploy -Dmaven.skip.test"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("true -P zp\n")])])]),a("blockquote",[a("p",[t._v("至此,已经可以正常向 Nexus 上传、下载 jar 包。")])]),t._v(" "),a("h2",{attrs:{id:"五、备份和迁移"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#五、备份和迁移"}},[t._v("#")]),t._v(" 五、备份和迁移")]),t._v(" "),a("p",[t._v("Nexus 三个重要目录:")]),t._v(" "),a("table",[a("thead",[a("tr",[a("th",{staticStyle:{"text-align":"left"}},[t._v("名称")]),t._v(" "),a("th",{staticStyle:{"text-align":"left"}},[t._v("目录名")]),t._v(" "),a("th",{staticStyle:{"text-align":"left"}},[t._v("重要配置文件")])])]),t._v(" "),a("tbody",[a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("nexus 主目录")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("nexus-2.6.4-02")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("conf/nexus.properties 里面有 sonatype-work 的地址")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("sonatype-work 目录")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("sonatype-work")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("nexus/conf/nexus.xml 里面有 storage 的地址")])]),t._v(" "),a("tr",[a("td",{staticStyle:{"text-align":"left"}},[t._v("storage 目录")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("storage")]),t._v(" "),a("td",{staticStyle:{"text-align":"left"}},[t._v("里面主要是各种程序的 jar 包等")])])])]),t._v(" "),a("h3",{attrs:{id:"备份"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#备份"}},[t._v("#")]),t._v(" 备份")]),t._v(" "),a("p",[t._v("Nexus 的数据都存储在 sonatype-work 目录,备份 Nexus 数据只需要将其打包即可。")]),t._v(" "),a("h3",{attrs:{id:"迁移"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#迁移"}},[t._v("#")]),t._v(" 迁移")]),t._v(" "),a("p",[t._v("将原 Nexus 服务器中的 sonatype-work 目录迁移到新 Nexus 服务器的 sonatype-work 目录下。")]),t._v(" "),a("h2",{attrs:{id:"六、faq"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#六、faq"}},[t._v("#")]),t._v(" 六、FAQ")]),t._v(" "),a("h3",{attrs:{id:"配置-install4j-java-home"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置-install4j-java-home"}},[t._v("#")]),t._v(" 配置 INSTALL4J_JAVA_HOME")]),t._v(" "),a("p",[t._v("我在工作中遇到 nexus systemctl 服务无法自启动的问题,通过查看状态,发现以下报错:")]),t._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[t._v("Please define INSTALL4J_JAVA_HOME to point to a suitable JVM\n")])])]),a("p",[t._v("通过排查,找到原因:即使环境上已安装 JDK,且配置了 JAVA_HOME,但 nexus 仍然无法正确找到 JDK,需要在 "),a("code",[t._v("/bin/nexus")]),t._v(" 中指定 "),a("code",[t._v("INSTALL4J_JAVA_HOME_OVERRIDE=")])]),t._v(" "),a("h2",{attrs:{id:"参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://blog.csdn.net/clj198606061111/article/details/52200928",target:"_blank",rel:"noopener noreferrer"}},[t._v("maven 私库 nexus3 安装及使用"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"https://www.cnblogs.com/jtlgb/p/7473837.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Nexus 安装 使用说明"),a("OutboundLink")],1)]),t._v(" "),a("li",[a("a",{attrs:{href:"http://www.eryajf.net/2002.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("企业级开源仓库 nexus3 实战应用–使用 nexus3 配置 yum 私有仓库"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/64.0be148a4.js b/assets/js/64.0be148a4.js new file mode 100644 index 0000000..50b4a84 --- /dev/null +++ b/assets/js/64.0be148a4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[64],{449:function(t,a,e){"use strict";e.r(a);var s=e(15),r=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"nodejs-安装"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#nodejs-安装"}},[t._v("#")]),t._v(" Nodejs 安装")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"#%E5%AE%89%E8%A3%85%E6%96%B9%E6%B3%95"}},[t._v("安装方法")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"#%E5%85%88%E5%AE%89%E8%A3%85-nvm"}},[t._v("先安装 nvm")])]),t._v(" "),e("li",[e("a",{attrs:{href:"#%E5%AE%89%E8%A3%85-nodejs"}},[t._v("安装 Nodejs")])])])]),t._v(" "),e("li",[e("a",{attrs:{href:"#%E8%84%9A%E6%9C%AC"}},[t._v("脚本")])])]),t._v(" "),e("h2",{attrs:{id:"安装方法"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#安装方法"}},[t._v("#")]),t._v(" 安装方法")]),t._v(" "),e("h3",{attrs:{id:"先安装-nvm"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#先安装-nvm"}},[t._v("#")]),t._v(" 先安装 nvm")]),t._v(" "),e("p",[t._v("推荐安装 nvm(Node Version Manager) ,来管理 node.js 版本。")]),t._v(" "),e("p",[t._v("安装步骤如下:")]),t._v(" "),e("p",[t._v("(1)执行安装脚本")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("rm -rf ~/.nvm\ncurl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash\n. ~/.nvm/nvm.sh\n")])])]),e("p",[t._v("(2)检验是否安装成功")]),t._v(" "),e("p",[t._v("执行 "),e("code",[t._v("nvm --version")]),t._v(" 命令。")]),t._v(" "),e("p",[t._v("注意:如果出现 "),e("code",[t._v("nvm: command not found")]),t._v(" ,关闭终端,然后再打开终端试试。")]),t._v(" "),e("h3",{attrs:{id:"安装-nodejs"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#安装-nodejs"}},[t._v("#")]),t._v(" 安装 Nodejs")]),t._v(" "),e("p",[t._v("安装步骤如下:")]),t._v(" "),e("p",[t._v("(1)使用 nvm 安装 nodejs 指定版本")]),t._v(" "),e("p",[t._v("执行以下命令:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("nvm install 8.9.4\nnvm use 8.9.4\n")])])]),e("p",[t._v("(2)检验是否安装成功")]),t._v(" "),e("p",[t._v("执行 "),e("code",[t._v("node --version")]),t._v(" 命令。")]),t._v(" "),e("p",[t._v("注意:如果出现 "),e("code",[t._v("node: command not found")]),t._v(" ,关闭终端,然后再打开终端试试。")]),t._v(" "),e("h2",{attrs:{id:"脚本"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),e("p",[t._v("| "),e("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft",target:"_blank",rel:"noopener noreferrer"}},[t._v("安装脚本"),e("OutboundLink")],1),t._v(" |")]),t._v(" "),e("h2",{attrs:{id:"更多内容"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#更多内容"}},[t._v("#")]),t._v(" 更多内容")]),t._v(" "),e("ul",[e("li",[e("strong",[t._v("引申")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[t._v("操作系统、运维部署总结系列"),e("OutboundLink")],1)])])])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/65.c520257e.js b/assets/js/65.c520257e.js new file mode 100644 index 0000000..c9eba2f --- /dev/null +++ b/assets/js/65.c520257e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{450:function(t,a,s){"use strict";s.r(a);var n=s(15),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"rocketmq-安装部署"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#rocketmq-安装部署"}},[t._v("#")]),t._v(" RocketMQ 安装部署")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"#%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82"}},[t._v("环境要求")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E4%B8%8B%E8%BD%BD%E8%A7%A3%E5%8E%8B"}},[t._v("下载解压")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E5%90%AF%E5%8A%A8-name-server"}},[t._v("启动 Name Server")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E5%90%AF%E5%8A%A8-broker"}},[t._v("启动 Broker")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E6%94%B6%E5%8F%91%E6%B6%88%E6%81%AF"}},[t._v("收发消息")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E5%85%B3%E9%97%AD%E6%9C%8D%E5%8A%A1%E5%99%A8"}},[t._v("关闭服务器")])]),t._v(" "),s("li",[s("a",{attrs:{href:"#faq"}},[t._v("FAQ")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"#connect-to-172170110909-failed"}},[t._v("connect to <172.17.0.1:10909> failed")])])])]),t._v(" "),s("li",[s("a",{attrs:{href:"#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[t._v("参考资料")])])]),t._v(" "),s("h2",{attrs:{id:"环境要求"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#环境要求"}},[t._v("#")]),t._v(" 环境要求")]),t._v(" "),s("ul",[s("li",[t._v("推荐 64 位操作系统:Linux/Unix/Mac")]),t._v(" "),s("li",[t._v("64bit JDK 1.8+")]),t._v(" "),s("li",[t._v("Maven 3.2.x")]),t._v(" "),s("li",[t._v("Git")])]),t._v(" "),s("h2",{attrs:{id:"下载解压"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#下载解压"}},[t._v("#")]),t._v(" 下载解压")]),t._v(" "),s("p",[t._v("进入官方下载地址:https://rocketmq.apache.org/dowloading/releases/,选择合适版本")]),t._v(" "),s("p",[t._v("建议选择 binary 版本。")]),t._v(" "),s("p",[t._v("解压到本地:")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("unzip")]),t._v(" rocketmq-all-4.2.0-source-release.zip\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" rocketmq-all-4.2.0/\n")])])]),s("h2",{attrs:{id:"启动-name-server"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#启动-name-server"}},[t._v("#")]),t._v(" 启动 Name Server")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nohup")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/mqnamesrv "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tail")]),t._v(" -f ~/logs/rocketmqlogs/namesrv.log\nThe Name Server boot success"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n")])])]),s("h2",{attrs:{id:"启动-broker"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#启动-broker"}},[t._v("#")]),t._v(" 启动 Broker")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nohup")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/mqbroker -n localhost:9876 -c conf/broker.conf "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("tail")]),t._v(" -f ~/logs/rocketmqlogs/broker.log\nThe broker"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("%s, "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("172.30")]),t._v(".30.233:10911"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" boot success"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n")])])]),s("h2",{attrs:{id:"收发消息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#收发消息"}},[t._v("#")]),t._v(" 收发消息")]),t._v(" "),s("p",[t._v("执行收发消息操作之前,不许告诉客户端命名服务器的位置。在 RocketMQ 中有多种方法来实现这个目的。这里,我们使用最简单的方法——设置环境变量 "),s("code",[t._v("NAMESRV_ADDR")]),t._v(" :")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("export")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("NAMESRV_ADDR")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("localhost:9876\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/tools.sh org.apache.rocketmq.example.quickstart.Producer\nSendResult "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("sendStatus"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("SEND_OK, "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("msgId")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer\nConsumeMessageThread_%d Receive New Messages: "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("MessageExt"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\n")])])]),s("h2",{attrs:{id:"关闭服务器"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#关闭服务器"}},[t._v("#")]),t._v(" 关闭服务器")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/mqshutdown broker\nThe mqbroker"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("36695")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" is running"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\nSend "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("shutdown")]),t._v(" request to mqbroker"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("36695")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" OK\n\n"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/mqshutdown namesrv\nThe mqnamesrv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("36664")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" is running"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("..")]),t._v(".\nSend "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("shutdown")]),t._v(" request to mqnamesrv"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("36664")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" OK\n")])])]),s("h2",{attrs:{id:"faq"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#faq"}},[t._v("#")]),t._v(" FAQ")]),t._v(" "),s("h3",{attrs:{id:"connect-to-172-17-0-1-10909-failed"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#connect-to-172-17-0-1-10909-failed"}},[t._v("#")]),t._v(" connect to <172.17.0.1:10909> failed")]),t._v(" "),s("p",[t._v("启动后,生产者客户端连接 RocketMQ 时报错:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("remoting"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("exception"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("RemotingConnectException")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" connect "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("to")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("172.17")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".0")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v(".1")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10909")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" failed\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("remoting"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("netty"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("NettyRemotingClient")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("invokeSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NettyRemotingClient")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("357")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendMessageSync")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("343")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendMessage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("327")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendMessage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MQClientAPIImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("290")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("producer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendKernelImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("688")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("producer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendSelectImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("901")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("producer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("878")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("impl"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("producer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultMQProducerImpl")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("873")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("org"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("apache"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("rocketmq"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("client"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("producer"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("DefaultMQProducer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("send")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DefaultMQProducer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("369")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("com"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("emrubik"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mdm"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("MdmInit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sendMessage")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MdmInit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("62")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n at "),s("span",{pre:!0,attrs:{class:"token class-name"}},[s("span",{pre:!0,attrs:{class:"token namespace"}},[t._v("com"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("emrubik"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("uc"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("mdm"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("sync"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("utils"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")])]),t._v("MdmInit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MdmInit")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("java"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2149")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n")])])]),s("p",[t._v("原因:RocketMQ 部署在虚拟机上,内网 ip 为 10.10.30.63,该虚拟机一个 docker0 网卡,ip 为 172.17.0.1。RocketMQ broker 启动时默认使用了 docker0 网卡,生产者客户端无法连接 172.17.0.1,造成以上问题。")]),t._v(" "),s("p",[t._v("解决方案")]),t._v(" "),s("p",[t._v("(1)干掉 docker0 网卡或修改网卡名称")]),t._v(" "),s("p",[t._v("(2)停掉 broker,修改 broker 配置文件,重启 broker。")]),t._v(" "),s("p",[t._v("修改 conf/broker.conf,增加两行来指定启动 broker 的 IP:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("namesrvAddr = 10.10.30.63:9876\nbrokerIP1 = 10.10.30.63\n")])])]),s("p",[t._v("启动时需要指定配置文件")]),t._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[t._v("nohup")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v(" bin/mqbroker -n localhost:9876 -c conf/broker.conf "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&")]),t._v("\n")])])]),s("h2",{attrs:{id:"更多内容"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#更多内容"}},[t._v("#")]),t._v(" 更多内容")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("引申")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[t._v("操作系统、运维部署总结系列"),s("OutboundLink")],1)])])]),t._v(" "),s("li",[s("strong",[t._v("引用")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"http://rocketmq.apache.org/docs/quick-start/",target:"_blank",rel:"noopener noreferrer"}},[t._v("RocketMQ 官方文档"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"http://laciagin.me/2017/12/07/RocketMQ%E6%90%AD%E5%BB%BA%E5%8F%8A%E5%88%A8%E5%9D%91/",target:"_blank",rel:"noopener noreferrer"}},[t._v("RocketMQ 搭建及刨坑"),s("OutboundLink")],1)])])])])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/66.f2335390.js b/assets/js/66.f2335390.js new file mode 100644 index 0000000..a05db8f --- /dev/null +++ b/assets/js/66.f2335390.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[66],{451:function(s,a,t){"use strict";t.r(a);var e=t(15),n=Object(e.a)({},(function(){var s=this,a=s.$createElement,t=s._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[t("h1",{attrs:{id:"svn-运维"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#svn-运维"}},[s._v("#")]),s._v(" Svn 运维")]),s._v(" "),t("blockquote",[t("p",[s._v("Svn 是 Subversion 的简称,是一个开放源代码的版本控制系统,它采用了分支管理系统。")]),s._v(" "),t("p",[s._v("本文目的在于记录 svn 的安装、配置、使用。")])]),s._v(" "),t("h2",{attrs:{id:"安装"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[s._v("#")]),s._v(" 安装")]),s._v(" "),t("h3",{attrs:{id:"安装-svn"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#安装-svn"}},[s._v("#")]),s._v(" 安装 svn")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ yum "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" -y subversion\n")])])]),t("h3",{attrs:{id:"创建-svn-仓库"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#创建-svn-仓库"}},[s._v("#")]),s._v(" 创建 svn 仓库")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("mkdir")]),s._v(" -p /share/svn\n$ svnadmin create /share/svn\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("ls")]),s._v(" /share/svn\nconf db "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("format")]),s._v(" hooks locks README.txt\n")])])]),t("p",[s._v("在 conf 目录下有三个重要的配置文件")]),s._v(" "),t("ul",[t("li",[t("code",[s._v("authz")]),s._v(" - 是权限控制文件")]),s._v(" "),t("li",[t("code",[s._v("passwd")]),s._v(" - 是帐号密码文件")]),s._v(" "),t("li",[t("code",[s._v("svnserve.conf")]),s._v(" - 是 SVN 服务配置文件")])]),s._v(" "),t("h2",{attrs:{id:"配置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#配置"}},[s._v("#")]),s._v(" 配置")]),s._v(" "),t("h3",{attrs:{id:"配置-svnserve-conf"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#配置-svnserve-conf"}},[s._v("#")]),s._v(" 配置 svnserve.conf")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v(" /share/svn/conf/svnserve.conf\n")])])]),t("p",[s._v("打开下面的 5 个注释")]),s._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("anon-access")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" read #匿名用户可读")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("auth-access")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" write #授权用户可写")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("password-db")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" passwd #使用哪个文件作为账号文件")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("authz-db")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" authz #使用哪个文件作为权限文件")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("realm")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" /share/svn # 认证空间名,版本库所在目录")]),s._v("\n")])])]),t("h3",{attrs:{id:"配置-passwd"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#配置-passwd"}},[s._v("#")]),s._v(" 配置 passwd")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v(" /share/svn/conf/passwd\n")])])]),t("p",[s._v("添加新用户的用户名/密码如下:")]),s._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[s._v("[users]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" 123456")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user2")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" 123456")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" 123456")]),s._v("\n")])])]),t("h3",{attrs:{id:"配置-authz"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#配置-authz"}},[s._v("#")]),s._v(" 配置 authz")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vim")]),s._v(" /share/svn/conf/authz\n")])])]),t("p",[s._v("指定用户的访问权限("),t("code",[s._v("r")]),s._v(" 为读权限;"),t("code",[s._v("w")]),s._v(" 为写权限):")]),s._v(" "),t("div",{staticClass:"language-ini extra-class"},[t("pre",{pre:!0,attrs:{class:"language-ini"}},[t("code",[t("span",{pre:!0,attrs:{class:"token selector"}},[s._v("[/]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user1")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" rw")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user2")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" rw")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("user3")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" rw")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token constant"}},[s._v("*")]),t("span",{pre:!0,attrs:{class:"token attr-value"}},[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")])]),s._v("\n")])])]),t("h2",{attrs:{id:"服务器管理"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#服务器管理"}},[s._v("#")]),s._v(" 服务器管理")]),s._v(" "),t("h3",{attrs:{id:"启动关闭-svn"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#启动关闭-svn"}},[s._v("#")]),s._v(" 启动关闭 svn")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ svnserve -d -r /share/svn "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 启动 svn")]),s._v("\n$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("killall")]),s._v(" svnserve "),t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 关闭 svn")]),s._v("\n")])])]),t("h3",{attrs:{id:"开机自启动-svn-方法"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#开机自启动-svn-方法"}},[s._v("#")]),s._v(" 开机自启动 svn 方法")]),s._v(" "),t("p",[s._v("安装好 svn 服务后,默认是没有随系统启动自动启动的,而一般我们有要求 svn 服务稳定持续的提供服务。所以,有必要配置开机自启动 svn 服务。")]),s._v(" "),t("h4",{attrs:{id:"centos7-以前"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#centos7-以前"}},[s._v("#")]),s._v(" Centos7 以前")]),s._v(" "),t("p",[s._v("编辑 "),t("code",[s._v("/etc/rc.d/rc.local")]),s._v(" 文件:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vi")]),s._v(" /etc/rc.d/rc.local\n")])])]),t("p",[s._v("输入以下内容:")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 开机自动启动 svn,默认端口是 3690")]),s._v("\n$ /usr/bin/svnserve -d -r /share/svn --listen-port "),t("span",{pre:!0,attrs:{class:"token number"}},[s._v("3690")]),s._v("\n")])])]),t("p",[s._v("注意:")]),s._v(" "),t("p",[s._v("我们在用终端操作的时候,可以直接使用以下命令启动 SVN:"),t("code",[s._v("svnserve -d -r /share/svn")]),s._v(",但是在 "),t("code",[s._v("/etc/rc.d/rc.local")]),s._v(" 文件中必须写上完整的路径!")]),s._v(" "),t("p",[s._v("如果不知道 svnserve 命令安装在哪儿,可以使用 whereis svnserve 查找。")]),s._v(" "),t("h4",{attrs:{id:"centos7"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#centos7"}},[s._v("#")]),s._v(" Centos7")]),s._v(" "),t("p",[s._v("CentOS 7 中的 "),t("code",[s._v("/etc/rc.d/rc.local")]),s._v(" 是没有执行权限的,系统建议创建 "),t("code",[s._v("systemd service")]),s._v(" 启动服务。")]),s._v(" "),t("p",[s._v("找到 svn 的 service 配置文件 "),t("code",[s._v("/etc/sysconfig/svnserve")]),s._v(" 编辑配置文件")]),s._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[s._v("$ "),t("span",{pre:!0,attrs:{class:"token function"}},[s._v("vi")]),s._v(" /etc/sysconfig/svnserve\n")])])]),t("p",[s._v("将 "),t("code",[s._v('OPTIONS="-r /var/svn"')]),s._v(" 改为 svn 版本库存放的目录,:wq 保存退出。")]),s._v(" "),t("p",[s._v("执行 "),t("code",[s._v("systemctl enable svnserve.service")])]),s._v(" "),t("p",[s._v("重启服务器后,执行 "),t("code",[s._v("ps -ef | grep svn")]),s._v(" 应该可以看到 svn 服务的进程已经启动。")]),s._v(" "),t("ul",[t("li",[s._v("启动一个服务 - systemctl start svnserve.service")]),s._v(" "),t("li",[s._v("关闭一个服务 - systemctl stop svnserve.service")]),s._v(" "),t("li",[s._v("重启一个服务 - systemctl restart svnserve.service")]),s._v(" "),t("li",[s._v("显示一个服务的状态 - systemctl status svnserve.service")]),s._v(" "),t("li",[s._v("在开机时启用一个服务 - systemctl enable svnserve.service")]),s._v(" "),t("li",[s._v("在开机时禁用一个服务 - systemctl disable svnserve.service")])]),s._v(" "),t("h2",{attrs:{id:"客户端使用"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#客户端使用"}},[s._v("#")]),s._v(" 客户端使用")]),s._v(" "),t("p",[s._v("进入 "),t("a",{attrs:{href:"https://tortoisesvn.net/downloads.html",target:"_blank",rel:"noopener noreferrer"}},[s._v("svn 官方下载地址"),t("OutboundLink")],1),s._v(",选择合适的版本,下载并安装。")]),s._v(" "),t("p",[s._v("新建一个目录,然后打开鼠标右键菜单,选择 "),t("strong",[s._v("SVN Checkout")]),s._v("。")]),s._v(" "),t("p",[s._v("在新的窗口,输入地址 "),t("code",[s._v("svn://<你的 IP>")]),s._v(" 即可,不出意外输入用户名和密码就能连接成功了(这里的用户、密码必须在 passwd 配置文件的清单中)。默认端口 3690,如果你修改了端口,那么要记得加上端口号。如下图所示:")]),s._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/20190129175443.png",alt:"img"}})]),s._v(" "),t("h2",{attrs:{id:"参考资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[s._v("#")]),s._v(" 参考资料")]),s._v(" "),t("ul",[t("li",[s._v("https://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html")]),s._v(" "),t("li",[s._v("https://blog.csdn.net/testcs_dn/article/details/45395645")]),s._v(" "),t("li",[s._v("https://www.cnblogs.com/moxiaoan/p/5683743.html")]),s._v(" "),t("li",[s._v("https://blog.csdn.net/realghost/article/details/52396648")])])])}),[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/67.e5737218.js b/assets/js/67.e5737218.js new file mode 100644 index 0000000..c604ad0 --- /dev/null +++ b/assets/js/67.e5737218.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[67],{452:function(t,a,r){"use strict";r.r(a);var e=r(15),s=Object(e.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"tomcat-安装"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#tomcat-安装"}},[t._v("#")]),t._v(" Tomcat 安装")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"#%E5%AE%89%E8%A3%85"}},[t._v("安装")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#%E5%90%AF%E5%8A%A8"}},[t._v("启动")])]),t._v(" "),r("li",[r("a",{attrs:{href:"#%E8%84%9A%E6%9C%AC"}},[t._v("脚本")])])]),t._v(" "),r("h2",{attrs:{id:"安装"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#安装"}},[t._v("#")]),t._v(" 安装")]),t._v(" "),r("p",[t._v("安装步骤如下:")]),t._v(" "),r("p",[t._v("(1)下载并解压到本地")]),t._v(" "),r("p",[t._v("进入官网下载地址:https://tomcat.apache.org/download-80.cgi ,选择合适的版本下载。")]),t._v(" "),r("p",[t._v("我选择的是最新稳定版本 8.5.28:http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.28/bin/apache-tomcat-8.5.28.tar.gz")]),t._v(" "),r("p",[t._v("我个人喜欢存放在:"),r("code",[t._v("/opt/tomcat")])]),t._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[t._v("wget -O /opt/tomcat/apache-tomcat-8.5.28.tar.gz http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.28/bin/apache-tomcat-8.5.28.tar.gz\ncd /opt/tomcat\ntar zxvf apache-tomcat-8.5.28.tar.gz\n")])])]),r("h2",{attrs:{id:"启动"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#启动"}},[t._v("#")]),t._v(" 启动")]),t._v(" "),r("p",[r("strong",[t._v("启动 tomcat 服务")])]),t._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[t._v("cd /opt/tomcat/apache-tomcat-8.5.28/bin\n./catalina.sh start\n")])])]),r("p",[r("strong",[t._v("停止 tomcat 服务")])]),t._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[t._v("cd /opt/tomcat/apache-tomcat-8.5.28/bin\n./catalina.sh stop\n")])])]),r("h2",{attrs:{id:"脚本"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),r("p",[t._v("| "),r("a",{attrs:{href:"https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft",target:"_blank",rel:"noopener noreferrer"}},[t._v("安装脚本"),r("OutboundLink")],1),t._v(" |")]),t._v(" "),r("h2",{attrs:{id:"更多内容"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#更多内容"}},[t._v("#")]),t._v(" 更多内容")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("引申")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/OS",target:"_blank",rel:"noopener noreferrer"}},[t._v("操作系统、运维部署总结系列"),r("OutboundLink")],1)])])])])])}),[],!1,null,null,null);a.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/68.46427a01.js b/assets/js/68.46427a01.js new file mode 100644 index 0000000..b5ea488 --- /dev/null +++ b/assets/js/68.46427a01.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[68],{453:function(t,a,e){"use strict";e.r(a);var s=e(15),r=Object(s.a)({},(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"yapi-运维"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#yapi-运维"}},[t._v("#")]),t._v(" YApi 运维")]),t._v(" "),e("blockquote",[e("p",[e("a",{attrs:{href:"https://github.com/YMFE/yapi",target:"_blank",rel:"noopener noreferrer"}},[t._v("YApi"),e("OutboundLink")],1),t._v(" 是一个可本地部署的、打通前后端及 QA 的、可视化的接口管理平台。")]),t._v(" "),e("p",[t._v("本文目的在于记录 svn 的安装、配置、使用。")])]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/dev/snap/1562814562978.png",alt:"img"}})]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"#1-%E6%99%AE%E9%80%9A%E9%83%A8%E7%BD%B2"}},[t._v("1. 普通部署")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"#11-%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82"}},[t._v("1.1. 环境要求")])]),t._v(" "),e("li",[e("a",{attrs:{href:"#12-%E9%83%A8%E7%BD%B2"}},[t._v("1.2. 部署")])]),t._v(" "),e("li",[e("a",{attrs:{href:"#13-%E5%8D%87%E7%BA%A7"}},[t._v("1.3. 升级")])])])]),t._v(" "),e("li",[e("a",{attrs:{href:"#2-docker-%E9%83%A8%E7%BD%B2"}},[t._v("2. Docker 部署")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"#21-%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82"}},[t._v("2.1. 环境要求")])]),t._v(" "),e("li",[e("a",{attrs:{href:"#22-%E9%83%A8%E7%BD%B2"}},[t._v("2.2. 部署")])])])]),t._v(" "),e("li",[e("a",{attrs:{href:"#3-%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"}},[t._v("3. 参考资料")])])]),t._v(" "),e("h2",{attrs:{id:"_1-普通部署"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-普通部署"}},[t._v("#")]),t._v(" 1. 普通部署")]),t._v(" "),e("h3",{attrs:{id:"_1-1-环境要求"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-1-环境要求"}},[t._v("#")]),t._v(" 1.1. 环境要求")]),t._v(" "),e("ul",[e("li",[t._v("nodejs(7.6+)")]),t._v(" "),e("li",[t._v("mongodb(2.6+)")]),t._v(" "),e("li",[t._v("git")])]),t._v(" "),e("h3",{attrs:{id:"_1-2-部署"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-2-部署"}},[t._v("#")]),t._v(" 1.2. 部署")]),t._v(" "),e("h4",{attrs:{id:"方式一-可视化部署-推荐"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#方式一-可视化部署-推荐"}},[t._v("#")]),t._v(" 方式一. 可视化部署[推荐]")]),t._v(" "),e("p",[t._v("执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定 url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("$ "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("npm")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" -g yapi-cli --registry https://registry.npm.taobao.org\n$ yapi server\n")])])]),e("h4",{attrs:{id:"方式二-命令行部署"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#方式二-命令行部署"}},[t._v("#")]),t._v(" 方式二. 命令行部署")]),t._v(" "),e("p",[t._v("如果 github 压缩文件无法下载,或需要部署到一些特殊的服务器,可尝试此方法")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("mkdir")]),t._v(" yapi\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" yapi\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" clone https://github.com/YMFE/yapi.git vendors //或者下载 "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("zip")]),t._v(" 包解压到 vendors 目录(clone 整个仓库大概 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("140")]),t._v("+ M,可以通过 "),e("span",{pre:!0,attrs:{class:"token variable"}},[e("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")]),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("git")]),t._v(" clone --depth"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" https://github.com/YMFE/yapi.git vendors"),e("span",{pre:!0,attrs:{class:"token variable"}},[t._v("`")])]),t._v(" 命令减少,大概 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("+ M)\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("cp")]),t._v(" vendors/config_example.json ./config.json //复制完成后请修改相关配置\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("cd")]),t._v(" vendors\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("npm")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("install")]),t._v(" --production --registry https://registry.npm.taobao.org\n"),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("npm")]),t._v(" run install-server //安装程序会初始化数据库索引和管理员账号,管理员账号名可在 config.json 配置\nnode server/app.js //启动服务器后,请访问 "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("127.0")]),t._v(".0.1:"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("config.json配置的端口"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(",初次运行会有个编译的过程,请耐心等候\n")])])]),e("p",[t._v("安装后的目录结构如下:")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("|-- config.json\n|-- init.lock\n|-- log\n`-- vendors\n |-- CHANGELOG.md\n |-- LICENSE\n |-- README.md\n |-- client\n |-- common\n |-- config_example.json\n |-- doc\n |-- exts\n |-- nodemon.json\n |-- npm-debug.log\n |-- package.json\n |-- plugin.json\n |-- server\n |-- static\n |-- test\n |-- webpack.alias.js\n |-- yapi-base-flow.jpg\n |-- ydocfile.js\n `-- ykit.config.js\n")])])]),e("h3",{attrs:{id:"_1-3-升级"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_1-3-升级"}},[t._v("#")]),t._v(" 1.3. 升级")]),t._v(" "),e("p",[t._v("升级项目版本是非常容易的,并且不会影响已有的项目数据,只会同步 vendors 目录下的源码文件。")]),t._v(" "),e("div",{staticClass:"language- extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("cd {项目目录}\nyapi ls //查看版本号列表\nyapi update //升级到最新版本\nyapi update -v v1.1.0 //升级到指定版本\n")])])]),e("h2",{attrs:{id:"_2-docker-部署"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-docker-部署"}},[t._v("#")]),t._v(" 2. Docker 部署")]),t._v(" "),e("h3",{attrs:{id:"_2-1-环境要求"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-1-环境要求"}},[t._v("#")]),t._v(" 2.1. 环境要求")]),t._v(" "),e("ul",[e("li",[t._v("系统:"),e("code",[t._v("CentOS 7.4")])]),t._v(" "),e("li",[t._v("硬件要求:"),e("code",[t._v("1 GB RAM minimum")])]),t._v(" "),e("li",[t._v("ip:"),e("code",[t._v("http://192.168.1.121")])]),t._v(" "),e("li",[t._v("docker version:"),e("code",[t._v("17.12.1-ce, build 7390fc6")])]),t._v(" "),e("li",[t._v("docker-compose version:"),e("code",[t._v("1.18.0, build 8dd22a9")])])]),t._v(" "),e("blockquote",[e("p",[t._v("建议部署成 http 站点,因 chrome 浏览器安全限制,部署成 https 会导致测试功能在请求 http 站点时文件上传功能异常。--"),e("a",{attrs:{href:"https://yapi.ymfe.org/devops.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("来源"),e("OutboundLink")],1)])]),t._v(" "),e("h3",{attrs:{id:"_2-2-部署"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_2-2-部署"}},[t._v("#")]),t._v(" 2.2. 部署")]),t._v(" "),e("ul",[e("li",[t._v("一个好心人的维护:"),e("a",{attrs:{href:"https://github.com/branchzero/yapi-docker",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/branchzero/yapi-docker"),e("OutboundLink")],1)]),t._v(" "),e("li",[t._v("使用方法: - work path:"),e("code",[t._v("mkdir -p /opt/git-data")]),t._v(" - clone:"),e("code",[t._v("cd /opt/git-data && git clone https://github.com/branchzero/yapi-docker.git")]),t._v(" - permission:"),e("code",[t._v("chmod -R 777 /opt/git-data")]),t._v(" - run command:"),e("code",[t._v("cd /opt/git-data/yapi-docker && docker-compose up -d")]),t._v(" - open chrome:"),e("code",[t._v("http://192.168.1.121:3000")])]),t._v(" "),e("li",[t._v("初始化管理员账号名:"),e("code",[t._v("admin@admin.com")]),t._v(",密码:"),e("code",[t._v("ymfe.org")])])]),t._v(" "),e("h2",{attrs:{id:"_3-参考资料"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#_3-参考资料"}},[t._v("#")]),t._v(" 3. 参考资料")]),t._v(" "),e("ul",[e("li",[e("a",{attrs:{href:"https://github.com/YMFE/yapi",target:"_blank",rel:"noopener noreferrer"}},[t._v("官方 Github"),e("OutboundLink")],1)]),t._v(" "),e("li",[e("a",{attrs:{href:"http://yapi.demo.qunar.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("官网在线演示"),e("OutboundLink")],1)]),t._v(" "),e("li",[e("a",{attrs:{href:"https://hellosean1025.github.io/yapi/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("官方使用手册"),e("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/69.450417bb.js b/assets/js/69.450417bb.js new file mode 100644 index 0000000..880599b --- /dev/null +++ b/assets/js/69.450417bb.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[69],{454:function(s,t,a){"use strict";a.r(t);var n=a(15),r=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"安装-ruby"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#安装-ruby"}},[s._v("#")]),s._v(" 安装 Ruby")]),s._v(" "),a("h2",{attrs:{id:"安装-rvm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#安装-rvm"}},[s._v("#")]),s._v(" 安装 rvm")]),s._v(" "),a("h3",{attrs:{id:"下载安装-rvm"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#下载安装-rvm"}},[s._v("#")]),s._v(" 下载安装 rvm")]),s._v(" "),a("ul",[a("li",[s._v("先安装好 RVM")]),s._v(" "),a("li",[s._v("RVM 是一个便捷的多版本 Ruby 环境的管理和切换工具\n官网:"),a("a",{attrs:{href:"https://links.jianshu.com/go?to=https%3A%2F%2Frvm.io%2F",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://rvm.io/"),a("OutboundLink")],1)]),s._v(" "),a("li",[s._v("在终端控制台命令:\n$ curl -sSL "),a("a",{attrs:{href:"https://links.jianshu.com/go?to=https%3A%2F%2Fget.rvm.io",target:"_blank",rel:"noopener noreferrer"}},[s._v("https://get.rvm.io"),a("OutboundLink")],1),s._v(" | bash -s stable 之后按回车键")]),s._v(" "),a("li",[s._v("截止到目前 最新的版本是 1.29.9")]),s._v(" "),a("li",[s._v("如下所示:")])]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[s._v(":~ admin$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("curl")]),s._v(" -sSL https://get.rvm.io "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v("|")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("bash")]),s._v(" -s stable\nDownloading https://github.com/rvm/rvm/archive/1.29.1.tar.gz\nDownloading https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc\nFound PGP signature at: "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v("'https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc'")]),s._v(",\nbut no GPG software exists to validate it, skipping.\n\nInstalling RVM to /Users/admin/.rvm/\n Adding rvm "),a("span",{pre:!0,attrs:{class:"token environment constant"}},[s._v("PATH")]),s._v(" line to /Users/admin/.profile /Users/admin/.mkshrc /Users/admin/.bashrc /Users/admin/.zshrc.\n Adding rvm loading line to /Users/admin/.profile /Users/admin/.bash_profile /Users/admin/.zlogin.\nInstallation of RVM "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" /Users/admin/.rvm/ is almost complete:\n\n * To start using RVM you need to run "),a("span",{pre:!0,attrs:{class:"token variable"}},[a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")]),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" /Users/admin/.rvm/scripts/rvm"),a("span",{pre:!0,attrs:{class:"token variable"}},[s._v("`")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" all your "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("open")]),s._v(" shell windows, "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("in")]),s._v(" rare cases you need to reopen all shell windows.\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# admin,")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# Thank you for using RVM!")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# We sincerely hope that RVM helps to make your life easier and more enjoyable!!!")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("#")]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# ~Wayne, Michal & team.")]),s._v("\n\nIn "),a("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("case")]),s._v(" of problems: https://rvm.io/help and https://twitter.com/rvm_io\n")])])]),a("p",[s._v("等待一两分钟,成功安装好 RVM。")]),s._v(" "),a("h3",{attrs:{id:"设置环境变量"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#设置环境变量"}},[s._v("#")]),s._v(" 设置环境变量")]),s._v(" "),a("div",{staticClass:"language-shell extra-class"},[a("pre",{pre:!0,attrs:{class:"language-shell"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 1.2 然后,载入 RVM 环境:")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" /etc/profile.d/rvm.sh\n$ "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("sudo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("chmod")]),s._v(" -R "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("777")]),s._v(" /usr/local/rvm/archives\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("# 1.3 修改 RVM 下载 Ruby 的源,到 Ruby China 的镜像")]),s._v("\n$ "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"ruby_url=https://cache.ruby-china.com/pub/ruby"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" /usr/local/rvm/user/db\n$ rvm "),a("span",{pre:!0,attrs:{class:"token function"}},[s._v("install")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("2.7")]),s._v(".0 --disable-binary\n\n// 如下所示:\nAdmindeiMac-4:~ admin$ "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("source")]),s._v(" ~/.rvm/scripts/rvm\nAdmindeiMac-4:~ admin$ "),a("span",{pre:!0,attrs:{class:"token builtin class-name"}},[s._v("echo")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('"ruby_url=https://cache.ruby-china.org/pub/ruby"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(">")]),s._v(" ~/.rvm/user/db\nAdmindeiMac-4:~ admin$ rvm -v\nrvm "),a("span",{pre:!0,attrs:{class:"token number"}},[s._v("1.29")]),s._v(".9 "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("(")]),s._v("latest"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(")")]),s._v(" by Michal Papis, Piotr Kuczynski, Wayne E. Seguin "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),s._v("https://rvm.io/"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n如果能显示版本号,则安装成功。\n")])])]),a("h2",{attrs:{id:"参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[s._v("#")]),s._v(" 参考资料")]),s._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://www.jianshu.com/p/c073e6fc01f5",target:"_blank",rel:"noopener noreferrer"}},[s._v("MAC_Ruby 安装"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/7.046e5a1b.js b/assets/js/7.046e5a1b.js new file mode 100644 index 0000000..5b9a02b --- /dev/null +++ b/assets/js/7.046e5a1b.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{346:function(t,e,a){},377:function(t,e,a){"use strict";a(346)},396:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(377),a(15)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/70.072034d2.js b/assets/js/70.072034d2.js new file mode 100644 index 0000000..ecc649c --- /dev/null +++ b/assets/js/70.072034d2.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[70],{391:function(n,e,t){"use strict";t.r(e),t.d(e,"register",(function(){return o})),t.d(e,"unregister",(function(){return c}));var r;function o(n,e){void 0===e&&(e={});var t=e.registrationOptions;void 0===t&&(t={}),delete e.registrationOptions;var o=function(n){for(var t=[],r=arguments.length-1;r-- >0;)t[r]=arguments[r+1];e&&e[n]&&e[n].apply(e,t)};"serviceWorker"in navigator&&r.then((function(){Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/))?(!function(n,e,t){fetch(n).then((function(r){404===r.status?(e("error",new Error("Service worker not found at "+n)),c()):-1===r.headers.get("content-type").indexOf("javascript")?(e("error",new Error("Expected "+n+" to have javascript content-type, but received "+r.headers.get("content-type"))),c()):a(n,e,t)})).catch((function(n){return i(e,n)}))}(n,o,t),navigator.serviceWorker.ready.then((function(n){o("ready",n)})).catch((function(n){return i(o,n)}))):(a(n,o,t),navigator.serviceWorker.ready.then((function(n){o("ready",n)})).catch((function(n){return i(o,n)})))}))}function i(n,e){navigator.onLine||n("offline"),n("error",e)}function a(n,e,t){navigator.serviceWorker.register(n,t).then((function(n){e("registered",n),n.waiting?e("updated",n):n.onupdatefound=function(){e("updatefound",n);var t=n.installing;t.onstatechange=function(){"installed"===t.state&&(navigator.serviceWorker.controller?e("updated",n):e("cached",n))}}})).catch((function(n){return i(e,n)}))}function c(){"serviceWorker"in navigator&&navigator.serviceWorker.ready.then((function(n){n.unregister()})).catch((function(n){return i(emit,n)}))}"undefined"!=typeof window&&(r="undefined"!=typeof Promise?new Promise((function(n){return window.addEventListener("load",n)})):{then:function(n){return window.addEventListener("load",n)}})}}]); \ No newline at end of file diff --git a/assets/js/8.77fb8967.js b/assets/js/8.77fb8967.js new file mode 100644 index 0000000..d933033 --- /dev/null +++ b/assets/js/8.77fb8967.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{347:function(e,t,a){},378:function(e,t,a){"use strict";a(347)},397:function(e,t,a){"use strict";a.r(t);a(74),a(33),a(102),a(103);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(378),a(15)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/assets/js/9.ebfa537e.js b/assets/js/9.ebfa537e.js new file mode 100644 index 0000000..3cc6889 --- /dev/null +++ b/assets/js/9.ebfa537e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{395:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(15),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/assets/js/app.79a38eea.js b/assets/js/app.79a38eea.js new file mode 100644 index 0000000..ecc6087 --- /dev/null +++ b/assets/js/app.79a38eea.js @@ -0,0 +1,8 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,l,a=e[0],u=e[1],s=e[2],f=0,p=[];f=0&&Math.floor(e)===e&&isFinite(t)}function v(t){return i(t)&&"function"==typeof t.then&&"function"==typeof t.catch}function d(t){return null==t?"":Array.isArray(t)||c(t)&&t.toString===s?JSON.stringify(t,null,2):String(t)}function h(t){var e=parseFloat(t);return isNaN(e)?t:e}function g(t,e){for(var n=Object.create(null),r=t.split(","),o=0;o-1)return t.splice(n,1)}}var b=Object.prototype.hasOwnProperty;function x(t,e){return b.call(t,e)}function _(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}var w=/-(\w)/g,k=_((function(t){return t.replace(w,(function(t,e){return e?e.toUpperCase():""}))})),O=_((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),E=/\B([A-Z])/g,j=_((function(t){return t.replace(E,"-$1").toLowerCase()}));var S=Function.prototype.bind?function(t,e){return t.bind(e)}:function(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n};function A(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function C(t,e){for(var n in e)t[n]=e[n];return t}function P(t){for(var e={},n=0;n0,J=K&&K.indexOf("edge/")>0,Z=(K&&K.indexOf("android"),K&&/iphone|ipad|ipod|ios/.test(K)||"ios"===G),Q=(K&&/chrome\/\d+/.test(K),K&&/phantomjs/.test(K),K&&K.match(/firefox\/(\d+)/)),tt={}.watch,et=!1;if(q)try{var nt={};Object.defineProperty(nt,"passive",{get:function(){et=!0}}),window.addEventListener("test-passive",null,nt)}catch(t){}var rt=function(){return void 0===H&&(H=!q&&!W&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),H},ot=q&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function it(t){return"function"==typeof t&&/native code/.test(t.toString())}var lt,at="undefined"!=typeof Symbol&&it(Symbol)&&"undefined"!=typeof Reflect&&it(Reflect.ownKeys);lt="undefined"!=typeof Set&&it(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var ut=L,st=0,ct=function(){this.id=st++,this.subs=[]};ct.prototype.addSub=function(t){this.subs.push(t)},ct.prototype.removeSub=function(t){y(this.subs,t)},ct.prototype.depend=function(){ct.target&&ct.target.addDep(this)},ct.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e-1)if(i&&!x(o,"default"))l=!1;else if(""===l||l===j(t)){var u=Ft(String,o.type);(u<0||a0&&(ce((u=t(u,(n||"")+"_"+r))[0])&&ce(c)&&(f[s]=mt(c.text+u[0].text),u.shift()),f.push.apply(f,u)):a(u)?ce(c)?f[s]=mt(c.text+u):""!==u&&f.push(mt(u)):ce(u)&&ce(c)?f[s]=mt(c.text+u.text):(l(e._isVList)&&i(u.tag)&&o(u.key)&&i(n)&&(u.key="__vlist"+n+"_"+r+"__"),f.push(u)));return f}(t):void 0}function ce(t){return i(t)&&i(t.text)&&!1===t.isComment}function fe(t,e){if(t){for(var n=Object.create(null),r=at?Reflect.ownKeys(t):Object.keys(t),o=0;o0,l=t?!!t.$stable:!i,a=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(l&&n&&n!==r&&a===n.$key&&!i&&!n.$hasNormal)return n;for(var u in o={},t)t[u]&&"$"!==u[0]&&(o[u]=he(e,u,t[u]))}else o={};for(var s in e)s in o||(o[s]=ge(e,s));return t&&Object.isExtensible(t)&&(t._normalized=o),F(o,"$stable",l),F(o,"$key",a),F(o,"$hasNormal",i),o}function he(t,e,n){var r=function(){var t=arguments.length?n.apply(null,arguments):n({});return(t=t&&"object"==typeof t&&!Array.isArray(t)?[t]:se(t))&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:r,enumerable:!0,configurable:!0}),r}function ge(t,e){return function(){return t[e]}}function me(t,e){var n,r,o,l,a;if(Array.isArray(t)||"string"==typeof t)for(n=new Array(t.length),r=0,o=t.length;rdocument.createEvent("Event").timeStamp&&(un=function(){return sn.now()})}function cn(){var t,e;for(an=un(),on=!0,tn.sort((function(t,e){return t.id-e.id})),ln=0;lnln&&tn[n].id>t.id;)n--;tn.splice(n+1,0,t)}else tn.push(t);rn||(rn=!0,ee(cn))}}(this)},pn.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||u(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){Bt(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},pn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},pn.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},pn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||y(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var vn={enumerable:!0,configurable:!0,get:L,set:L};function dn(t,e,n){vn.get=function(){return this[e][n]},vn.set=function(t){this[e][n]=t},Object.defineProperty(t,n,vn)}function hn(t){t._watchers=[];var e=t.$options;e.props&&function(t,e){var n=t.$options.propsData||{},r=t._props={},o=t.$options._propKeys=[];t.$parent&&kt(!1);var i=function(i){o.push(i);var l=Mt(i,e,n,t);jt(r,i,l),i in t||dn(t,"_props",i)};for(var l in e)i(l);kt(!0)}(t,e.props),e.methods&&function(t,e){t.$options.props;for(var n in e)t[n]="function"!=typeof e[n]?L:S(e[n],t)}(t,e.methods),e.data?function(t){var e=t.$options.data;c(e=t._data="function"==typeof e?function(t,e){pt();try{return t.call(e,e)}catch(t){return Bt(t,e,"data()"),{}}finally{vt()}}(e,t):e||{})||(e={});var n=Object.keys(e),r=t.$options.props,o=(t.$options.methods,n.length);for(;o--;){var i=n[o];0,r&&x(r,i)||(l=void 0,36!==(l=(i+"").charCodeAt(0))&&95!==l&&dn(t,"_data",i))}var l;Et(e,!0)}(t):Et(t._data={},!0),e.computed&&function(t,e){var n=t._computedWatchers=Object.create(null),r=rt();for(var o in e){var i=e[o],l="function"==typeof i?i:i.get;0,r||(n[o]=new pn(t,l||L,L,gn)),o in t||mn(t,o,i)}}(t,e.computed),e.watch&&e.watch!==tt&&function(t,e){for(var n in e){var r=e[n];if(Array.isArray(r))for(var o=0;o-1:"string"==typeof t?t.split(",").indexOf(e)>-1:!!f(t)&&t.test(e)}function Sn(t,e){var n=t.cache,r=t.keys,o=t._vnode;for(var i in n){var l=n[i];if(l){var a=En(l.componentOptions);a&&!e(a)&&An(n,i,r,o)}}}function An(t,e,n,r){var o=t[e];!o||r&&o.tag===r.tag||o.componentInstance.$destroy(),t[e]=null,y(n,e)}!function(t){t.prototype._init=function(t){var e=this;e._uid=_n++,e._isVue=!0,t&&t._isComponent?function(t,e){var n=t.$options=Object.create(t.constructor.options),r=e._parentVnode;n.parent=e.parent,n._parentVnode=r;var o=r.componentOptions;n.propsData=o.propsData,n._parentListeners=o.listeners,n._renderChildren=o.children,n._componentTag=o.tag,e.render&&(n.render=e.render,n.staticRenderFns=e.staticRenderFns)}(e,t):e.$options=zt(wn(e.constructor),t||{},e),e._renderProxy=e,e._self=e,function(t){var e=t.$options,n=e.parent;if(n&&!e.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(t)}t.$parent=n,t.$root=n?n.$root:t,t.$children=[],t.$refs={},t._watcher=null,t._inactive=null,t._directInactive=!1,t._isMounted=!1,t._isDestroyed=!1,t._isBeingDestroyed=!1}(e),function(t){t._events=Object.create(null),t._hasHookEvent=!1;var e=t.$options._parentListeners;e&&Ke(t,e)}(e),function(t){t._vnode=null,t._staticTrees=null;var e=t.$options,n=t.$vnode=e._parentVnode,o=n&&n.context;t.$slots=pe(e._renderChildren,o),t.$scopedSlots=r,t._c=function(e,n,r,o){return De(t,e,n,r,o,!1)},t.$createElement=function(e,n,r,o){return De(t,e,n,r,o,!0)};var i=n&&n.data;jt(t,"$attrs",i&&i.attrs||r,null,!0),jt(t,"$listeners",e._parentListeners||r,null,!0)}(e),Qe(e,"beforeCreate"),function(t){var e=fe(t.$options.inject,t);e&&(kt(!1),Object.keys(e).forEach((function(n){jt(t,n,e[n])})),kt(!0))}(e),hn(e),function(t){var e=t.$options.provide;e&&(t._provided="function"==typeof e?e.call(t):e)}(e),Qe(e,"created"),e.$options.el&&e.$mount(e.$options.el)}}(kn),function(t){var e={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(t.prototype,"$data",e),Object.defineProperty(t.prototype,"$props",n),t.prototype.$set=St,t.prototype.$delete=At,t.prototype.$watch=function(t,e,n){if(c(e))return xn(this,t,e,n);(n=n||{}).user=!0;var r=new pn(this,t,e,n);if(n.immediate)try{e.call(this,r.value)}catch(t){Bt(t,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(kn),function(t){var e=/^hook:/;t.prototype.$on=function(t,n){var r=this;if(Array.isArray(t))for(var o=0,i=t.length;o1?A(n):n;for(var r=A(arguments,1),o='event handler for "'+t+'"',i=0,l=n.length;iparseInt(this.max)&&An(l,a[0],a,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={get:function(){return D}};Object.defineProperty(t,"config",e),t.util={warn:ut,extend:C,mergeOptions:zt,defineReactive:jt},t.set=St,t.delete=At,t.nextTick=ee,t.observable=function(t){return Et(t),t},t.options=Object.create(null),N.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,C(t.options.components,Pn),function(t){t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=A(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this}}(t),function(t){t.mixin=function(t){return this.options=zt(this.options,t),this}}(t),On(t),function(t){N.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&c(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"==typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}(t)}(kn),Object.defineProperty(kn.prototype,"$isServer",{get:rt}),Object.defineProperty(kn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(kn,"FunctionalRenderContext",{value:$e}),kn.version="2.6.12";var Ln=g("style,class"),$n=g("input,textarea,option,select,progress"),Tn=g("contenteditable,draggable,spellcheck"),Rn=g("events,caret,typing,plaintext-only"),In=g("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),zn="http://www.w3.org/1999/xlink",Nn=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},Mn=function(t){return Nn(t)?t.slice(6,t.length):""},Dn=function(t){return null==t||!1===t};function Un(t){for(var e=t.data,n=t,r=t;i(r.componentInstance);)(r=r.componentInstance._vnode)&&r.data&&(e=Fn(r.data,e));for(;i(n=n.parent);)n&&n.data&&(e=Fn(e,n.data));return function(t,e){if(i(t)||i(e))return Bn(t,Hn(e));return""}(e.staticClass,e.class)}function Fn(t,e){return{staticClass:Bn(t.staticClass,e.staticClass),class:i(t.class)?[t.class,e.class]:e.class}}function Bn(t,e){return t?e?t+" "+e:t:e||""}function Hn(t){return Array.isArray(t)?function(t){for(var e,n="",r=0,o=t.length;r-1?pr(t,e,n):In(e)?Dn(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):Tn(e)?t.setAttribute(e,function(t,e){return Dn(e)||"false"===e?"false":"contenteditable"===t&&Rn(e)?e:"true"}(e,n)):Nn(e)?Dn(n)?t.removeAttributeNS(zn,Mn(e)):t.setAttributeNS(zn,e,n):pr(t,e,n)}function pr(t,e,n){if(Dn(n))t.removeAttribute(e);else{if(X&&!Y&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var r=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",r)};t.addEventListener("input",r),t.__ieph=!0}t.setAttribute(e,n)}}var vr={create:cr,update:cr};function dr(t,e){var n=e.elm,r=e.data,l=t.data;if(!(o(r.staticClass)&&o(r.class)&&(o(l)||o(l.staticClass)&&o(l.class)))){var a=Un(e),u=n._transitionClasses;i(u)&&(a=Bn(a,Hn(u))),a!==n._prevClass&&(n.setAttribute("class",a),n._prevClass=a)}}var hr,gr={create:dr,update:dr};function mr(t,e,n){var r=hr;return function o(){var i=e.apply(null,arguments);null!==i&&xr(t,o,n,r)}}var yr=Gt&&!(Q&&Number(Q[1])<=53);function br(t,e,n,r){if(yr){var o=an,i=e;e=i._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=o||t.timeStamp<=0||t.target.ownerDocument!==document)return i.apply(this,arguments)}}hr.addEventListener(t,e,et?{capture:n,passive:r}:n)}function xr(t,e,n,r){(r||hr).removeEventListener(t,e._wrapper||e,n)}function _r(t,e){if(!o(t.data.on)||!o(e.data.on)){var n=e.data.on||{},r=t.data.on||{};hr=e.elm,function(t){if(i(t.__r)){var e=X?"change":"input";t[e]=[].concat(t.__r,t[e]||[]),delete t.__r}i(t.__c)&&(t.change=[].concat(t.__c,t.change||[]),delete t.__c)}(n),le(n,r,br,xr,mr,e.context),hr=void 0}}var wr,kr={create:_r,update:_r};function Or(t,e){if(!o(t.data.domProps)||!o(e.data.domProps)){var n,r,l=e.elm,a=t.data.domProps||{},u=e.data.domProps||{};for(n in i(u.__ob__)&&(u=e.data.domProps=C({},u)),a)n in u||(l[n]="");for(n in u){if(r=u[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),r===a[n])continue;1===l.childNodes.length&&l.removeChild(l.childNodes[0])}if("value"===n&&"PROGRESS"!==l.tagName){l._value=r;var s=o(r)?"":String(r);Er(l,s)&&(l.value=s)}else if("innerHTML"===n&&Wn(l.tagName)&&o(l.innerHTML)){(wr=wr||document.createElement("div")).innerHTML=""+r+"";for(var c=wr.firstChild;l.firstChild;)l.removeChild(l.firstChild);for(;c.firstChild;)l.appendChild(c.firstChild)}else if(r!==a[n])try{l[n]=r}catch(t){}}}}function Er(t,e){return!t.composing&&("OPTION"===t.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(t,e)||function(t,e){var n=t.value,r=t._vModifiers;if(i(r)){if(r.number)return h(n)!==h(e);if(r.trim)return n.trim()!==e.trim()}return n!==e}(t,e))}var jr={create:Or,update:Or},Sr=_((function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach((function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}})),e}));function Ar(t){var e=Cr(t.style);return t.staticStyle?C(t.staticStyle,e):e}function Cr(t){return Array.isArray(t)?P(t):"string"==typeof t?Sr(t):t}var Pr,Lr=/^--/,$r=/\s*!important$/,Tr=function(t,e,n){if(Lr.test(e))t.style.setProperty(e,n);else if($r.test(n))t.style.setProperty(j(e),n.replace($r,""),"important");else{var r=Ir(e);if(Array.isArray(n))for(var o=0,i=n.length;o-1?e.split(Mr).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function Ur(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(Mr).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function Fr(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&C(e,Br(t.name||"v")),C(e,t),e}return"string"==typeof t?Br(t):void 0}}var Br=_((function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}})),Hr=q&&!Y,Vr="transition",qr="transitionend",Wr="animation",Gr="animationend";Hr&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(Vr="WebkitTransition",qr="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Wr="WebkitAnimation",Gr="webkitAnimationEnd"));var Kr=q?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Xr(t){Kr((function(){Kr(t)}))}function Yr(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Dr(t,e))}function Jr(t,e){t._transitionClasses&&y(t._transitionClasses,e),Ur(t,e)}function Zr(t,e,n){var r=to(t,e),o=r.type,i=r.timeout,l=r.propCount;if(!o)return n();var a="transition"===o?qr:Gr,u=0,s=function(){t.removeEventListener(a,c),n()},c=function(e){e.target===t&&++u>=l&&s()};setTimeout((function(){u0&&(n="transition",c=l,f=i.length):"animation"===e?s>0&&(n="animation",c=s,f=u.length):f=(n=(c=Math.max(l,s))>0?l>s?"transition":"animation":null)?"transition"===n?i.length:u.length:0,{type:n,timeout:c,propCount:f,hasTransform:"transition"===n&&Qr.test(r[Vr+"Property"])}}function eo(t,e){for(;t.length1}function ao(t,e){!0!==e.data.show&&ro(e)}var uo=function(t){var e,n,r={},u=t.modules,s=t.nodeOps;for(e=0;ed?b(t,o(n[m+1])?null:n[m+1].elm,n,v,m,r):v>m&&_(e,p,d)}(p,g,m,n,c):i(m)?(i(t.text)&&s.setTextContent(p,""),b(p,null,m,0,m.length-1,n)):i(g)?_(g,0,g.length-1):i(t.text)&&s.setTextContent(p,""):t.text!==e.text&&s.setTextContent(p,e.text),i(d)&&i(v=d.hook)&&i(v=v.postpatch)&&v(t,e)}}}function E(t,e,n){if(l(n)&&i(t.parent))t.parent.data.pendingInsert=e;else for(var r=0;r-1,l.selected!==i&&(l.selected=i);else if(R(vo(l),r))return void(t.selectedIndex!==a&&(t.selectedIndex=a));o||(t.selectedIndex=-1)}}function po(t,e){return e.every((function(e){return!R(e,t)}))}function vo(t){return"_value"in t?t._value:t.value}function ho(t){t.target.composing=!0}function go(t){t.target.composing&&(t.target.composing=!1,mo(t.target,"input"))}function mo(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function yo(t){return!t.componentInstance||t.data&&t.data.transition?t:yo(t.componentInstance._vnode)}var bo={model:so,show:{bind:function(t,e,n){var r=e.value,o=(n=yo(n)).data&&n.data.transition,i=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;r&&o?(n.data.show=!0,ro(n,(function(){t.style.display=i}))):t.style.display=r?i:"none"},update:function(t,e,n){var r=e.value;!r!=!e.oldValue&&((n=yo(n)).data&&n.data.transition?(n.data.show=!0,r?ro(n,(function(){t.style.display=t.__vOriginalDisplay})):oo(n,(function(){t.style.display="none"}))):t.style.display=r?t.__vOriginalDisplay:"none")},unbind:function(t,e,n,r,o){o||(t.style.display=t.__vOriginalDisplay)}}},xo={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function _o(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?_o(Ve(e.children)):t}function wo(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var o=n._parentListeners;for(var i in o)e[k(i)]=o[i];return e}function ko(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}var Oo=function(t){return t.tag||He(t)},Eo=function(t){return"show"===t.name},jo={name:"transition",props:xo,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(Oo)).length){0;var r=this.mode;0;var o=n[0];if(function(t){for(;t=t.parent;)if(t.data.transition)return!0}(this.$vnode))return o;var i=_o(o);if(!i)return o;if(this._leaving)return ko(t,o);var l="__transition-"+this._uid+"-";i.key=null==i.key?i.isComment?l+"comment":l+i.tag:a(i.key)?0===String(i.key).indexOf(l)?i.key:l+i.key:i.key;var u=(i.data||(i.data={})).transition=wo(this),s=this._vnode,c=_o(s);if(i.data.directives&&i.data.directives.some(Eo)&&(i.data.show=!0),c&&c.data&&!function(t,e){return e.key===t.key&&e.tag===t.tag}(i,c)&&!He(c)&&(!c.componentInstance||!c.componentInstance._vnode.isComment)){var f=c.data.transition=C({},u);if("out-in"===r)return this._leaving=!0,ae(f,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),ko(t,o);if("in-out"===r){if(He(i))return s;var p,v=function(){p()};ae(u,"afterEnter",v),ae(u,"enterCancelled",v),ae(f,"delayLeave",(function(t){p=t}))}}return o}}},So=C({tag:String,moveClass:String},xo);function Ao(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function Co(t){t.data.newPos=t.elm.getBoundingClientRect()}function Po(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,o=e.top-n.top;if(r||o){t.data.moved=!0;var i=t.elm.style;i.transform=i.WebkitTransform="translate("+r+"px,"+o+"px)",i.transitionDuration="0s"}}delete So.mode;var Lo={Transition:jo,TransitionGroup:{props:So,beforeMount:function(){var t=this,e=this._update;this._update=function(n,r){var o=Ye(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,o(),e.call(t,n,r)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,o=this.$slots.default||[],i=this.children=[],l=wo(this),a=0;a-1?Kn[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:Kn[t]=/HTMLUnknownElement/.test(e.toString())},C(kn.options.directives,bo),C(kn.options.components,Lo),kn.prototype.__patch__=q?uo:L,kn.prototype.$mount=function(t,e){return function(t,e,n){var r;return t.$el=e,t.$options.render||(t.$options.render=gt),Qe(t,"beforeMount"),r=function(){t._update(t._render(),n)},new pn(t,r,L,{before:function(){t._isMounted&&!t._isDestroyed&&Qe(t,"beforeUpdate")}},!0),n=!1,null==t.$vnode&&(t._isMounted=!0,Qe(t,"mounted")),t}(this,t=t&&q?function(t){if("string"==typeof t){var e=document.querySelector(t);return e||document.createElement("div")}return t}(t):void 0,e)},q&&setTimeout((function(){D.devtools&&ot&&ot.emit("init",kn)}),0),e.a=kn},function(t,e,n){var r=n(3),o=n(25).f,i=n(16),l=n(18),a=n(79),u=n(117),s=n(76);t.exports=function(t,e){var n,c,f,p,v,d=t.target,h=t.global,g=t.stat;if(n=h?r:g?r[d]||a(d,{}):(r[d]||{}).prototype)for(c in e){if(p=e[c],f=t.noTargetGet?(v=o(n,c))&&v.value:n[c],!s(h?c:d+(g?".":"#")+c,t.forced)&&void 0!==f){if(typeof p==typeof f)continue;u(p,f)}(t.sham||f&&f.sham)&&i(p,"sham",!0),l(n,c,p,t)}}},function(t,e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof global&&global)||function(){return this}()||Function("return this")()},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){var r=n(3),o=n(52),i=n(11),l=n(53),a=n(81),u=n(112),s=o("wks"),c=r.Symbol,f=u?c:c&&c.withoutSetter||l;t.exports=function(t){return i(s,t)&&(a||"string"==typeof s[t])||(a&&i(c,t)?s[t]=c[t]:s[t]=f("Symbol."+t)),s[t]}},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(88),o=n(18),i=n(207);r||o(Object.prototype,"toString",i,{unsafe:!0})},function(t,e,n){var r=n(6);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){var r=n(4);t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(t,e,n){var r=n(9),o=n(110),i=n(8),l=n(38),a=Object.defineProperty;e.f=r?a:function(t,e,n){if(i(t),e=l(e,!0),i(n),o)try{return a(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(14),o={}.hasOwnProperty;t.exports=function(t,e){return o.call(r(t),e)}},function(t,e,n){"use strict";var r=n(131).charAt,o=n(34),i=n(116),l=o.set,a=o.getterFor("String Iterator");i(String,"String",(function(t){l(this,{type:"String Iterator",string:String(t),index:0})}),(function(){var t,e=a(this),n=e.string,o=e.index;return o>=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r=n(3),o=n(132),i=n(109),l=n(16),a=n(5),u=a("iterator"),s=a("toStringTag"),c=i.values;for(var f in o){var p=r[f],v=p&&p.prototype;if(v){if(v[u]!==c)try{l(v,u,c)}catch(t){v[u]=c}if(v[s]||l(v,s,f),o[f])for(var d in i)if(v[d]!==i[d])try{l(v,d,i[d])}catch(t){v[d]=i[d]}}}},function(t,e,n){var r=n(23);t.exports=function(t){return Object(r(t))}},function(t,e,n){"use strict";function r(t,e,n,r,o,i,l,a){var u,s="function"==typeof t?t.options:t;if(e&&(s.render=e,s.staticRenderFns=n,s._compiled=!0),r&&(s.functional=!0),i&&(s._scopeId="data-v-"+i),l?(u=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(l)},s._ssrRegister=u):o&&(u=a?function(){o.call(this,(s.functional?this.parent:this).$root.$options.shadowRoot)}:o),u)if(s.functional){s._injectStyles=u;var c=s.render;s.render=function(t,e){return u.call(e),c(t,e)}}else{var f=s.beforeCreate;s.beforeCreate=f?[].concat(f,u):[u]}return{exports:t,options:s}}n.d(e,"a",(function(){return r}))},function(t,e,n){var r=n(9),o=n(10),i=n(39);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(56),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(3),o=n(16),i=n(11),l=n(79),a=n(84),u=n(34),s=u.get,c=u.enforce,f=String(String).split("String");(t.exports=function(t,e,n,a){var u,s=!!a&&!!a.unsafe,p=!!a&&!!a.enumerable,v=!!a&&!!a.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),(u=c(n)).source||(u.source=f.join("string"==typeof e?e:""))),t!==r?(s?!v&&t[e]&&(p=!0):delete t[e],p?t[e]=n:o(t,e,n)):p?t[e]=n:l(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&s(this).source||a(this)}))},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(37),o=n(23);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(142),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(111),o=n(3),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports=!1},function(t,e,n){var r=n(9),o=n(85),i=n(39),l=n(20),a=n(38),u=n(11),s=n(110),c=Object.getOwnPropertyDescriptor;e.f=r?c:function(t,e){if(t=l(t),e=a(e,!0),s)try{return c(t,e)}catch(t){}if(u(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},function(t,e,n){var r=n(236),o=n(239);t.exports=function(t,e){var n=o(t,e);return r(n)?n:void 0}},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e,n){var r,o=n(8),i=n(191),l=n(83),a=n(41),u=n(115),s=n(80),c=n(57),f=c("IE_PROTO"),p=function(){},v=function(t){return" + + diff --git a/docker/docker-compose.html b/docker/docker-compose.html new file mode 100644 index 0000000..b0df479 --- /dev/null +++ b/docker/docker-compose.html @@ -0,0 +1,73 @@ + + + + + + Docker Compose | LINUX-TUTORIAL + + + + + + + + +

# Docker Compose

compose (opens new window) 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 OpenStack 中的 Heat 十分类似。

# 一、Compose 简介

Compose 的定位是:定义和运行多个 Docker 容器的应用。 使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

# 二、安装卸载

Compose 支持 Linux、macOS、Windows10 三大平台。

Linux 安装方式:

sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
+sudo chmod +x /usr/local/bin/docker-compose
+

🔔 详情请参考:Install Docker Compose (opens new window)

# 三、快速入门

# web 应用

新建文件夹,在该目录中编写 app.py 文件

from flask import Flask
+from redis import Redis
+
+app = Flask(__name__)
+redis = Redis(host='redis', port=6379)
+
+@app.route('/')
+def hello():
+    count = redis.incr('hits')
+    return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
+
+if __name__ == "__main__":
+    app.run(host="0.0.0.0", debug=True)
+

# Dockerfile

编写 Dockerfile 文件,内容为

FROM python:3.6-alpine
+ADD . /code
+WORKDIR /code
+RUN pip install redis flask
+CMD ["python", "app.py"]
+

# docker-compose.yml

编写 docker-compose.yml 文件,这个是 Compose 使用的主模板文件。

version: '3'
+services:
+
+  web:
+    build: .
+    ports:
+     - "5000:5000"
+
+  redis:
+    image: "redis:alpine"
+

# 运行 compose 项目

$ docker-compose up
+

此时访问本地 5000 端口,每次刷新页面,计数就会加 1。

# 四、命令

🔔 请参考:

# 五、模板文件

docker-compose.yml 文件是 Docker Compose 的模板文件,其作用类似于 Dockerfile 和 Docker。

docker-compose.yml 支持的默认环境变量官方文档 (opens new window)

# 参考资料

+ + + diff --git a/docker/docker-dockerfile.html b/docker/docker-dockerfile.html new file mode 100644 index 0000000..0b6b853 --- /dev/null +++ b/docker/docker-dockerfile.html @@ -0,0 +1,222 @@ + + + + + + Dockerfile 最佳实践 | LINUX-TUTORIAL + + + + + + + + +

# Dockerfile 最佳实践

# 一、Dockerfile 简介

Docker 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

# 使用 Dockerfile 构建镜像

# 二、Dockerfile 指令详解

# FROM(指定基础镜像)

作用:FROM 指令用于指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 FROM 就是指定基础镜像,因此一个 DockerfileFROM 是必备的指令,并且必须是第一条指令。

Docker Store (opens new window) 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx (opens new window)redis (opens new window)mongo (opens new window)mysql (opens new window)httpd (opens new window)php (opens new window)tomcat (opens new window) 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node (opens new window)openjdk (opens new window)python (opens new window)ruby (opens new window)golang (opens new window) 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 ubuntu (opens new window)debian (opens new window)centos (opens new window)fedora (opens new window)alpine (opens new window) 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

FROM scratch
+...
+

如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarm (opens new window)coreos/etcd (opens new window)。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言 (opens new window) 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

# RUN(执行命令)

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
+
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

既然 RUN 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如这样:

FROM debian:jessie
+
+RUN apt-get update
+RUN apt-get install -y gcc libc6-dev make
+RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
+RUN mkdir -p /usr/src/redis
+RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
+RUN make -C /usr/src/redis
+RUN make -C /usr/src/redis install
+

之前说过,Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。

而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。

Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。

上面的 Dockerfile 正确的写法应该是这样:

FROM debian:jessie
+
+RUN buildDeps='gcc libc6-dev make' \
+    && apt-get update \
+    && apt-get install -y $buildDeps \
+    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
+    && mkdir -p /usr/src/redis \
+    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
+    && make -C /usr/src/redis \
+    && make -C /usr/src/redis install \
+    && rm -rf /var/lib/apt/lists/* \
+    && rm redis.tar.gz \
+    && rm -r /usr/src/redis \
+    && apt-get purge -y --auto-remove $buildDeps
+

首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。

并且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。

此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了 apt 缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。

很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。

# COPY(复制文件)

COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。

格式:

  • COPY [--chown=<user>:<group>] <源路径>... <目标路径>
  • COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

示例:

COPY package.json /usr/src/app/
+

<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match (opens new window) 规则,如:

COPY hom* /mydir/
+COPY hom?.txt /mydir/
+

<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

COPY --chown=55:mygroup files* /mydir/
+COPY --chown=bin files* /mydir/
+COPY --chown=1 files* /mydir/
+COPY --chown=10:11 files* /mydir/
+

# ADD(更高级的复制文件)

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

比如 <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径>去。下载后的文件权限自动设置为 600,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。

如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。

在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 ubuntu 中:

FROM scratch
+ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
+...
+

但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。

在 Docker 官方的 Dockerfile 最佳实践文档 (opens new window) 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。

另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

因此在 COPYADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD

在使用该指令的时候还可以加上 --chown=<user>:<group> 选项来改变文件的所属用户及所属组。

ADD --chown=55:mygroup files* /mydir/
+ADD --chown=bin files* /mydir/
+ADD --chown=1 files* /mydir/
+ADD --chown=10:11 files* /mydir/
+

# CMD(容器启动命令)

之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD/bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。

在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。

如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

CMD echo $HOME
+

在实际执行中,会将其变更为:

CMD [ "sh", "-c", "echo $HOME" ]
+

这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。

提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。

Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。

一些初学者将 CMD 写为:

CMD service nginx start
+

然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。

正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:

CMD ["nginx", "-g", "daemon off;"]
+

# ENTRYPOINT(入口点)

ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式和 shell 格式。

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:

<ENTRYPOINT> "<CMD>"
+

那么有了 CMD 后,为什么还要有 ENTRYPOINT 呢?这种 <ENTRYPOINT> "<CMD>" 有什么好处么?让我们来看几个场景。

# 场景一:让镜像变成像命令一样使用

假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD 来实现:

FROM ubuntu:18.04
+RUN apt-get update \
+    && apt-get install -y curl \
+    && rm -rf /var/lib/apt/lists/*
+CMD [ "curl", "-s", "https://ip.cn" ]
+

假如我们使用 docker build -t myip . 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:

$ docker run myip
+当前 IP:61.148.226.66 来自:北京市 联通
+

嗯,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD 中可以看到实质的命令是 curl,那么如果我们希望显示 HTTP 头信息,就需要加上 -i 参数。那么我们可以直接加 -i 参数给 docker run myip 么?

$ docker run myip -i
+docker: Error response from daemon: invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"exec: \\\"-i\\\": executable file not found in $PATH\"\n".
+

我们可以看到可执行文件找不到的报错,executable file not found。之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i 替换了原来的 CMD,而不是添加在原来的 curl -s https://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。

那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:

$ docker run myip curl -s https://ip.cn -i
+

这显然不是很好的解决方案,而使用 ENTRYPOINT 就可以解决这个问题。现在我们重新用 ENTRYPOINT 来实现这个镜像:

FROM ubuntu:18.04
+RUN apt-get update \
+    && apt-get install -y curl \
+    && rm -rf /var/lib/apt/lists/*
+ENTRYPOINT [ "curl", "-s", "https://ip.cn" ]
+

这次我们再来尝试直接使用 docker run myip -i

$ docker run myip
+当前 IP:61.148.226.66 来自:北京市 联通
+
+$ docker run myip -i
+HTTP/1.1 200 OK
+Server: nginx/1.8.0
+Date: Tue, 22 Nov 2016 05:12:40 GMT
+Content-Type: text/html; charset=UTF-8
+Vary: Accept-Encoding
+X-Powered-By: PHP/5.6.24-1~dotdeb+7.1
+X-Cache: MISS from cache-2
+X-Cache-Lookup: MISS from cache-2:80
+X-Cache: MISS from proxy-2_6
+Transfer-Encoding: chunked
+Via: 1.1 cache-2:80, 1.1 proxy-2_6:8006
+Connection: keep-alive
+
+当前 IP:61.148.226.66 来自:北京市 联通
+

可以看到,这次成功了。这是因为当存在 ENTRYPOINT 后,CMD 的内容将会作为参数传给 ENTRYPOINT,而这里 -i 就是新的 CMD,因此会作为参数传给 curl,从而达到了我们预期的效果。

# 场景二:应用运行前的准备工作

启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。

比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的 mysql 服务器运行之前解决。

此外,可能希望避免使用 root 用户去启动服务,从而提高安全性,而在启动服务前还需要以 root 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 root 身份执行,方便调试等。

这些准备工作是和容器 CMD 无关的,无论 CMD 为什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 ENTRYPOINT 中去执行,而这个脚本会将接到的参数(也就是 <CMD>)作为命令,在脚本最后执行。比如官方镜像 redis 中就是这么做的:

FROM alpine:3.4
+...
+RUN addgroup -S redis && adduser -S -G redis redis
+...
+ENTRYPOINT ["docker-entrypoint.sh"]
+
+EXPOSE 6379
+CMD [ "redis-server" ]
+

可以看到其中为了 redis 服务创建了 redis 用户,并在最后指定了 ENTRYPOINTdocker-entrypoint.sh 脚本。

#!/bin/sh
+...
+# allow the container to be started with `--user`
+if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
+    chown -R redis .
+    exec su-exec redis "$0" "$@"
+fi
+
+exec "$@"
+

该脚本的内容就是根据 CMD 的内容来判断,如果是 redis-server 的话,则切换到 redis 用户身份启动服务器,否则依旧使用 root 身份执行。比如:

$ docker run -it redis id
+uid=0(root) gid=0(root) groups=0(root)
+

# ENV(设置环境变量)

ENV 指令用于设置环境变量。无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

格式:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

示例 1:

ENV VERSION=1.0 DEBUG=on \
+    NAME="Happy Feet"
+

这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。

示例 2:

定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方 node 镜像 Dockerfile 中,就有类似这样的代码:

ENV NODE_VERSION 7.2.0
+
+RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
+  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
+  && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
+  && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
+  && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
+  && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
+  && ln -s /usr/local/bin/node /usr/local/bin/nodejs
+

在这里先定义了环境变量 NODE_VERSION,其后的 RUN 这层里,多次使用 $NODE_VERSION 来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新 7.2.0 即可,Dockerfile 构建维护变得更轻松了。

下列指令可以支持环境变量展开: ADDCOPYENVEXPOSELABELUSERWORKDIRVOLUMESTOPSIGNALONBUILD

可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份 Dockerfile 制作更多的镜像,只需使用不同的环境变量即可。

# ARG(构建参数)

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

格式:ARG <参数名>[=<默认值>]

在 1.13 之前的版本,要求 --build-arg 中的参数名,必须在 Dockerfile 中用 ARG 定义过了,换句话说,就是 --build-arg 指定的参数,必须在 Dockerfile 中使用了。如果对应参数没有被使用,则会报错退出构建。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用 CI 系统,用同样的构建流程构建不同的 Dockerfile 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改。

# VOLUME(定义匿名卷)

格式:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

VOLUME /data
+

这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:

docker run -d -v mydata:/data xxxx
+

在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。

# EXPOSE(暴露端口)

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

格式:EXPOSE <端口1> [<端口2>...]

# WORKDIR(指定工作目录)

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

格式:WORKDIR <工作目录路径>

示例 1:

之前提到一些初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:

RUN cd /app
+RUN echo "hello" > world.txt
+

如果将这个 Dockerfile 进行构建镜像运行后,会发现找不到 /app/world.txt 文件,或者其内容不是 hello。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile 中,这两行 RUN 命令的执行环境根本不同,是两个完全不同的容器。这就是对 Dockerfile 构建分层存储的概念不了解所导致的错误。

之前说过每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。

# LABEL

LABEL用于为镜像添加元数据,元数以键值对的形式指定:

LABEL <key>=<value> <key>=<value> <key>=<value> ...
+

使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。

如,通过LABEL指定一些元数据:

LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
+

指定后可以通过docker inspect查看:

$sudo docker inspect itbilu/test
+"Labels": {
+    "version": "1.0",
+    "description": "这是一个Web服务器",
+    "by": "IT笔录"
+},
+

注意;Dockerfile中还有个MAINTAINER命令,该命令用于指定镜像作者。但MAINTAINER并不推荐使用,更推荐使用LABEL来指定镜像作者。如:

LABEL maintainer="itbilu.com"
+

# USER(指定当前用户)

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

当然,和 WORKDIR 一样,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

格式:USER <用户名>[:<用户组>]

示例 1:

RUN groupadd -r redis && useradd -r -g redis redis
+USER redis
+RUN [ "redis-server" ]
+

如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 su或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu (opens new window)

# 建立 redis 用户,并使用 gosu 换另一个用户执行命令
+RUN groupadd -r redis && useradd -r -g redis redis
+# 下载 gosu
+RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
+    && chmod +x /usr/local/bin/gosu \
+    && gosu nobody true
+# 设置 CMD,并以另外的用户执行
+CMD [ "exec", "gosu", "redis", "redis-server" ]
+

# HEALTHCHECK(健康检查)

格式:

  • HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
  • HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。

在没有 HEALTHCHECK 指令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了。在 1.12 以前,Docker 不会检测到容器的这种状态,从而不会重新调度,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。

而自 1.12 之后,Docker 提供了 HEALTHCHECK 指令,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy

HEALTHCHECK 支持下列选项:

  • --interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
  • --timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
  • --retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。

CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。

HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 一样,分为 shell 格式,和 exec 格式。命令的返回值决定了该次健康检查的成功与否:0:成功;1:失败;2:保留,不要使用这个值。

假设我们有个镜像是个最简单的 Web 服务,我们希望增加健康检查来判断其 Web 服务是否在正常工作,我们可以用 curl 来帮助判断,其 DockerfileHEALTHCHECK 可以这么写:

FROM nginx
+RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
+HEALTHCHECK --interval=5s --timeout=3s \
+  CMD curl -fs http://localhost/ || exit 1
+

这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令。

使用 docker build 来构建这个镜像:

$ docker build -t myweb:v1 .
+

构建好了后,我们启动一个容器:

$ docker run -d --name web -p 80:80 myweb:v1
+

当运行该镜像后,可以通过 docker container ls 看到最初的状态为 (health: starting)

$ docker container ls
+CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES
+03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds (health: starting)   80/tcp, 443/tcp     web
+

在等待几秒钟后,再次 docker container ls,就会看到健康状态变化为了 (healthy)

$ docker container ls
+CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS               NAMES
+03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   18 seconds ago      Up 16 seconds (healthy)   80/tcp, 443/tcp     web
+

如果健康检查连续失败超过了重试次数,状态就会变为 (unhealthy)

为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看。

$ docker inspect --format '{{json .State.Health}}' web | python -m json.tool
+{
+    "FailingStreak": 0,
+    "Log": [
+        {
+            "End": "2016-11-25T14:35:37.940957051Z",
+            "ExitCode": 0,
+            "Output": "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>\n<style>\n    body {\n        width: 35em;\n        margin: 0 auto;\n        font-family: Tahoma, Verdana, Arial, sans-serif;\n    }\n</style>\n</head>\n<body>\n<h1>Welcome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.</p>\n\n<p>For online documentation and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCommercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n<p><em>Thank you for using nginx.</em></p>\n</body>\n</html>\n",
+            "Start": "2016-11-25T14:35:37.780192565Z"
+        }
+    ],
+    "Status": "healthy"
+}
+

# ONBUILD(为他人作嫁衣裳)

格式:ONBUILD <其它指令>

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。

假设我们要制作 Node.js 所写的应用的镜像。我们都知道 Node.js 使用 npm 进行包管理,所有依赖、配置、启动信息等会放到 package.json 文件里。在拿到程序代码后,需要先进行 npm install 才可以获得所有需要的依赖。然后就可以通过 npm start来启动应用。因此,一般来说会这样写 Dockerfile

FROM node:slim
+RUN mkdir /app
+WORKDIR /app
+COPY ./package.json /app
+RUN [ "npm", "install" ]
+COPY . /app/
+CMD [ "npm", "start" ]
+

把这个 Dockerfile 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 Dockerfile 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。

如果第一个 Node.js 项目在开发过程中,发现这个 Dockerfile 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 Dockerfile,再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 Dockerfile 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 Dockerfile,而第二个项目的 Dockerfile 就会被自动修复。

那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 Dockerfile的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 Dockerfile 就会变为:

FROM node:slim
+RUN mkdir /app
+WORKDIR /app
+CMD [ "npm", "start" ]
+

这里我们把项目相关的构建指令拿出来,放到子项目里去。假设这个基础镜像的名字为 my-node 的话,各个项目内的自己的 Dockerfile 就变为:

FROM my-node
+COPY ./package.json /app
+RUN [ "npm", "install" ]
+COPY . /app/
+

基础镜像变化后,各个项目都用这个 Dockerfile 重新构建镜像,会继承基础镜像的更新。

那么,问题解决了么?没有。准确说,只解决了一半。如果这个 Dockerfile 里面有些东西需要调整呢?比如 npm install 都需要加一些参数,那怎么办?这一行 RUN 是不可能放入基础镜像的,因为涉及到了当前项目的 ./package.json,难道又要一个个修改么?所以说,这样制作基础镜像,只解决了原来的 Dockerfile 的前 4 条指令的变化问题,而后面三条指令的变化则完全没办法处理。

ONBUILD 可以解决这个问题。让我们用 ONBUILD 重新写一下基础镜像的 Dockerfile:

FROM node:slim
+RUN mkdir /app
+WORKDIR /app
+ONBUILD COPY ./package.json /app
+ONBUILD RUN [ "npm", "install" ]
+ONBUILD COPY . /app/
+CMD [ "npm", "start" ]
+

这次我们回到原始的 Dockerfile,但是这次将项目相关的指令加上 ONBUILD,这样在构建基础镜像的时候,这三行并不会被执行。然后各个项目的 Dockerfile 就变成了简单地:

FROM my-node
+

是的,只有这么一行。当在各个项目目录中,用这个只有一行的 Dockerfile 构建镜像时,之前基础镜像的那三行 ONBUILD 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 npm install,生成应用镜像。

# 二、最佳实践

有任何的问题或建议,欢迎给我留言 😆

# 参考资料

+ + + diff --git a/docker/docker-quickstart.html b/docker/docker-quickstart.html new file mode 100644 index 0000000..070e54b --- /dev/null +++ b/docker/docker-quickstart.html @@ -0,0 +1,103 @@ + + + + + + Docker 快速入门 | LINUX-TUTORIAL + + + + + + + + +

# Docker 快速入门

# 一、Docker 的简介

# 什么是 Docker

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。

它是目前最流行的 Linux 容器解决方案。

Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。

总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

# 为什么需要 Docker

  • 更高效的利用系统资源 - 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
  • 更快速的启动时间 - 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
  • 一致的运行环境 - 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
  • 持续交付和部署 - 对开发和运维(DevOps (opens new window))人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile (opens new window) 来进行镜像构建,并结合 持续集成(Continuous Integration) (opens new window) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) (opens new window) 系统进行自动部署。而且使用 Dockerfile (opens new window) 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
  • 更轻松的迁移 - 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
  • 更轻松的维护和扩展 - Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像 (opens new window),既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

img

# Docker 的主要用途

Docker 提供了被称为容器的松散隔离环境,在环境中可以打包和运行应用程序。隔离和安全性允许您在给定主机上同时运行多个容器。容器是轻量级的,因为它们不需要管理程序的额外负载,而是直接在主机的内核中运行。这意味着您可以在给定的硬件组合上运行更多容器,而不是使用虚拟机。你甚至可以在实际上是虚拟机的主机中运行 Docker 容器!

Docker 的主要用途,目前有三大类。

  • **提供一次性的环境。**比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
  • **提供弹性的云服务。**因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
  • **组建微服务架构。**通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。

# Docker 的核心概念

# 镜像

Docker 把应用程序及其依赖,打包在镜像(Image)文件里面。

我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

分层存储

因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

# 容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间 (opens new window)。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume) (opens new window)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

# 仓库

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry (opens new window) 就是这样的服务。

一个 Docker Registry 中可以包含多个仓库Repository);每个仓库可以包含多个标签Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Ubuntu 镜像 (opens new window) 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:14.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。

# 二、Docker 的运维

不同操作系统环境下安装 Docker 的方式有所不同,详情可以参:

国内访问 Docker 比较慢,如果需要提速,可以参考 镜像加速器 (opens new window)

安装完成后,运行下面的命令,验证是否安装成功。

  • docker version
  • docker info

Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组(官方文档 (opens new window))。

$ sudo usermod -aG docker $USER
+

Docker 是服务器----客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动(官方文档 (opens new window))。

# service 命令的用法
+$ sudo service docker start
+
+# systemctl 命令的用法
+$ sudo systemctl start docker
+

# 三、Hello World 实例

下面,我们通过最简单的 image 文件"hello world" (opens new window),感受一下 Docker。

需要说明的是,国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站,具体的修改方法在下一篇文章 (opens new window)的第一节。有需要的朋友,可以先看一下。

首先,运行下面的命令,将 image 文件从仓库抓取到本地。

$ docker image pull library/hello-world
+

上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。

由于 Docker 官方提供的 image 文件,都放在library (opens new window)组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。

$ docker image pull hello-world
+

抓取成功以后,就可以在本机看到这个 image 文件了。

$ docker image ls
+

现在,运行这个 image 文件。

$ docker container run hello-world
+

docker container run命令会从 image 文件,生成一个正在运行的容器实例。

注意,docker container run命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。因此,前面的docker image pull命令并不是必需的步骤。

如果运行成功,你会在屏幕上读到下面的输出。

$ docker container run hello-world
+
+Hello from Docker!
+This message shows that your installation appears to be working correctly.
+
+... ...
+

输出这段提示以后,hello world就会停止运行,容器自动终止。

有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。

$ docker container run -it ubuntu bash
+

对于那些不会自动终止的容器,必须使用docker container kill (opens new window) 命令手动终止。

$ docker container kill [containID]
+

# 四、制作 Docker 容器

下面我以 koa-demos (opens new window) 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。

作为准备工作,请先下载源码 (opens new window)

$ git clone https://github.com/ruanyf/koa-demos.git
+$ cd koa-demos
+

# 编写 Dockerfile 文件

首先,在项目的根目录下,新建一个文本文件.dockerignore,写入下面的内容 (opens new window)

.git
+node_modules
+npm-debug.log
+

上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。

然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容 (opens new window)

FROM node:8.4
+COPY . /app
+WORKDIR /app
+RUN npm install --registry=https://registry.npm.taobao.org
+EXPOSE 3000
+

上面代码一共五行,含义如下。

  • FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即 8.4 版本的 node。
  • COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。
  • WORKDIR /app:指定接下来的工作路径为/app
  • RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
  • EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。

# 创建 image 文件

有了 Dockerfile 文件以后,就可以使用docker image build命令创建 image 文件了。

$ docker image build -t koa-demo .
+# 或者
+$ docker image build -t koa-demo:0.0.1 .
+

上面代码中,-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。

如果运行成功,就可以看到新生成的 image 文件koa-demo了。

$ docker image ls
+

# 生成容器

docker container run命令会从 image 文件生成容器。

$ docker container run -p 8000:3000 -it koa-demo /bin/bash
+# 或者
+$ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash
+

上面命令的各个参数含义如下:

  • -p参数:容器的 3000 端口映射到本机的 8000 端口。
  • -it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。
  • koa-demo:0.0.1:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。
  • /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。

如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。

root@66d80f4aaf1e:/app#
+

这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。

root@66d80f4aaf1e:/app# node demos/01.js
+

这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示"Not Found",这是因为这个 demo (opens new window) 没有写路由。

这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。

现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用docker container kill终止容器运行。

# 在本机的另一个终端窗口,查出容器的 ID
+$ docker container ls
+
+# 停止指定的容器运行
+$ docker container kill [containerID]
+

容器停止运行之后,并不会消失,用下面的命令删除容器文件。

# 查出容器的 ID
+$ docker container ls --all
+
+# 删除指定的容器文件
+$ docker container rm [containerID]
+

也可以使用docker container run命令的--rm参数,在容器终止运行后自动删除容器文件。

$ docker container run --rm -p 8000:3000 -it koa-demo /bin/bash
+

# CMD 命令

上一节的例子里面,容器启动以后,需要手动输入命令node demos/01.js。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。

FROM node:8.4
+COPY . /app
+WORKDIR /app
+RUN npm install --registry=https://registry.npm.taobao.org
+EXPOSE 3000
+CMD node demos/01.js
+

上面的 Dockerfile 里面,多了最后一行CMD node demos/01.js,它表示容器启动后自动执行node demos/01.js

你可能会问,RUN命令与CMD命令的区别在哪里?简单说,RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令。

注意,指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令。现在,启动容器可以使用下面的命令。

$ docker container run --rm -p 8000:3000 -it koa-demo:0.0.1
+

# 发布 image 文件

容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。

首先,去 hub.docker.com (opens new window)cloud.docker.com (opens new window) 注册一个账户。然后,用下面的命令登录。

$ docker login
+

接着,为本地的 image 标注用户名和版本。

$ docker image tag [imageName] [username]/[repository]:[tag]
+# 实例
+$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1
+

也可以不标注用户名,重新构建一下 image 文件。

$ docker image build -t [username]/[repository]:[tag] .
+

最后,发布 image 文件。

$ docker image push [username]/[repository]:[tag]
+

发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。

# 参考资料

+ + + diff --git a/docker/index.html b/docker/index.html new file mode 100644 index 0000000..c675fc1 --- /dev/null +++ b/docker/index.html @@ -0,0 +1,42 @@ + + + + + + Docker 教程 | LINUX-TUTORIAL + + + + + + + + + + + + diff --git a/docker/kubernetes.html b/docker/kubernetes.html new file mode 100644 index 0000000..a5a225b --- /dev/null +++ b/docker/kubernetes.html @@ -0,0 +1,126 @@ + + + + + + Kubernetes 应用指南 | LINUX-TUTORIAL + + + + + + + + +

# Kubernetes 应用指南

Kubernetes 是谷歌开源的容器集群管理系统 是用于自动部署,扩展和管理 Docker 应用程序的开源系统,简称 K8S。

关键词: docker

# 一、K8S 简介

K8S 主控组件(Master) 包含三个进程,都运行在集群中的某个节上,通常这个节点被称为 master 节点。这些进程包括:kube-apiserverkube-controller-managerkube-scheduler

集群中的每个非 master 节点都运行两个进程:

  • kubelet,和 master 节点进行通信。
  • kube-proxy,一种网络代理,将 Kubernetes 的网络服务代理到每个节点上。

# K8S 功能

  • 基于容器的应用部署、维护和滚动升级
  • 负载均衡和服务发现
  • 跨机器和跨地区的集群调度
  • 自动伸缩
  • 无状态服务和有状态服务
  • 广泛的 Volume 支持
  • 插件机制保证扩展性

# K8S 核心组件

Kubernetes 主要由以下几个核心组件组成:

  • etcd 保存了整个集群的状态;
  • apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
  • controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
  • scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
  • kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
  • Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);
  • kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡

img

# K8S 核心概念

K8S 包含若干抽象用来表示系统状态,包括:已部署的容器化应用和负载、与它们相关的网络和磁盘资源以及有关集群正在运行的其他操作的信息。

img

  • Pod - K8S 使用 Pod 来管理容器,每个 Pod 可以包含一个或多个紧密关联的容器。Pod 是一组紧密关联的容器集合,它们共享 PID、IPC、Network 和 UTS namespace,是 K8S 调度的基本单位。Pod 内的多个容器共享网络和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。
  • Node - Node 是 Pod 真正运行的主机,可以是物理机,也可以是虚拟机。为了管理 Pod,每个 Node 节点上至少要运行 container runtime(比如 docker 或者 rkt)、kubeletkube-proxy 服务。
  • Namespace - Namespace 是对一组资源和对象的抽象集合,比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的 pods, services, replication controllers 和 deployments 等都是属于某一个 namespace 的(默认是 default),而 node, persistentVolumes 等则不属于任何 namespace。
  • Service - Service 是应用服务的抽象,通过 labels 为应用提供负载均衡和服务发现。匹配 labels 的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上。每个 Service 都会自动分配一个 cluster IP(仅在集群内部可访问的虚拟地址)和 DNS 名,其他容器可以通过该地址或 DNS 来访问服务,而不需要了解后端容器的运行。
  • Label - Label 是识别 K8S 对象的标签,以 key/value 的方式附加到对象上(key 最长不能超过 63 字节,value 可以为空,也可以是不超过 253 字节的字符串)。Label 不提供唯一性,并且实际上经常是很多对象(如 Pods)都使用相同的 label 来标志具体的应用。Label 定义好后其他对象可以使用 Label Selector 来选择一组相同 label 的对象(比如 ReplicaSet 和 Service 用 label 来选择一组 Pod)。Label Selector 支持以下几种方式: +
    • 等式,如 app=nginxenv!=production
    • 集合,如 env in (production, qa)
    • 多个 label(它们之间是 AND 关系),如 app=nginx,env=test
  • Annotations - Annotations 是 key/value 形式附加于对象的注解。不同于 Labels 用于标志和选择对象,Annotations 则是用来记录一些附加信息,用来辅助应用部署、安全策略以及调度策略等。比如 deployment 使用 annotations 来记录 rolling update 的状态。

# 二、K8S 命令

# 客户端配置

# Setup autocomplete in bash; bash-completion package should be installed first
+source <(kubectl completion bash)
+
+# View Kubernetes config
+kubectl config view
+
+# View specific config items by json path
+kubectl config view -o jsonpath='{.users[?(@.name == "k8s")].user.password}'
+
+# Set credentials for foo.kuberntes.com
+kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword
+

# 查找资源

# List all services in the namespace
+kubectl get services
+
+# List all pods in all namespaces in wide format
+kubectl get pods -o wide --all-namespaces
+
+# List all pods in json (or yaml) format
+kubectl get pods -o json
+
+# Describe resource details (node, pod, svc)
+kubectl describe nodes my-node
+
+# List services sorted by name
+kubectl get services --sort-by=.metadata.name
+
+# List pods sorted by restart count
+kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
+
+# Rolling update pods for frontend-v1
+kubectl rolling-update frontend-v1 -f frontend-v2.json
+
+# Scale a replicaset named 'foo' to 3
+kubectl scale --replicas=3 rs/foo
+
+# Scale a resource specified in "foo.yaml" to 3
+kubectl scale --replicas=3 -f foo.yaml
+
+# Execute a command in every pod / replica
+for i in 0 1; do kubectl exec foo-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
+

# 资源管理

# Get documentation for pod or service
+kubectl explain pods,svc
+
+# Create resource(s) like pods, services or daemonsets
+kubectl create -f ./my-manifest.yaml
+
+# Apply a configuration to a resource
+kubectl apply -f ./my-manifest.yaml
+
+# Start a single instance of Nginx
+kubectl run nginx --image=nginx
+
+# Create a secret with several keys
+cat <<EOF | kubectl create -f -
+apiVersion: v1
+kind: Secret
+metadata:
+ name: mysecret
+type: Opaque
+data:
+ password: $(echo "s33msi4" | base64)
+ username: $(echo "jane"| base64)
+EOF
+
+# Delete a resource
+kubectl delete -f ./my-manifest.yaml
+

# 监控和日志

# Deploy Heapster from Github repository
+kubectl create -f deploy/kube-config/standalone/
+
+# Show metrics for nodes
+kubectl top node
+
+# Show metrics for pods
+kubectl top pod
+
+# Show metrics for a given pod and its containers
+kubectl top pod pod_name --containers
+
+# Dump pod logs (stdout)
+kubectl logs pod_name
+
+# Stream pod container logs (stdout, multi-container case)
+kubectl logs -f pod_name -c my-container
+

# 参考资料

+ + + diff --git a/docker/service/docker-install-mysql.html b/docker/service/docker-install-mysql.html new file mode 100644 index 0000000..752de6c --- /dev/null +++ b/docker/service/docker-install-mysql.html @@ -0,0 +1,50 @@ + + + + + + Docker 安装 MySQL | LINUX-TUTORIAL + + + + + + + + +

# Docker 安装 MySQL

实测环境:Centos

# 查看可下载镜像

# docker search mysql
+INDEX       NAME                                                             DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
+docker.io   docker.io/mysql                                                  MySQL is a widely used, open-source relati...   5757      [OK]       
+docker.io   docker.io/mariadb                                                MariaDB is a community-developed fork of M...   1863      [OK]       
+docker.io   docker.io/mysql/mysql-server                                     Optimized MySQL Server Docker images. Crea...   397                  [OK]
+...
+

# 选择下载官方镜像

比如,我想下载最新版本,则执行如下命令:

docker pull mysql
+

# 使用镜像

docker run -p 3306:3306 --name mysql -v /opt/docker_v/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 -d mysql
+

# 资源

  • https://hub.docker.com/_/mysql/
+ + + diff --git a/docker/service/docker-install-nginx.html b/docker/service/docker-install-nginx.html new file mode 100644 index 0000000..ea811f4 --- /dev/null +++ b/docker/service/docker-install-nginx.html @@ -0,0 +1,50 @@ + + + + + + Docker 安装 Nginx | LINUX-TUTORIAL + + + + + + + + +

# Docker 安装 Nginx

实测环境:Centos

# 查看可用镜像

执行 docker search nginx 命令查看可用镜像:

# docker search nginx
+INDEX       NAME                                                             DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
+docker.io   docker.io/nginx                                                  Official build of Nginx.                        8272      [OK]       
+docker.io   docker.io/jwilder/nginx-proxy                                    Automated Nginx reverse proxy for docker c...   1300                 [OK]
+docker.io   docker.io/richarvey/nginx-php-fpm                                Container running Nginx + PHP-FPM capable ...   540                  [OK]
+docker.io   docker.io/jrcs/letsencrypt-nginx-proxy-companion                 LetsEncrypt container to use with nginx as...   336                  [OK]
+...
+

# 选择下载镜像

执行 docker pull nginx 命令下载镜像

# 运行镜像

docker run -p 80:80 --name mynginx -d nginx
+
+ + + diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..51e9bfa Binary files /dev/null and b/favicon.ico differ diff --git a/images/dunwu-logo-100.png b/images/dunwu-logo-100.png new file mode 100644 index 0000000..12d8177 Binary files /dev/null and b/images/dunwu-logo-100.png differ diff --git a/images/dunwu-logo-200.png b/images/dunwu-logo-200.png new file mode 100644 index 0000000..ea0a019 Binary files /dev/null and b/images/dunwu-logo-200.png differ diff --git a/images/dunwu-logo-50.png b/images/dunwu-logo-50.png new file mode 100644 index 0000000..90a1976 Binary files /dev/null and b/images/dunwu-logo-50.png differ diff --git a/images/dunwu-logo.png b/images/dunwu-logo.png new file mode 100644 index 0000000..61570e2 Binary files /dev/null and b/images/dunwu-logo.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..e2a5260 --- /dev/null +++ b/index.html @@ -0,0 +1,53 @@ + + + + + + LINUX-TUTORIAL + + + + + + + + +
hero

+ LINUX-TUTORIAL +

+ 📚 linux-tutorial 是一个 Linux 教程。 +

license build

📚 linux-tutorial 是一个 Linux 教程。

🔁 项目同步维护在 github (opens new window) | gitee (opens new window)

📖 电子书 (opens new window) | 电子书(国内) (opens new window)

# 📖 内容

# Linux 命令

学习 Linux 的第一步:当然是从 Linux 命令 入手了。

# Linux 运维

Linux 系统的常见运维工作。

# 软件运维

部署在 Linux 系统上的软件运维。

配套安装脚本:⌨ 软件运维配置脚本集合 (opens new window)

# Docker

# 其他

# ⌨ 脚本

# Shell 脚本大全

Shell 脚本大全 精心收集、整理了 Linux 环境下的常见 Shell 脚本操作片段。

源码:Shell 脚本大全 (opens new window)

# CentOS 运维脚本集合

本人作为一名 Java 后端,苦于经常在 CentOS 环境上开荒虚拟机。为提高效率,写了一套 Shell 脚本,提供如下功能:安装常用 lib 库、命令工具、设置 DNS、NTP、配置国内 yum 源、一键安装常用软件等。

源码:CentOS 常规操作运维脚本集合 (opens new window)

# 📚 资料

# 🚪 传送门

◾ 🏠 LINUX-TUTORIAL 首页 (opens new window) ◾ 🎯 我的博客 (opens new window)

+ + + diff --git a/linux/cli/free.html b/linux/cli/free.html new file mode 100644 index 0000000..4aa2865 --- /dev/null +++ b/linux/cli/free.html @@ -0,0 +1,115 @@ + + + + + + free | LINUX-TUTORIAL + + + + + + + + +

# free

显示内存的使用情况

# 补充说明

free 命令 可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。

# 语法

free(选项)
+

# 选项

-b # 以Byte为单位显示内存使用情况;
+-k # 以KB为单位显示内存使用情况;
+-m # 以MB为单位显示内存使用情况;
+-g # 以GB为单位显示内存使用情况。
+-o # 不显示缓冲区调节列;
+-s<间隔秒数> # 持续观察内存使用状况;
+-t # 显示内存总和列;
+-V # 显示版本信息。
+

# 实例

free -t    # 以总和的形式显示内存的使用信息
+free -s 10 # 周期性的查询内存使用信息,每10s 执行一次命令
+

显示内存使用情况

free -m
+             total       used       free     shared    buffers     cached
+Mem:          2016       1973         42          0        163       1497
+-/+ buffers/cache:        312       1703
+Swap:         4094          0       4094
+

第一部分 Mem 行解释:

total:内存总数;
+used:已经使用的内存数;
+free:空闲的内存数;
+shared:当前已经废弃不用;
+buffers Buffer:缓存内存数;
+cached Page:缓存内存数。
+

关系:total = used + free

第二部分(-/+ buffers/cache)解释:

(-buffers/cache) used内存数:第一部分Mem行中的 used – buffers – cached
+(+buffers/cache) free内存数: 第一部分Mem行中的 free + buffers + cached
+

可见-buffers/cache 反映的是被程序实实在在吃掉的内存,而+buffers/cache 反映的是可以挪用的内存总数。

第三部分是指交换分区。

输出结果的第四行是交换分区 SWAP 的,也就是我们通常所说的虚拟内存。 +区别:第二行(mem)的 used/free 与第三行(-/+ buffers/cache) used/free 的区别。 这两个的区别在于使用的角度来看,第一行是从 OS 的角度来看,因为对于 OS,buffers/cached 都是属于被使用,所以他的可用内存是 2098428KB,已用内存是 30841684KB,其中包括,内核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached.

第三行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为 buffer/cached 是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached 会很快地被回收。

所以从应用程序的角度来说,可用内存=系统 free memory+buffers+cached。 +如本机情况的可用内存为:

18007156=2098428KB+4545340KB+11363424KB

接下来解释什么时候内存会被交换,以及按什么方交换。

当可用内存少于额定值的时候,就会开会进行交换。如何看额定值:

cat /proc/meminfo
+
+MemTotal:       16140816 kB
+MemFree:          816004 kB
+MemAvailable:    2913824 kB
+Buffers:           17912 kB
+Cached:          2239076 kB
+SwapCached:            0 kB
+Active:         12774804 kB
+Inactive:        1594328 kB
+Active(anon):   12085544 kB
+Inactive(anon):    94572 kB
+Active(file):     689260 kB
+Inactive(file):  1499756 kB
+Unevictable:      116888 kB
+Mlocked:          116888 kB
+SwapTotal:       8191996 kB
+SwapFree:        8191996 kB
+Dirty:                56 kB
+Writeback:             0 kB
+AnonPages:      12229228 kB
+Mapped:           117136 kB
+Shmem:             58736 kB
+Slab:             395568 kB
+SReclaimable:     246700 kB
+SUnreclaim:       148868 kB
+KernelStack:       30496 kB
+PageTables:       165104 kB
+NFS_Unstable:          0 kB
+Bounce:                0 kB
+WritebackTmp:          0 kB
+CommitLimit:    16262404 kB
+Committed_AS:   27698600 kB
+VmallocTotal:   34359738367 kB
+VmallocUsed:      311072 kB
+VmallocChunk:   34350899200 kB
+HardwareCorrupted:     0 kB
+AnonHugePages:   3104768 kB
+HugePages_Total:       0
+HugePages_Free:        0
+HugePages_Rsvd:        0
+HugePages_Surp:        0
+Hugepagesize:       2048 kB
+DirectMap4k:      225536 kB
+DirectMap2M:    13279232 kB
+DirectMap1G:     5242880 kB
+

交换将通过三个途径来减少系统中使用的物理页面的个数:

  1. 减少缓冲与页面 cache 的大小,
  2. 将系统 V 类型的内存页面交换出去,
  3. 换出或者丢弃页面。(Application 占用的内存页,也就是物理内存不足)。

事实上,少量地使用 swap 是不是影响到系统性能的。

那 buffers 和 cached 都是缓存,两者有什么区别呢?

为了提高磁盘存取效率, Linux 做了一些精心的设计, 除了对 dentry 进行缓存(用于 VFS,加速文件路径名到 inode 的转换), 还采取了两种主要 Cache 方式:

Buffer Cache 和 Page Cache。前者针对磁盘块的读写,后者针对文件 inode 的读写。这些 Cache 有效缩短了 I/O 系统调用(比如 read,write,getdents)的时间。 +磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种 Cache 就是分别缓存逻辑和物理级数据的。

Page cache 实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到 page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当 page cache 的数据需要刷新时,page cache 中的数据交给 buffer cache,因为 Buffer Cache 就是缓存磁盘块的。但是这种处理在 2.6 版本的内核之后就变的很简单了,没有真正意义上的 cache 操作。

Buffer cache 是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到 buffer cache 中,例如,文件系统的元数据都会缓存到 buffer cache 中。

简单说来,page cache 用来缓存文件数据,buffer cache 用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到 page cache,如果直接采用 dd 等工具对磁盘进行读写,那么数据会缓存到 buffer cache。

所以我们看 linux,只要不用 swap 的交换空间,就不用担心自己的内存太少.如果常常 swap 用很多,可能你就要考虑加物理内存了.这也是 linux 看内存是否够用的标准.

如果是应用服务器的话,一般只看第二行,+buffers/cache,即对应用程序来说 free 的内存太少了,也是该考虑优化程序或加内存了。

+ + + diff --git a/linux/cli/grep.html b/linux/cli/grep.html new file mode 100644 index 0000000..768c93b --- /dev/null +++ b/linux/cli/grep.html @@ -0,0 +1,176 @@ + + + + + + grep | LINUX-TUTORIAL + + + + + + + + +

# grep

强大的文本搜索工具

# 补充说明

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。

# 选项

-a --text  # 不要忽略二进制数据。
+-A <显示行数>   --after-context=<显示行数>   # 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
+-b --byte-offset                           # 在显示符合范本样式的那一行之外,并显示该行之前的内容。
+-B<显示行数>   --before-context=<显示行数>   # 除了显示符合样式的那一行之外,并显示该行之前的内容。
+-c --count    # 计算符合范本样式的列数。
+-C<显示行数> --context=<显示行数>或-<显示行数> # 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
+-d<进行动作> --directories=<动作>  # 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。
+-e<范本样式> --regexp=<范本样式>   # 指定字符串作为查找文件内容的范本样式。
+-E --extended-regexp             # 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
+-f<范本文件> --file=<规则文件>     # 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。
+-F --fixed-regexp   # 将范本样式视为固定字符串的列表。
+-G --basic-regexp   # 将范本样式视为普通的表示法来使用。
+-h --no-filename    # 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
+-H --with-filename  # 在显示符合范本样式的那一列之前,标示该列的文件名称。
+-i --ignore-case    # 忽略字符大小写的差别。
+-l --file-with-matches   # 列出文件内容符合指定的范本样式的文件名称。
+-L --files-without-match # 列出文件内容不符合指定的范本样式的文件名称。
+-n --line-number         # 在显示符合范本样式的那一列之前,标示出该列的编号。
+-P --perl-regexp         # PATTERN 是一个 Perl 正则表达式
+-q --quiet或--silent     # 不显示任何信息。
+-R/-r  --recursive       # 此参数的效果和指定“-d recurse”参数相同。
+-s --no-messages  # 不显示错误信息。
+-v --revert-match # 反转查找。
+-V --version      # 显示版本信息。
+-w --word-regexp  # 只显示全字符合的列。
+-x --line-regexp  # 只显示全列符合的列。
+-y # 此参数效果跟“-i”相同。
+-o # 只输出文件中匹配到的部分。
+-m <num> --max-count=<num> # 找到num行结果后停止查找,用来限制匹配行数
+

# 规则表达式

^    # 锚定行的开始 如:'^grep'匹配所有以grep开头的行。
+$    # 锚定行的结束 如:'grep$' 匹配所有以grep结尾的行。
+.    # 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。
+*    # 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。
+.*   # 一起用代表任意字符。
+[]   # 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
+[^]  # 匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep'匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。
+\(..\)  # 标记匹配字符,如'\(love\)',love被标记为1。
+\<      # 锚定单词的开始,如:'\<grep'匹配包含以grep开头的单词的行。
+\>      # 锚定单词的结束,如'grep\>'匹配包含以grep结尾的单词的行。
+x\{m\}  # 重复字符x,m次,如:'0\{5\}'匹配包含5个o的行。
+x\{m,\}   # 重复字符x,至少m次,如:'o\{5,\}'匹配至少有5个o的行。
+x\{m,n\}  # 重复字符x,至少m次,不多于n次,如:'o\{5,10\}'匹配5--10个o的行。
+\w    # 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。
+\W    # \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
+\b    # 单词锁定符,如: '\bgrep\b'只匹配grep。
+

# grep 命令常见用法

在文件中搜索一个单词,命令会返回一个包含 “match_pattern” 的文本行:

grep match_pattern file_name
+grep "match_pattern" file_name
+

在多个文件中查找:

grep "match_pattern" file_1 file_2 file_3 ...
+

输出除之外的所有行 -v 选项:

grep -v "match_pattern" file_name
+

标记匹配颜色 --color=auto 选项:

grep "match_pattern" file_name --color=auto
+

使用正则表达式 -E 选项:

grep -E "[1-9]+"
+# 或
+egrep "[1-9]+"
+

使用正则表达式 -P 选项:

grep -P "(\d{3}\-){2}\d{4}" file_name
+

只输出文件中匹配到的部分 -o 选项:

echo this is a test line. | grep -o -E "[a-z]+\."
+line.
+
+echo this is a test line. | egrep -o "[a-z]+\."
+line.
+

统计文件或者文本中包含匹配字符串的行数 -c 选项:

grep -c "text" file_name
+

输出包含匹配字符串的行数 -n 选项:

grep "text" -n file_name
+# 或
+cat file_name | grep "text" -n
+
+#多个文件
+grep "text" -n file_1 file_2
+

打印样式匹配所位于的字符或字节偏移:

echo gun is not unix | grep -b -o "not"
+7:not
+#一行中字符串的字符便宜是从该行的第一个字符开始计算,起始值为0。选项  **-b -o**  一般总是配合使用。
+

搜索多个文件并查找匹配文本在哪些文件中:

grep -l "text" file1 file2 file3...
+

# grep 递归搜索文件

在多级目录中对文本进行递归搜索:

grep "text" . -r -n
+# .表示当前目录。
+

忽略匹配样式中的字符大小写:

echo "hello world" | grep -i "HELLO"
+# hello
+

选项 -e 制动多个匹配样式:

echo this is a text line | grep -e "is" -e "line" -o
+is
+line
+
+#也可以使用 **-f** 选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符。
+cat patfile
+aaa
+bbb
+
+echo aaa bbb ccc ddd eee | grep -f patfile -o
+

在 grep 搜索结果中包括或者排除指定文件:

# 只在目录中所有的.php和.html文件中递归搜索字符"main()"
+grep "main()" . -r --include *.{php,html}
+
+# 在搜索结果中排除所有README文件
+grep "main()" . -r --exclude "README"
+
+# 在搜索结果中排除filelist文件列表里的文件
+grep "main()" . -r --exclude-from filelist
+
+

使用 0 值字节后缀的 grep 与 xargs:

# 测试文件:
+echo "aaa" > file1
+echo "bbb" > file2
+echo "aaa" > file3
+
+grep "aaa" file* -lZ | xargs -0 rm
+
+# 执行后会删除file1和file3,grep输出用-Z选项来指定以0值字节作为终结符文件名(\0),xargs -0 读取输入并用0值字节终结符分隔文件名,然后删除匹配文件,-Z通常和-l结合使用。
+

grep 静默输出:

grep -q "test" filename
+# 不会输出任何信息,如果命令运行成功返回0,失败则返回非0值。一般用于条件测试。
+

打印出匹配文本之前或者之后的行:

# 显示匹配某个结果之后的3行,使用 -A 选项:
+seq 10 | grep "5" -A 3
+5
+6
+7
+8
+
+# 显示匹配某个结果之前的3行,使用 -B 选项:
+seq 10 | grep "5" -B 3
+2
+3
+4
+5
+
+# 显示匹配某个结果的前三行和后三行,使用 -C 选项:
+seq 10 | grep "5" -C 3
+2
+3
+4
+5
+6
+7
+8
+
+# 如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:
+echo -e "a\nb\nc\na\nb\nc" | grep a -A 1
+a
+b
+--
+a
+b
+
+ + + diff --git a/linux/cli/index.html b/linux/cli/index.html new file mode 100644 index 0000000..b2aa56d --- /dev/null +++ b/linux/cli/index.html @@ -0,0 +1,42 @@ + + + + + + Linux 命令行 | LINUX-TUTORIAL + + + + + + + + +

# Linux 命令行

学习 Linux 的第一步:当然是从 Linux 命令入手了。

# 📖 内容

# 📚 资料

# 🚪 传送门

◾ 🏠 DB-TUTORIAL 首页 (opens new window) ◾ 🎯 我的博客 (opens new window)

+ + + diff --git a/linux/cli/iostat.html b/linux/cli/iostat.html new file mode 100644 index 0000000..d6191b7 --- /dev/null +++ b/linux/cli/iostat.html @@ -0,0 +1,64 @@ + + + + + + iostat | LINUX-TUTORIAL + + + + + + + + +

# iostat

监视系统输入输出设备和 CPU 的使用情况

# 补充说明

iostat 命令 被用于监视系统输入输出设备和 CPU 的使用情况。它的特点是汇报磁盘活动统计情况,同时也会汇报出 CPU 使用情况。同 vmstat 一样,iostat 也有一个弱点,就是它不能对某个进程进行深入分析,仅对系统的整体情况进行分析。

# 语法

iostat(选项)(参数)
+

# 选项

-c:仅显示CPU使用情况;
+-d:仅显示设备利用率;
+-k:显示状态以千字节每秒为单位,而不使用块每秒;
+-m:显示状态以兆字节每秒为单位;
+-p:仅显示块设备和所有被使用的其他分区的状态;
+-t:显示每个报告产生时的时间;
+-V:显示版号并退出;
+-x:显示扩展状态。
+

# 参数

  • 间隔时间:每次报告的间隔时间(秒);
  • 次数:显示报告的次数。

# 实例

iostat -x /dev/sda1来观看磁盘 I/O 的详细情况:

iostat -x /dev/sda1
+Linux 2.6.18-164.el5xen (localhost.localdomain)
+2010年03月26日
+
+avg-cpu:  %user   %nice %system %iowait
+%steal   %idle
+            0.11    0.02    0.18    0.35
+0.03    99.31
+
+Device:         tps   Blk_read/s    Blk_wrtn/s
+Blk_read   Blk_wrtn
+sda1                0.02          0.08
+0.00          2014               4
+

详细说明:第二行是系统信息和监测时间,第三行和第四行显示 CPU 使用情况(具体内容和 mpstat 命令相同)。这里主要关注后面 I/O 输出的信息,如下所示:

标示 说明
Device 监测设备名称
rrqm/s 每秒需要读取需求的数量
wrqm/s 每秒需要写入需求的数量
r/s 每秒实际读取需求的数量
w/s 每秒实际写入需求的数量
rsec/s 每秒读取区段的数量
wsec/s 每秒写入区段的数量
rkB/s 每秒实际读取的大小,单位为 KB
wkB/s 每秒实际写入的大小,单位为 KB
avgrq-sz 需求的平均大小区段
avgqu-sz 需求的平均队列长度
await 等待 I/O 平均的时间(milliseconds)
svctm I/O 需求完成的平均时间
%util 被 I/O 需求消耗的 CPU 百分比
+ + + diff --git a/linux/cli/iotop.html b/linux/cli/iotop.html new file mode 100644 index 0000000..0514f9d --- /dev/null +++ b/linux/cli/iotop.html @@ -0,0 +1,69 @@ + + + + + + iotop | LINUX-TUTORIAL + + + + + + + + +

# iotop

用来监视磁盘 I/O 使用状况的工具

# 补充说明

iotop 命令 是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。

iotop 使用 Python 语言编写而成,要求 Python2.5(及以上版本)和 Linux kernel2.6.20(及以上版本)。iotop 提供有源代码及 rpm 包,可从其官方主页下载。

# 安装

Ubuntu

apt-get install iotop
+

CentOS

yum install iotop
+

编译安装

wget http://guichaz.free.fr/iotop/files/iotop-0.4.4.tar.gz
+tar zxf iotop-0.4.4.tar.gz
+python setup.py build
+python setup.py install
+

# 语法

iotop(选项)
+

# 选项

-o:只显示有io操作的进程
+-b:批量显示,无交互,主要用作记录到文件。
+-n NUM:显示NUM次,主要用于非交互式模式。
+-d SEC:间隔SEC秒显示一次。
+-p PID:监控的进程pid。
+-u USER:监控的进程用户。
+

iotop 常用快捷键:

  1. 左右箭头:改变排序方式,默认是按 IO 排序。
  2. r:改变排序顺序。
  3. o:只显示有 IO 输出的进程。
  4. p:进程/线程的显示方式的切换。
  5. a:显示累积使用量。
  6. q:退出。

# 实例

直接执行 iotop 就可以看到效果了:

Total DISK read:       0.00 B/s | Total DISK write:       0.00 B/s
+  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    command
+    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % init [3]
+    2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
+    3 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
+    4 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
+    5 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/0]
+    6 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/1]
+    7 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/1]
+    8 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/1]
+    9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [events/0]
+   10 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [events/1]
+   11 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [khelper]
+2572 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bluetooth]
+
+ + + diff --git a/linux/cli/linux-cli-dir.html b/linux/cli/linux-cli-dir.html new file mode 100644 index 0000000..005a602 --- /dev/null +++ b/linux/cli/linux-cli-dir.html @@ -0,0 +1,196 @@ + + + + + + Linux 文件目录管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 文件目录管理

关键词:cd, ls, pwd, mkdir, rmdir, tree, touch, ln, rename, stat, file, chmod, chown, locate, find, cp, scp, mv, rm

# 1. Linux 文件目录工作机制

# 1.1. Linux 目录结构

linux 目录结构是树形结构,其根目录是 / 。一张思维导图说明各个目录的作用:

img

# 1.2. Linux 文件属性

Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。 +在 Linux 中我们可以使用 ll 或者 ls –l 命令来显示一个文件的属性以及文件所属的用户和组,如:

$ ls -l
+total 64
+dr-xr-xr-x 2 root root 4096 Dec 14 2012 bin
+dr-xr-xr-x 4 root root 4096 Apr 19 2012 boot
+

实例中,bin 文件的第一个属性用 d 表示。d 在 Linux 中代表该文件是一个目录文件。 +在 Linux 中第一个字符代表这个文件是目录、文件或链接文件等等。

  • 当为 d 则是目录
  • 当为 - 则是文件;
  • 若是 l 则表示为链接文档(link file);
  • 若是 b 则表示为装置文件里面的可供储存的接口设备(可随机存取装置);
  • 若是 c 则表示为装置文件里面的串行端口设备,例如键盘、鼠标(一次性读取装置)。

接下来的字符中,以三个为一组,且均为『rwx』 的三个参数的组合。其中,r 代表可读(read)、w 代表可写(write)、x 代表可执行(execute)。 要注意的是,这三个权限的位置不会改变,如果没有权限,就会出现减号 - 而已。

每个文件的属性由左边第一部分的 10 个字符来确定(如下图)。

img

从左至右用 0-9 这些数字来表示。

  • 第 0 位确定文件类型
  • 第 1-3 位确定属主(该文件的拥有者)拥有该文件的权限。
  • 第 4-6 位确定属组(拥有者的同组用户)拥有该文件的权限。
  • 第 7-9 位确定其他用户拥有该文件的权限。
  • 第 1、4、7 位表示读权限,如果用"r"字符表示,则有读权限,如果用"-"字符表示,则没有读权限。
  • 第 2、5、8 位表示写权限,如果用"w"字符表示,则有写权限,如果用"-"字符表示没有写权限。
  • 第 3、6、9 位表示可执行权限,如果用"x"字符表示,则有执行权限,如果用"-"字符表示,则没有执行权限。

# 1.2.1. Linux 文件属主和属组

$ ls -l
+total 64
+dr-xr-xr-x   2 root root 4096 Dec 14  2012 bin
+dr-xr-xr-x   4 root root 4096 Apr 19  2012 boot
+
  • 对于文件来说,它都有一个特定的拥有者,也就是对该文件具有所有权的用户。
  • 同时,在 Linux 系统中,用户是按组分类的,一个用户属于一个或多个组。
  • 文件拥有者以外的用户又可以分为文件拥有者的同组用户和其他用户。
  • 因此,Linux 系统按文件拥有者、文件拥有者同组用户和其他用户来规定了不同的文件访问权限。
  • 在以上实例中,bin 文件是一个目录文件,属主和属组都为 root,属主有可读、可写、可执行的权限;与属主同组的其他用户有可读和可执行的权限;其他用户也有可读和可执行的权限。

# 2. Linux 文件目录管理要点

# 2.1. 目录管理

  • 切换目录 - 使用 cd
  • 查看目录信息 - 使用 ls
  • 显示当前目录的绝对路径 - 使用 pwd
  • 树状显示目录的内容 - 使用 tree
  • 创建目录 - 使用 mkdir
  • 删除目录 - 使用 rmdir

# 2.2. 文件管理

  • 创建空文件 - 使用 touch
  • 为文件创建连接 - 使用 ln
  • 批量重命名 - 使用 rename
  • 显示文件的详细信息 - 使用 stat
  • 探测文件类型 - 使用 file
  • 设置文件或目录的权限 - 使用 chmod
  • 设置文件或目录的拥有者或所属群组 - 使用 chown
  • 查找文件或目录 - 使用 locate
  • 在指定目录下查找文件 - 使用 find
  • 查找命令的绝对路径 - 使用 which
  • 查找命令的程序、源代码等相关文件 - 使用 whereis

# 2.3. 文件和目录通用管理

  • 复制文件或目录 - 使用 cp
  • 复制文件或目录到远程服务器 - 使用 scp
  • 移动文件或目录 - 使用 mv
  • 删除文件或目录 - 使用 rm

# 3. 命令常见用法

# 3.1. cd

cd 命令用来切换工作目录。

参考:http://man.linuxde.net/cd

示例:

cd          # 切换到用户主目录
+cd ~        # 切换到用户主目录
+cd -        # 切换到上一个工作目录
+cd ..       # 切换到上级目录
+cd ../..    # 切换到上两级目录
+

# 3.2. ls

ls 命令用来显示目录信息。

参考:http://man.linuxde.net/ls

示例:

ls        # 列出当前目录可见文件
+ls -l     # 列出当前目录可见文件详细信息
+ls -la    # 列出所有文件(包括隐藏)的详细信息
+ls -lh    # 列出详细信息并以可读大小显示文件大小
+ls -lt    # 按时间列出文件和文件夹详细信息
+ls -ltr   # 按修改时间列出文件和文件夹详细信息
+ls --color=auto     # 列出文件并标记颜色分类
+

# 3.3. pwd

pwd 命令用来显示当前目录的绝对路径。

参考:http://man.linuxde.net/pwd

# 3.4. mkdir

mkdir 命令用来创建目录。

参考:http://man.linuxde.net/mkdir

示例:

# 在当前目录中创建 zp 和 zp 的子目录 test
+mkdir -p zp/test
+
+# 在当前目录中创建 zp 和 zp 的子目录 test;权限设置为文件主可读、写、执行,同组用户可读和执行,其他用户无权访问
+mkdir -p -m 750 zp/test
+

# 3.5. rmdir

rmdir 命令用来删除空目录。

参考:http://man.linuxde.net/rmdir

示例:

# 删除子目录 test 和其父目录 zp
+rmdir -p zp/test
+

# 3.6. tree

tree 命令以树状显示目录的内。

参考:http://man.linuxde.net/tree

示例:

# 列出目录 /private 第一级文件名
+tree /private -L 1
+/private/
+├── etc
+├── tftpboot
+├── tmp
+└── var
+
+# 忽略文件夹
+tree -I node_modules            # 忽略当前目录文件夹 node_modules
+tree -P node_modules            # 列出当前目录文件夹 node_modules 的目录结构
+tree -P node_modules -L 2       # 显示目录 node_modules 两层的目录树结构
+tree -L 2 > /home/www/tree.txt  # 当前目录结果存到 tree.txt 文件中
+
+# 忽略多个文件夹
+tree -I 'node_modules|icon|font' -L 2
+

# 3.7. touch

touch 命令有两个功能:一是用于把已存在文件的时间标签更新为系统当前的时间(默认方式),它们的数据将原封不动地保留下来;二是用来创建空文件。

参考:http://man.linuxde.net/touch

示例:

touch ex2
+

# 3.8. ln

ln 命令用来为文件创建连接,连接类型分为硬连接和符号连接两种,默认的连接类型是硬连接。如果要创建符号连接必须使用"-s"选项。

🔔 注意:符号链接文件不是一个独立的文件,它的许多属性依赖于源文件,所以给符号链接文件设置存取权限是没有意义的。

参考:http://man.linuxde.net/ln

示例:

# 将目录 /usr/mengqc/mub1 下的文件 m2.c 链接到目录 /usr/liu 下的文件 a2.c
+cd /usr/mengqc
+ln /mub1/m2.c /usr/liu/a2.c
+
+# 在目录 /usr/liu 下建立一个符号链接文件 abc,使它指向目录 /usr/mengqc/mub1
+# 执行该命令后,/usr/mengqc/mub1 代表的路径将存放在名为 /usr/liu/abc 的文件中
+ln -s /usr/mengqc/mub1 /usr/liu/abc
+

# 3.9. rename

rename 命令用字符串替换的方式批量重命名。

参考:http://man.linuxde.net/rename

示例:

# 将 main1.c 重命名为 main.c
+rename main1.c main.c main1.c
+
+rename "s/AA/aa/" *             # 把文件名中的 AA 替换成 aa
+rename "s//.html//.php/" *      # 把 .html 后缀的改成 .php 后缀
+rename "s/$//.txt/" *           # 把所有的文件名都以 txt 结尾
+rename "s//.txt//" *            # 把所有以 .txt 结尾的文件名的.txt 删掉
+

# 3.10. stat

stat 命令用于显示文件的状态信息。stat 命令的输出信息比 ls 命令的输出信息要更详细。

参考:http://man.linuxde.net/stat

示例:

stat myfile
+

# 3.11. file

file 命令用来探测给定文件的类型。file 命令对文件的检查分为文件系统、魔法幻数检查和语言检查 3 个过程。

参考:http://man.linuxde.net/file

示例:

file install.log          # 显示文件类型
+file -b install.log       # 不显示文件名称
+file -i install.log       # 显示 MIME 类型
+file -L /var/spool/mail   # 显示符号链接的文件类型
+

# 3.12. chmod

chmod 命令用来变更文件或目录的权限。在 UNIX 系统家族里,文件或目录权限的控制分别以读取、写入、执行 3 种一般权限来区分,另有 3 种特殊权限可供运用。用户可以使用 chmod 指令去变更文件与目录的权限,设置方式采用文字或数字代号皆可。符号连接的权限无法变更,如果用户对符号连接修改权限,其改变会作用在被连接的原始文件。

参考:http://man.linuxde.net/chmod

知识扩展:

Linux 用 户分为:拥有者、组群(Group)、其他(other),Linux 系统中,预设的情況下,系统中所有的帐号与一般身份使用者,以及 root 的相关信 息, 都是记录在/etc/passwd文件中。每个人的密码则是记录在/etc/shadow文件下。 此外,所有的组群名称记录在/etc/group內!

linux 文件的用户权限的分析图

  -rw-r--r--   1 user  staff   651 Oct 12 12:53 .gitmodules
+# ↑╰┬╯╰┬╯╰┬╯
+# ┆ ┆  ┆  ╰┈ 0 其他人
+# ┆ ┆  ╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ g 属组
+# ┆ ╰┈┈┈┈ u 属组
+# ╰┈┈ 第一个字母 `d` 代表目录,`-` 代表普通文件
+

例:rwx   rw-  r--

r=读取属性  //值= 4
+w=写入属性  //值= 2
+x=执行属性  //值= 1

示例:

chmod u+x,g+w f01  # 为文件f01设置自己可以执行,组员可以写入的权限
+chmod u=rwx,g=rw,o=r f01
+chmod 764 f01
+chmod a+x f01      # 对文件f01的u,g,o都设置可执行属性
+
+# 将/home/wwwroot/里的所有文件和文件夹设置为755权限
+chmod -R  755 /home/wwwroot/*
+

# 3.13. chown

chown 命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组。用户可以是用户或者是用户 D,用户组可以是组名或组 id。文件名可以使由空格分开的文件列表,在文件名中可以包含通配符。

只有文件拥有者和超级用户才可以便用该命令。

参考:http://man.linuxde.net/chown

示例:

# 将目录/usr/meng及其下面的所有文件、子目录的文件主改成 liu
+chown -R liu /usr/meng
+

# 3.14. locate

locate 命令和 slocate 命令都用来查找文件或目录。

locate 命令其实是 find -name 的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库/var/lib/locatedb,这个数据库中含有本地所有文件信息。Linux 系统自动创建这个数据库,并且每天自动更新一次,所以使用 locate 命令查不到最新变动过的文件。为了避免这种情况,可以在使用 locate 之前,先使用 updatedb 命令,手动更新数据库。

参考:http://man.linuxde.net/locate_slocate

示例:

locate pwd      # 查找和 pwd 相关的所有文件
+locate /etc/sh  # 搜索 etc 目录下所有以 sh 开头的文件
+

# 3.15. find

find 命令用来在指定目录下查找文件。任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则 find 命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。

参考:http://man.linuxde.net/find

# 当前目录搜索所有文件,文件内容 包含 “140.206.111.111” 的内容
+find . -type f -name "*" | xargs grep "140.206.111.111"
+
+# 列出当前目录及子目录下所有文件和文件夹
+find .
+
+# 在 /home 目录下查找以 .txt 结尾的文件名
+find /home -name "*.txt"
+# 同上,但忽略大小写
+find /home -iname "*.txt"
+
+# 当前目录及子目录下查找所有以 .txt 和 .pdf 结尾的文件
+find . -name "*.txt" -o -name "*.pdf"
+
+# 匹配文件路径或者文件
+find /usr/ -path "*local*"
+
+# 基于正则表达式匹配文件路径
+find . -regex ".*\(\.txt\|\.pdf\)$"
+# 同上,但忽略大小写
+find . -iregex ".*\(\.txt\|\.pdf\)$"
+
+# 找出 /home 下不是以 .txt 结尾的文件
+find /home ! -name "*.txt"
+

# 3.16. cp

cp 命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录。它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下。cp 命令还支持同时复制多个文件,当一次复制多个文件时,目标文件参数必须是一个已经存在的目录,否则将出现错误。

参考:http://man.linuxde.net/cp

示例:

# 3.16.1. 参数

  • 源文件:制定源文件列表。默认情况下,cp 命令不能复制目录,如果要复制目录,则必须使用-R选项;
  • 目标文件:指定目标文件。当“源文件”为多个文件时,要求“目标文件”为指定的目录。

示例:

# 将文件 file 复制到目录 /usr/men/tmp 下,并改名为 file1
+cp file /usr/men/tmp/file1
+
+# 将目录 /usr/men下的所有文件及其子目录复制到目录 /usr/zh 中
+cp -r /usr/men /usr/zh
+
+# 强行将 /usr/men下的所有文件复制到目录 /usr/zh 中,无论是否有文件重复
+cp -rf /usr/men/* /usr/zh
+
+# 将目录 /usr/men 中的以 m 打头的所有 .c 文件复制到目录 /usr/zh 中
+cp -i /usr/men m*.c /usr/zh
+

# 3.17. scp

scp 命令用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然 rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。

示例:

# 拷贝文件到远程服务器的指定目录
+scp <file> <user>@<ip>:<url>
+scp test.txt root@192.168.0.1:/opt
+
+# 拷贝目录到远程服务器的指定目录
+scp -r <folder> <user>@<ip>:<url>
+scp -r test root@192.168.0.1:/opt
+

# 3.17.1. 免密码传输

(1)生成 ssh 公私钥对

ssh-keygen -t rsa
+

(2)将服务器 A 的 \~/.ssh/id_rsa.pub 文件内容复制到服务器 B 的 \~/.ssh/authorized_keys 文件中。

# 服务器 A 上执行以下命令
+scp ~/.ssh/id_rsa.pub root@192.168.0.2:~/.ssh/id_rsa.pub.tmp
+
+# 服务器 B 上执行以下命令
+cat ~/.ssh/id_rsa.pub.tmp >> ~/.ssh/authorized_keys
+rm ~/.ssh/id_rsa.pub.tmp
+

# 3.18. mv

mv 命令用来对文件或目录重新命名,或者将文件从一个目录移到另一个目录中。source 表示源文件或目录,target 表示目标文件或目录。如果将一个文件移到一个已经存在的目标文件中,则目标文件的内容将被覆盖。

参考:http://man.linuxde.net/mv

示例:

mv file1.txt /home/office/                      # 移动单个文件
+mv file2.txt file3.txt file4.txt /home/office/  # 移动多个文件
+mv *.txt /home/office/                          # 移动所有 txt 文件
+mv dir1/ /home/office/                          # 移动目录
+mv /usr/men/* .                                 # 将指定目录中的所有文件移到当前目录中
+
+mv file1.txt file2.txt          # 重命名文件
+mv dir1/ dir2/                  # 重命名目录
+mv -v *.txt /home/office        # 打印移动信息
+mv -i file1.txt /home/office    # 提示是否覆盖文件
+
+mv -uv *.txt /home/office       # 源文件比目标文件新时才执行更新
+mv -vn *.txt /home/office       # 不要覆盖任何已存在的文件
+mv -f *.txt /home/office        # 无条件覆盖已经存在的文件
+mv -bv *.txt /home/office       # 复制时创建备份
+

# 3.19. rm

rm 命令可以删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉。对于链接文件,只是删除整个链接文件,而原有文件保持不变。

参考:http://man.linuxde.net/rm

rm test.txt               # 删除文件
+rm -i test.txt test2.txt  # 交互式删除文件
+rm -r *                   # 删除当前目录下的所有文件和目录
+rm -r testdir             # 删除目录下的所有文件和目录
+rm -rf testdir            # 强制删除目录下的所有文件和目录
+rm -v testdir             # 显示当前删除操作的详情
+
+ + + diff --git a/linux/cli/linux-cli-file-compress.html b/linux/cli/linux-cli-file-compress.html new file mode 100644 index 0000000..b2fcb8b --- /dev/null +++ b/linux/cli/linux-cli-file-compress.html @@ -0,0 +1,61 @@ + + + + + + Linux 文件压缩和解压 | LINUX-TUTORIAL + + + + + + + + +

# Linux 文件压缩和解压

关键词:tar, gzip, zip, unzip

# 1. Linux 文件压缩和解压要点

  • 压缩和解压 tar 文件 - 使用 tar
  • 压缩和解压 gz 文件 - 使用 gzip
  • 压缩和解压 zip 文件 - 分别使用 zipunzip

# 2. 命令常见用法

# 2.1. tar

tar 命令可以为 linux 的文件和目录创建档案。利用 tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件。tar 最初被用来在磁带上创建档案,现在,用户可以在任何设备上创建档案。利用 tar 命令,可以把一大堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的。

参考:http://man.linuxde.net/tar

示例:

tar -cvf log.tar log2012.log            # 仅打包,不压缩
+tar -zcvf log.tar.gz log2012.log        # 打包后,以 gzip 压缩
+tar -jcvf log.tar.bz2 log2012.log       # 打包后,以 bzip2 压缩
+
+tar -ztvf log.tar.gz                    # 查阅上述 tar 包内有哪些文件
+tar -zxvf log.tar.gz                    # 将 tar 包解压缩
+tar -zxvf log30.tar.gz log2013.log      # 只将 tar 内的部分文件解压出来
+

# 2.2. gzip

gzip 命令用来压缩文件。gzip 是个使用广泛的压缩程序,文件经它压缩过后,其名称后面会多出“.gz”扩展名。

gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。gzip 不仅可以用来压缩大的、较少使用的文件以节省磁盘空间,还可以和 tar 命令一起构成 Linux 操作系统中比较流行的压缩文件格式。据统计,gzip 命令对文本文件有 60%~ 70%的压缩率。减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。

参考:http://man.linuxde.net/gzip

示例:

gzip * # 将所有文件压缩成 .gz 文件
+gzip -l * # 详细显示压缩文件的信息,并不解压
+gzip -dv * # 解压上例中的所有压缩文件,并列出详细的信息
+gzip -r log.tar     # 压缩一个 tar 备份文件,此时压缩文件的扩展名为.tar.gz
+gzip -rv test/      # 递归的压缩目录
+gzip -dr test/      # 递归地解压目录
+

# 2.3. zip

zip 命令可以用来解压缩文件,或者对文件进行打包操作。zip 是个使用广泛的压缩程序,文件经它压缩后会另外产生具有“.zip”扩展名的压缩文件。

参考:http://man.linuxde.net/zip

示例:

# 将 /home/Blinux/html/ 这个目录下所有文件和文件夹打包为当前目录下的 html.zip
+zip -q -r html.zip /home/Blinux/html
+

# 2.4. unzip

unzip 命令用于解压缩由 zip 命令压缩的“.zip”压缩包。

参考:http://man.linuxde.net/unzip

示例:

unzip test.zip              # 解压 zip 文件
+unzip -n test.zip -d /tmp/  # 在指定目录下解压缩
+unzip -o test.zip -d /tmp/  # 在指定目录下解压缩,如果有相同文件存在则覆盖
+unzip -v test.zip           # 查看压缩文件目录,但不解压
+
+ + + diff --git a/linux/cli/linux-cli-file.html b/linux/cli/linux-cli-file.html new file mode 100644 index 0000000..c6c6c1c --- /dev/null +++ b/linux/cli/linux-cli-file.html @@ -0,0 +1,97 @@ + + + + + + Linux 文件内容查看编辑 | LINUX-TUTORIAL + + + + + + + + +

# Linux 文件内容查看编辑

关键词:cat, head, tail, more, less, sed, vi, grep

# 1. Linux 文件内容查看编辑要点

  • 连接文件并打印到标准输出设备 - 使用 cat
  • 显示指定文件的开头若干行 - 使用 head
  • 显示指定文件的末尾若干行,常用于实时打印日志文件内容 - 使用 tail
  • 显示文件内容,每次显示一屏 - 使用 more
  • 显示文件内容,每次显示一屏 - 使用 less
  • 自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等 - 使用 sed
  • 文本编辑器 - 使用 vi
  • 使用正则表达式搜索文本,并把匹配的行打印出来 - 使用 grep

# 2. 命令常见用法

# 2.1. cat

cat 命令用于连接文件并打印到标准输出设备上。

参考:http://man.linuxde.net/cat

示例:

cat m1              # 在屏幕上显示文件 ml 的内容
+cat m1 m2           # 同时显示文件 ml 和 m2 的内容
+cat m1 m2 > file    # 将文件 ml 和 m2 合并后放入文件 file 中
+

# 2.2. head

head 命令用于显示文件的开头内容。在默认情况下,head 命令显示文件的头部 10 行内容。

参考:http://man.linuxde.net/head

# 2.3. tail

tail 命令用于显示文件的尾部内容。在默认情况下,tail 命令显示文件的尾部 10 行内容。如果给定的文件不止一个,则在显示的每个文件前面加一个文件名标题。如果没有指定文件或者文件名为“-”,则读取标准输入。

参考:http://man.linuxde.net/tail

示例:

tail file           # 显示文件file的最后10行
+tail -n +20 file    # 显示文件file的内容,从第20行至文件末尾
+tail -c 10 file     # 显示文件file的最后10个字符
+

# 2.4. more

more 命令是一个基于 vi 编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持 vi 中的关键字定位操作。more 名单中内置了若干快捷键,常用的有 H(获得帮助信息),Enter(向下翻滚一行),空格(向下滚动一屏),Q(退出命令)。

该命令一次显示一屏文本,满屏后停下来,并且在屏幕的底部出现一个提示信息,给出至今己显示的该文件的百分比:--More--(XX%)可以用下列不同的方法对提示做出回答:

  • 按 Space 键:显示文本的下一屏内容。
  • 按 Enier 键:只显示文本的下一行内容。
  • 按斜线符|:接着输入一个模式,可以在文本中寻找下一个相匹配的模式。
  • 按 H 键:显示帮助屏,该屏上有相关的帮助信息。
  • 按 B 键:显示上一屏内容。
  • 按 Q 键:退出 rnore 命令。

参考:http://man.linuxde.net/more

示例:

# 显示文件 file 的内容,但在显示之前先清屏,并且在屏幕的最下方显示完核的百分比。
+more -dc file
+
+# 显示文件 file 的内容,每 10 行显示一次,而且在显示之前先清屏。
+more -c -10 file
+

# 2.5. less

less 命令的作用与 more 十分相似,都可以用来浏览文字档案的内容,不同的是 less 命令允许用户向前或向后浏览文件,而 more 命令只能向前浏览。用 less 命令显示文件时,用 PageUp 键向上翻页,用 PageDown 键向下翻页。要退出 less 程序,应按 Q 键。

示例:

less /var/log/shadowsocks.log
+

# 2.6. sed

sed 是一种流编辑器,它是文本处理工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed 主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

参考:http://man.linuxde.net/sed

示例:

# 替换文本中的字符串
+sed 's/book/books/' file
+
+# -n 选项 和 p 命令 一起使用表示只打印那些发生替换的行
+sed -n 's/test/TEST/p' file
+
+# 直接编辑文件选项 -i ,会匹配 file 文件中每一行的第一个 book 替换为 books
+sed -i 's/book/books/g' file
+
+# 使用后缀 /g 标记会替换每一行中的所有匹配
+sed 's/book/books/g' file
+
+# 删除空白行
+sed '/^$/d' file
+
+# 删除文件的第2行
+sed '2d' file
+
+# 删除文件的第2行到末尾所有行
+sed '2,$d' file
+
+# 删除文件最后一行
+sed '$d' file
+
+# 删除文件中所有开头是test的行
+sed '/^test/'d file
+

# 2.7. vi

vi 命令是 UNIX 操作系统和类 UNIX 操作系统中最通用的全屏幕纯文本编辑器。Linux 中的 vi 编辑器叫 vim,它是 vi 的增强版(vi Improved),与 vi 编辑器完全兼容,而且实现了很多增强功能。

参考:http://man.linuxde.net/vi

引申阅读:Vim 入门指南 (opens new window)

# 2.8. grep

grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

参考:http://man.linuxde.net/grep

示例:

# 在多级目录中对文本递归搜索(程序员搜代码的最爱):
+$ grep "class" . -R -n
+
+# 忽略匹配样式中的字符大小写
+$ echo "hello world" | grep -i "HELLO"
+
+# 匹配多个模式:
+$ grep -e "class" -e "vitural" file
+
+# 只在目录中所有的.php和.html文件中递归搜索字符"main()"
+$ grep "main()" . -r --include *.{php,html}
+
+# 在搜索结果中排除所有README文件
+$ grep "main()" . -r --exclude "README"
+
+# 在搜索结果中排除filelist文件列表里的文件
+$ grep "main()" . -r --exclude-from filelist
+

# 3. 参考资料

+ + + diff --git a/linux/cli/linux-cli-hardware.html b/linux/cli/linux-cli-hardware.html new file mode 100644 index 0000000..25a3353 --- /dev/null +++ b/linux/cli/linux-cli-hardware.html @@ -0,0 +1,134 @@ + + + + + + Linux 硬件管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 硬件管理

关键词:df, du, top, free, iotop

# 1. Linux 硬件管理要点

  • 查看磁盘空间 - 使用 df
  • 查看文件或目录的磁盘空间 - 使用 du
  • 实时查看系统整体运行状态(如:CPU、内存) - 使用 top
  • 查看已使用和未使用的内存 - 使用 free
  • 查看磁盘 I/O 使用状况 - 使用 iotop

# 2. 命令常见用法

# 2.1. df

df 命令用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为 KB。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。

参考:http://man.linuxde.net/df

示例:

# 查看系统磁盘设备,默认是 KB 为单位
+[root@LinServ-1 ~]# df
+文件系统               1K-块        已用     可用 已用% 挂载点
+/dev/sda2            146294492  28244432 110498708  21% /
+/dev/sda1              1019208     62360    904240   7% /boot
+tmpfs                  1032204         0   1032204   0% /dev/shm
+/dev/sdb1            2884284108 218826068 2518944764   8% /data1
+
+# 使用 -h 选项以 KB 以上的单位来显示,可读性高
+[root@LinServ-1 ~]# df -h
+文件系统              容量  已用 可用 已用% 挂载点
+/dev/sda2             140G   27G  106G  21% /
+/dev/sda1             996M   61M  884M   7% /boot
+tmpfs                1009M     0 1009M   0% /dev/shm
+/dev/sdb1             2.7T  209G  2.4T   8% /data1
+
+# 查看全部文件系统
+[root@LinServ-1 ~]# df -a
+文件系统               1K-块        已用     可用 已用% 挂载点
+/dev/sda2            146294492  28244432 110498708  21% /
+proc                         0         0         0   -  /proc
+sysfs                        0         0         0   -  /sys
+devpts                       0         0         0   -  /dev/pts
+/dev/sda1              1019208     62360    904240   7% /boot
+tmpfs                  1032204         0   1032204   0% /dev/shm
+/dev/sdb1            2884284108 218826068 2518944764   8% /data1
+none                         0         0         0   -  /proc/sys/fs/binfmt_misc
+

# 2.2. du

du 命令也是查看使用空间的,但是与 df 命令不同的是:du 命令是对文件和目录磁盘使用的空间的查看,还是和 df 命令有一些区别的。

参考:http://man.linuxde.net/du

示例:

# 显示目录或者文件所占空间
+root@localhost [test]# du
+608 ./test6
+308 ./test4
+4 ./scf/lib
+4 ./scf/service/deploy/product
+4 ./scf/service/deploy/info
+12 ./scf/service/deploy
+16 ./scf/service
+4 ./scf/doc
+4 ./scf/bin
+32 ./scf
+8 ./test3
+1288 .
+
+# 显示指定文件所占空间
+[root@localhost test]# du log2012.log
+300 log2012.log
+
+# 查看指定目录的所占空间
+[root@localhost test]# du scf
+4 scf/lib
+4 scf/service/deploy/product
+4 scf/service/deploy/info
+12 scf/service/deploy
+16 scf/service
+4 scf/doc
+4 scf/bin
+32 scf
+
+# 显示多个文件所占空间
+[root@localhost test]# du log30.tar.gz log31.tar.gz
+4 log30.tar.gz
+4 log31.tar.gz
+
+# 只显示总和的大小
+[root@localhost test]# du -s
+1288 .
+
+[root@localhost test]# du -s scf
+32 scf
+

# 2.3. top

top 命令可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。

参考:http://man.linuxde.net/top

# 2.4. free

free 命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区。

参考:http://man.linuxde.net/free

示例:

free -t    # 以总和的形式显示内存的使用信息
+free -s 10 # 周期性的查询内存使用信息,每10s 执行一次命令
+
+# 显示内存使用情况
+
+free -m
+             total       used       free     shared    buffers     cached
+Mem:          2016       1973         42          0        163       1497
+-/+ buffers/cache:        312       1703
+Swap:         4094          0       4094
+

# 2.5. iotop

iotop 命令是一个用来监视磁盘 I/O 使用状况的 top 类工具。iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息。Linux 下的 IO 统计工具如 iostat,nmon 等大多数是只能统计到 per 设备的读写情况,如果你想知道每个进程是如何使用 IO 的就比较麻烦,使用 iotop 命令可以很方便的查看。

参考:http://man.linuxde.net/iotop

示例:

Total DISK read:       0.00 B/s | Total DISK write:       0.00 B/s
+  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    command
+    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % init [3]
+    2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
+    3 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
+    4 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
+    5 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/0]
+    6 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/1]
+    7 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/1]
+    8 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [watchdog/1]
+    9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [events/0]
+   10 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [events/1]
+   11 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [khelper]
+2572 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [bluetooth]
+
+ + + diff --git a/linux/cli/linux-cli-help.html b/linux/cli/linux-cli-help.html new file mode 100644 index 0000000..e577636 --- /dev/null +++ b/linux/cli/linux-cli-help.html @@ -0,0 +1,63 @@ + + + + + + 查看 Linux 命令帮助信息 | LINUX-TUTORIAL + + + + + + + + +

# 查看 Linux 命令帮助信息

Linux 中有非常多的命令,想全部背下来是很困难的事。所以,我认为学习 Linux 的第一步,就是了解如何快速检索命令说明。

关键词:help, whatis, info, which, whereis, man

# 1. 查看 Linux 命令帮助信息的要点

  • 查看 Shell 内部命令的帮助信息 - 使用 help
  • 查看命令的简要说明 - 使用 whatis
  • 查看命令的详细说明 - 使用 info
  • 查看命令的位置 - 使用 which
  • 定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径 - 使用 whereis
  • 查看命令的帮助手册(包含说明、用法等信息) - 使用 man
  • 只记得部分命令关键字 - 使用 man -k

注:推荐一些 Linux 命令中文手册:

# 2. 命令常见用法

# 2.1. help

help 命令用于查看 Shell 内部命令的帮助信息。而对于外部命令的帮助信息只能使用 man 或者 info 命令查看。

参考:http://man.linuxde.net/help

# 2.2. whatis

whatis 用于查询一个命令执行什么功能。

参考:http://man.linuxde.net/whatis

示例:

# 查看 man 命令的简要说明
+$ whatis man
+
+# 查看以 loca 开拓的命令的简要说明
+$ whatis -w "loca*"
+

# 2.3. info

info 是 Linux 下 info 格式的帮助指令。

参考:http://man.linuxde.net/info

示例:

# 查看 man 命令的详细说明
+$ info man
+

# 2.4. which

which 命令用于查找并显示给定命令的绝对路径,环境变量 PATH 中保存了查找命令时需要遍历的目录。which 指令会在环境变量$PATH 设置的目录里查找符合条件的文件。也就是说,使用 which 命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。

参考:http://man.linuxde.net/which

示例:

which pwd # 查找命令的路径
+

说明:which 是根据使用者所配置的 PATH 变量内的目录去搜寻可运行档的!所以,不同的 PATH 配置内容所找到的命令当然不一样的!

[root@localhost ~]# which cd
+cd: shell built-in command
+

cd 这个常用的命令竟然找不到啊!为什么呢?这是因为 cd 是 bash 内建的命令!但是 which 默认是找 PATH 内所规范的目录,所以当然一定找不到的!

# 2.5. whereis

whereis 命令用来定位指令的二进制程序、源代码文件和 man 手册页等相关文件的路径。

whereis 命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man 说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。

参考:http://man.linuxde.net/whereis

示例:

whereis git # 将相关的文件都查找出来
+

# 2.6. man

man 命令是 Linux 下的帮助指令,通过 man 指令可以查看 Linux 中的指令帮助、配置文件帮助和编程帮助等信息。

参考:http://man.linuxde.net/man

示例:

$ man date # 查看 date 命令的帮助手册
+$ man 3 printf # 查看 printf 命令的帮助手册中的第 3 类
+$ man -k keyword # 根据命令中部分关键字来查询命令
+

# 2.6.1. man 要点

在 man 的帮助手册中,可以使用 page up 和 page down 来上下翻页。

man 的帮助手册中,将帮助文档分为了 9 个类别,对于有的关键字可能存在多个类别中, 我们就需要指定特定的类别来查看;(一般我们查询 bash 命令,归类在 1 类中)。

man 页面的分类(常用的是分类 1 和分类 3):

  1. 可执行程序或 shell 命令
  2. 系统调用(内核提供的函数)
  3. 库调用(程序库中的函数)
  4. 特殊文件(通常位于 /dev)
  5. 文件格式和规范,如 /etc/passwd
  6. 游戏
  7. 杂项(包括宏包和规范,如 man(7),groff(7))
  8. 系统管理命令(通常只针对 root 用户)
  9. 内核例程 [非标准]

前面说到使用 whatis 会显示命令所在的具体的文档类别,我们学习如何使用它

$ whatis printf
+printf (1) - format and print data
+printf (1p) - write formatted output
+printf (3) - formatted output conversion
+printf (3p) - print formatted output
+printf [builtins](1) - bash built-in commands, see bash(1)
+

我们看到 printf 在分类 1 和分类 3 中都有;分类 1 中的页面是命令操作及可执行文件的帮助;而 3 是常用函数库说明;如果我们想看的是 C 语言中 printf 的用法,可以指定查看分类 3 的帮助:

$ man 3 printf
+

# 3. 参考资料

https://linuxtools-rst.readthedocs.io/zh_CN/latest/base/01_use_man.html

+ + + diff --git a/linux/cli/linux-cli-net.html b/linux/cli/linux-cli-net.html new file mode 100644 index 0000000..7c4e194 --- /dev/null +++ b/linux/cli/linux-cli-net.html @@ -0,0 +1,224 @@ + + + + + + Linux 网络管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 网络管理

关键词:curl, wget, telnet, ip, hostname, ifconfig, route, ssh, ssh-keygen, firewalld, iptables, host, nslookup, nc/netcat, ping, traceroute, netstat

# 1. Linux 网络应用要点

  • 下载文件 - 使用 curlwget
  • telnet 方式登录远程主机,对远程主机进行管理 - 使用 telnet
  • 查看或操纵 Linux 主机的路由、网络设备、策略路由和隧道 - 使用 ip
  • 查看和设置系统的主机名 - 使用 hostname
  • 查看和配置 Linux 内核中网络接口的网络参数 - 使用 ifconfig
  • 查看和设置 Linux 内核中的网络路由表 - 使用 route
  • ssh 方式连接远程主机 - 使用 ssh
  • 为 ssh 生成、管理和转换认证密钥 - 使用 ssh-keygen
  • 查看、设置防火墙(Centos7),使用 firewalld
  • 查看、设置防火墙(Centos7 以前),使用 iptables
  • 查看域名信息 - 使用 host, nslookup
  • 设置路由 - 使用 nc/netcat
  • 测试主机之间网络是否连通 - 使用 ping
  • 追踪数据在网络上的传输时的全部路径 - 使用 traceroute
  • 查看当前工作的端口信息 - 使用 netstat

# 2. 命令常见用法

# 2.1. curl

curl 命令是一个利用 URL 规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称 curl 为下载工具。作为一款强力工具,curl 支持包括 HTTP、HTTPS、ftp 等众多协议,还支持 POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。做网页处理流程和数据检索自动化,curl 可以祝一臂之力。

参考:http://man.linuxde.net/curl

示例:

# 下载文件
+$ curl http://man.linuxde.net/text.iso --silent
+
+# 下载文件,指定下载路径,并查看进度
+$ curl http://man.linuxde.net/test.iso -o filename.iso --progress
+########################################## 100.0%
+

# 2.2. wget

wget 命令用来从指定的 URL 下载文件。

参考:http://man.linuxde.net/wget

示例:

# 使用 wget 下载单个文件
+$ wget http://www.linuxde.net/testfile.zip
+

# 2.3. telnet

telnet 命令用于登录远程主机,对远程主机进行管理。

参考:http://man.linuxde.net/telnet

示例:

telnet 192.168.2.10
+Trying 192.168.2.10...
+Connected to 192.168.2.10 (192.168.2.10).
+Escape character is '^]'.
+
+    localhost (Linux release 2.6.18-274.18.1.el5 #1 SMP Thu Feb 9 12:45:44 EST 2012) (1)
+
+login: root
+Password:
+Login incorrect
+

# 2.4. ip

ip 命令用来查看或操纵 Linux 主机的路由、网络设备、策略路由和隧道,是 Linux 下较新的功能强大的网络配置工具。

参考:http://man.linuxde.net/ip

示例:

$ ip link show                     # 查看网络接口信息
+$ ip link set eth0 upi             # 开启网卡
+$ ip link set eth0 down            # 关闭网卡
+$ ip link set eth0 promisc on      # 开启网卡的混合模式
+$ ip link set eth0 promisc offi    # 关闭网卡的混个模式
+$ ip link set eth0 txqueuelen 1200 # 设置网卡队列长度
+$ ip link set eth0 mtu 1400        # 设置网卡最大传输单元
+$ ip addr show     # 查看网卡IP信息
+$ ip addr add 192.168.0.1/24 dev eth0 # 设置eth0网卡IP地址192.168.0.1
+$ ip addr del 192.168.0.1/24 dev eth0 # 删除eth0网卡IP地址
+
+$ ip route show # 查看系统路由
+$ ip route add default via 192.168.1.254   # 设置系统默认路由
+$ ip route list                 # 查看路由信息
+$ ip route add 192.168.4.0/24  via  192.168.0.254 dev eth0 # 设置192.168.4.0网段的网关为192.168.0.254,数据走eth0接口
+$ ip route add default via  192.168.0.254  dev eth0        # 设置默认网关为192.168.0.254
+$ ip route del 192.168.4.0/24   # 删除192.168.4.0网段的网关
+$ ip route del default          # 删除默认路由
+$ ip route delete 192.168.1.0/24 dev eth0 # 删除路由
+

# 2.5. hostname

hostname 命令用于查看和设置系统的主机名称。环境变量 HOSTNAME 也保存了当前的主机名。在使用 hostname 命令设置主机名后,系统并不会永久保存新的主机名,重新启动机器之后还是原来的主机名。如果需要永久修改主机名,需要同时修改 /etc/hosts/etc/sysconfig/network 的相关内容。

参考:http://man.linuxde.net/hostname

示例:

$ hostname
+AY1307311912260196fcZ
+

# 2.6. ifconfig

ifconfig 命令被用于查看和配置 Linux 内核中网络接口的网络参数。用 ifconfig 命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。

参考:http://man.linuxde.net/ifconfig

示例:

# 查看网络设备信息(激活状态的)
+[root@localhost ~]# ifconfig
+eth0      Link encap:Ethernet  HWaddr 00:16:3E:00:1E:51
+          inet addr:10.160.7.81  Bcast:10.160.15.255  Mask:255.255.240.0
+          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
+          RX packets:61430830 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:88534 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:1000
+          RX bytes:3607197869 (3.3 GiB)  TX bytes:6115042 (5.8 MiB)
+
+lo        Link encap:Local Loopback
+          inet addr:127.0.0.1  Mask:255.0.0.0
+          UP LOOPBACK RUNNING  MTU:16436  Metric:1
+          RX packets:56103 errors:0 dropped:0 overruns:0 frame:0
+          TX packets:56103 errors:0 dropped:0 overruns:0 carrier:0
+          collisions:0 txqueuelen:0
+          RX bytes:5079451 (4.8 MiB)  TX bytes:5079451 (4.8 MiB)
+

# 2.7. route

route 命令用来查看和设置 Linux 内核中的网络路由表,route 命令设置的路由主要是静态路由。要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。

参考:http://man.linuxde.net/route

示例:

# 查看当前路由
+route
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
+112.124.12.0    *               255.255.252.0   U     0      0        0 eth1
+10.160.0.0      *               255.255.240.0   U     0      0        0 eth0
+192.168.0.0     10.160.15.247   255.255.0.0     UG    0      0        0 eth0
+172.16.0.0      10.160.15.247   255.240.0.0     UG    0      0        0 eth0
+10.0.0.0        10.160.15.247   255.0.0.0       UG    0      0        0 eth0
+default         112.124.15.247  0.0.0.0         UG    0      0        0 eth1
+
+route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0    # 添加网关/设置网关
+route add -net 224.0.0.0 netmask 240.0.0.0 reject      # 屏蔽一条路由
+route del -net 224.0.0.0 netmask 240.0.0.0             # 删除路由记录
+route add default gw 192.168.120.240                   # 添加默认网关
+route del default gw 192.168.120.240                   # 删除默认网关
+

# 2.8. ssh

ssh 命令是 openssh 套件中的客户端连接工具,可以给予 ssh 加密协议实现安全的远程登录服务器。

参考:http://man.linuxde.net/ssh

示例:

# ssh 用户名@远程服务器地址
+ssh user1@172.24.210.101
+# 指定端口
+ssh -p 2211 root@140.206.185.170
+

引申阅读:ssh 背后的故事 (opens new window)

# 2.9. ssh-keygen

ssh-keygen 命令用于为 ssh 生成、管理和转换认证密钥,它支持 RSA 和 DSA 两种认证密钥。

参考:http://man.linuxde.net/ssh-keygen

# 2.10. firewalld

firewalld 命令是 Linux 上的防火墙软件(Centos7 默认防火墙)。

参考:https://www.cnblogs.com/moxiaoan/p/5683743.html

# 2.10.1. firewalld 的基本使用

  • 启动 - systemctl start firewalld
  • 关闭 - systemctl stop firewalld
  • 查看状态 - systemctl status firewalld
  • 开机禁用 - systemctl disable firewalld
  • 开机启用 - systemctl enable firewalld

# 2.10.2. 使用 systemctl 管理 firewalld 服务

systemctl 是 CentOS7 的服务管理工具中主要的工具,它融合之前 service 和 chkconfig 的功能于一体。

  • 启动一个服务 - systemctl start firewalld.service
  • 关闭一个服务 - systemctl stop firewalld.service
  • 重启一个服务 - systemctl restart firewalld.service
  • 显示一个服务的状态 - systemctl status firewalld.service
  • 在开机时启用一个服务 - systemctl enable firewalld.service
  • 在开机时禁用一个服务 - systemctl disable firewalld.service
  • 查看服务是否开机启动 - systemctl is-enabled firewalld.service
  • 查看已启动的服务列表 - systemctl list-unit-files|grep enabled
  • 查看启动失败的服务列表 - systemctl --failed

# 2.10.3. 配置 firewalld-cmd

  • 查看版本 - firewall-cmd --version
  • 查看帮助 - firewall-cmd --help
  • 显示状态 - firewall-cmd --state
  • 查看所有打开的端口 - firewall-cmd --zone=public --list-ports
  • 更新防火墙规则 - firewall-cmd --reload
  • 查看区域信息: firewall-cmd --get-active-zones
  • 查看指定接口所属区域 - firewall-cmd --get-zone-of-interface=eth0
  • 拒绝所有包:firewall-cmd --panic-on
  • 取消拒绝状态 - firewall-cmd --panic-off
  • 查看是否拒绝 - firewall-cmd --query-panic

# 2.10.4. 在防火墙中开放一个端口

  • 添加(--permanent 永久生效,没有此参数重启后失效) - firewall-cmd --zone=public --add-port=80/tcp --permanent
  • 重新载入 - firewall-cmd --reload
  • 查看 - firewall-cmd --zone= public --query-port=80/tcp
  • 删除 - firewall-cmd --zone= public --remove-port=80/tcp --permanent

# 2.11. iptables

iptables 命令是 Linux 上常用的防火墙软件,是 netfilter 项目的一部分。可以直接配置,也可以通过许多前端和图形界面配置。

参考:http://man.linuxde.net/iptables

示例:

# 开放指定的端口
+iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT               #允许本地回环接口(即运行本机访问本机)
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT    #允许已建立的或相关连的通行
+iptables -A OUTPUT -j ACCEPT         #允许所有本机向外的访问
+iptables -A INPUT -p tcp --dport 22 -j ACCEPT    #允许访问22端口
+iptables -A INPUT -p tcp --dport 80 -j ACCEPT    #允许访问80端口
+iptables -A INPUT -p tcp --dport 21 -j ACCEPT    #允许ftp服务的21端口
+iptables -A INPUT -p tcp --dport 20 -j ACCEPT    #允许FTP服务的20端口
+iptables -A INPUT -j reject       #禁止其他未允许的规则访问
+iptables -A FORWARD -j REJECT     #禁止其他未允许的规则访问
+
+# 屏蔽IP
+iptables -I INPUT -s 123.45.6.7 -j DROP       #屏蔽单个IP的命令
+iptables -I INPUT -s 123.0.0.0/8 -j DROP      #封整个段即从123.0.0.1到123.255.255.254的命令
+iptables -I INPUT -s 124.45.0.0/16 -j DROP    #封IP段即从123.45.0.1到123.45.255.254的命令
+iptables -I INPUT -s 123.45.6.0/24 -j DROP    #封IP段即从123.45.6.1到123.45.6.254的命令是
+
+# 查看已添加的iptables规则
+iptables -L -n -v
+Chain INPUT (policy DROP 48106 packets, 2690K bytes)
+ pkts bytes target     prot opt in     out     source               destination
+ 5075  589K ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
+ 191K   90M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22
+1499K  133M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80
+4364K 6351M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
+ 6256  327K ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0
+
+Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
+ pkts bytes target     prot opt in     out     source               destination
+
+Chain OUTPUT (policy ACCEPT 3382K packets, 1819M bytes)
+ pkts bytes target     prot opt in     out     source               destination
+ 5075  589K ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0
+

# 2.12. host

host 命令是常用的分析域名查询工具,可以用来测试域名系统工作是否正常。

参考:http://man.linuxde.net/host

示例:

[root@localhost ~]# host www.jsdig.com
+www.jsdig.com is an alias for host.1.jsdig.com.
+host.1.jsdig.com has address 100.42.212.8
+
+[root@localhost ~]# host -a www.jsdig.com
+Trying "www.jsdig.com"
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34671
+;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;www.jsdig.com.               IN      ANY
+
+;; ANSWER SECTION:
+www.jsdig.com.        463     IN      CNAME   host.1.jsdig.com.
+
+Received 54 bytes from 202.96.104.15#53 in 0 ms
+

# 2.13. nslookup

nslookup 命令是常用域名查询工具,就是查 DNS 信息用的命令。

参考:http://man.linuxde.net/nslookup

示例:

[root@localhost ~]# nslookup www.jsdig.com
+Server:         202.96.104.15
+Address:        202.96.104.15#53
+
+Non-authoritative answer:
+www.jsdig.com canonical name = host.1.jsdig.com.
+Name:   host.1.jsdig.com
+Address: 100.42.212.8
+

# 2.14. nc/netcat

nc 命令是 netcat 命令的简称,都是用来设置路由器。

参考:http://man.linuxde.net/nc_netcat

示例:

# TCP 端口扫描
+[root@localhost ~]# nc -v -z -w2 192.168.0.3 1-100
+192.168.0.3: inverse host lookup failed: Unknown host
+(UNKNOWN) [192.168.0.3] 80 (http) open
+(UNKNOWN) [192.168.0.3] 23 (telnet) open
+(UNKNOWN) [192.168.0.3] 22 (ssh) open
+
+# UDP 端口扫描
+[root@localhost ~]# nc -u -z -w2 192.168.0.1 1-1000  # 扫描192.168.0.3 的端口 范围是 1-1000
+

# 2.15. ping

ping 命令用来测试主机之间网络的连通性。执行 ping 指令会使用 ICMP 传输协议,发出要求回应的信息,若远端主机的网络功能没有问题,就会回应该信息,因而得知该主机运作正常。

参考:http://man.linuxde.net/ping

示例:

[root@AY1307311912260196fcZ ~]# ping www.jsdig.com
+PING host.1.jsdig.com (100.42.212.8) 56(84) bytes of data.
+64 bytes from 100-42-212-8.static.webnx.com (100.42.212.8): icmp_seq=1 ttl=50 time=177 ms
+64 bytes from 100-42-212-8.static.webnx.com (100.42.212.8): icmp_seq=2 ttl=50 time=178 ms
+64 bytes from 100-42-212-8.static.webnx.com (100.42.212.8): icmp_seq=3 ttl=50 time=174 ms
+64 bytes from 100-42-212-8.static.webnx.com (100.42.212.8): icmp_seq=4 ttl=50 time=177 ms
+...按Ctrl+C结束
+
+--- host.1.jsdig.com ping statistics ---
+4 packets transmitted, 4 received, 0% packet loss, time 2998ms
+rtt min/avg/max/mdev = 174.068/176.916/178.182/1.683 ms
+

# 2.16. traceroute

traceroute 命令用于追踪数据包在网络上的传输时的全部路径,它默认发送的数据包大小是 40 字节。

参考:http://man.linuxde.net/traceroute

示例:

traceroute www.58.com
+traceroute to www.58.com (211.151.111.30), 30 hops max, 40 byte packets
+ 1  unknown (192.168.2.1)  3.453 ms  3.801 ms  3.937 ms
+ 2  221.6.45.33 (221.6.45.33)  7.768 ms  7.816 ms  7.840 ms
+ 3  221.6.0.233 (221.6.0.233)  13.784 ms  13.827 ms 221.6.9.81 (221.6.9.81)  9.758 ms
+ 4  221.6.2.169 (221.6.2.169)  11.777 ms 122.96.66.13 (122.96.66.13)  34.952 ms 221.6.2.53 (221.6.2.53)  41.372 ms
+ 5  219.158.96.149 (219.158.96.149)  39.167 ms  39.210 ms  39.238 ms
+ 6  123.126.0.194 (123.126.0.194)  37.270 ms 123.126.0.66 (123.126.0.66)  37.163 ms  37.441 ms
+ 7  124.65.57.26 (124.65.57.26)  42.787 ms  42.799 ms  42.809 ms
+ 8  61.148.146.210 (61.148.146.210)  30.176 ms 61.148.154.98 (61.148.154.98)  32.613 ms  32.675 ms
+ 9  202.106.42.102 (202.106.42.102)  44.563 ms  44.600 ms  44.627 ms
+10  210.77.139.150 (210.77.139.150)  53.302 ms  53.233 ms  53.032 ms
+11  211.151.104.6 (211.151.104.6)  39.585 ms  39.502 ms  39.598 ms
+12  211.151.111.30 (211.151.111.30)  35.161 ms  35.938 ms  36.005 ms
+

# 2.17. netstat

netstat 命令用来打印 Linux 中网络系统的状态信息,可让你得知整个 Linux 系统的网络情况。

参考:http://man.linuxde.net/netstat

示例:

# 列出所有端口 (包括监听和未监听的)
+netstat -a     #列出所有端口
+netstat -at    #列出所有tcp端口
+netstat -au    #列出所有udp端口
+
+# 列出所有处于监听状态的 Sockets
+netstat -l        #只显示监听端口
+netstat -lt       #只列出所有监听 tcp 端口
+netstat -lu       #只列出所有监听 udp 端口
+netstat -lx       #只列出所有监听 UNIX 端口
+
+# 显示每个协议的统计信息
+netstat -s   显示所有端口的统计信息
+netstat -st   显示TCP端口的统计信息
+netstat -su   显示UDP端口的统计信息
+
+ + + diff --git a/linux/cli/linux-cli-software.html b/linux/cli/linux-cli-software.html new file mode 100644 index 0000000..8213c28 --- /dev/null +++ b/linux/cli/linux-cli-software.html @@ -0,0 +1,107 @@ + + + + + + Linux 软件管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 软件管理

关键词:rpm, yum, apt-get

# 1. rpm

rpm 命令是 RPM 软件包的管理工具。rpm 原本是 Red Hat Linux 发行版专门用来管理 Linux 各项套件的程序,由于它遵循 GPL 规则且功能强大方便,因而广受欢迎。逐渐受到其他发行版的采用。RPM 套件管理方式的出现,让 Linux 易于安装,升级,间接提升了 Linux 的适用度。

参考:http://man.linuxde.net/rpm

示例:

(1)安装 rpm 包

rpm -ivh xxx.rpm
+

(2)安装.src.rpm 软件包

这类软件包是包含了源代码的 rpm 包,在安装时需要进行编译

rpm -i xxx.src.rpm
+cd /usr/src/redhat/SPECS
+rpmbuild -bp xxx.specs             #一个和你的软件包同名的specs文件
+cd /usr/src/redhat/BUILD/xxx/      #一个和你的软件包同名的目录
+./configure                        #这一步和编译普通的源码软件一样,可以加上参数
+make
+make install
+

(3)卸载 rpm 软件包

使用命令 rpm -e 包名,包名可以包含版本号等信息,但是不可以有后缀.rpm,比如卸载软件包 proftpd-1.2.8-1,可以使用下列格式:

rpm -e proftpd-1.2.8-1
+rpm -e proftpd-1.2.8
+rpm -e proftpd-
+rpm -e proftpd
+

不可以是下列格式:

rpm -e proftpd-1.2.8-1.i386.rpm
+rpm -e proftpd-1.2.8-1.i386
+rpm -e proftpd-1.2
+rpm -e proftpd-1
+

有时会出现一些错误或者警告:

... is needed by ...
+

这说明这个软件被其他软件需要,不能随便卸载,可以用 rpm -e --nodeps 强制卸载

(4)查看与 rpm 包相关的文件和其他信息

rpm -qa # 列出所有安装过的包
+

# 2. yum

yum 命令是在 Fedora 和 RedHat 以及 SUSE 中基于 rpm 的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理 RPM 软件包,能够从指定的服务器自动下载 RPM 包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载、安装。

参考:http://man.linuxde.net/yum

示例:

部分常用的命令包括:

  • 自动搜索最快镜像插件:yum install yum-fastestmirror
  • 安装 yum 图形窗口插件:yum install yumex
  • 查看可能批量安装的列表:yum grouplist

安装

yum install              #全部安装
+yum install package1     #安装指定的安装包package1
+yum groupinsall group1   #安装程序组group1
+

更新和升级

yum update               #全部更新
+yum update package1      #更新指定程序包package1
+yum check-update         #检查可更新的程序
+yum upgrade package1     #升级指定程序包package1
+yum groupupdate group1   #升级程序组group1
+

查找和显示

yum info package1      #显示安装包信息package1
+yum list               #显示所有已经安装和可以安装的程序包
+yum list package1      #显示指定程序包安装情况package1
+yum groupinfo group1   #显示程序组group1信息yum search string 根据关键字string查找安装包
+yum search <keyword>   #查找软件包
+

删除程序

yum remove <package_name>          #删除程序包package_name
+yum groupremove group1             #删除程序组group1
+yum deplist package1               #查看程序package1依赖情况
+

清除缓存

yum clean packages       #清除缓存目录下的软件包
+yum clean headers        #清除缓存目录下的 headers
+yum clean oldheaders     #清除缓存目录下旧的 headers
+

# 2.1. yum 源

yum 的默认源是国外的,下载速度比较慢,所以最好替换为一个国内的 yum 源。

推荐 yum 国内源 源地址
http://mirrors.163.com/ (opens new window) Centos6:http://mirrors.aliyun.com/repo/Centos-6.repo
Centos7:http://mirrors.aliyun.com/repo/Centos-7.repo
http://mirrors.aliyun.com/ (opens new window) Centos6:http://mirrors.163.com/.help/CentOS6-Base-163.repo
Centos7:http://mirrors.163.com/.help/CentOS7-Base-163.repo

🔔 注意:Cento5 已废弃,只能使用 http://vault.centos.org/ 替换,但由于是国外镜像,速度较慢。

替换方法,以 aliyun CentOS7 为例:

cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
+wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
+yum clean all
+yum makecache
+

# 3. apt-get

apt-get 命令是 Debian Linux 发行版中的 APT 软件包管理工具。所有基于 Debian 的发行都使用这个包管理系统。deb 包可以把一个应用的文件包在一起,大体就如同 Windows 上的安装文件。

参考:http://man.linuxde.net/apt-get

示例:

使用 apt-get 命令的第一步就是引入必需的软件库,Debian 的软件库也就是所有 Debian 软件包的集合,它们存在互联网上的一些公共站点上。把它们的地址加入,apt-get 就能搜索到我们想要的软件。/etc/apt/sources.list 是存放这些地址列表的配置文件,其格式如下:

deb [web 或 ftp 地址][发行版名字] [main/contrib/non-free] +我们常用的 Ubuntu 就是一个基于 Debian 的发行,我们使用 apt-get 命令获取这个列表,以下是我整理的常用命令:

在修改 /etc/apt/sources.list 或者 /etc/apt/preferences 之后运行该命令。

# 更新 apt-get
+apt-get update
+
+# 安装一个软件包
+apt-get install packagename
+
+# 卸载一个已安装的软件包(保留配置文件)
+apt-get remove packagename
+
+# 卸载一个已安装的软件包(删除配置文件)
+apt-get –purge remove packagename
+
+# 如果需要空间的话,可以让这个命令来删除你已经删掉的软件
+apt-get autoclean apt
+
+# 把安装的软件的备份也删除,不过这样不会影响软件的使用的
+apt-get clean
+
+# 更新所有已安装的软件包
+apt-get upgrade
+
+# 将系统升级到新版本
+apt-get dist-upgrade
+

# 4. 参考资料

  • http://man.linuxde.net/rpm
  • http://man.linuxde.net/yum
  • http://man.linuxde.net/apt-get
  • http://www.runoob.com/linux/linux-yum.html
+ + + diff --git a/linux/cli/linux-cli-system.html b/linux/cli/linux-cli-system.html new file mode 100644 index 0000000..50e091e --- /dev/null +++ b/linux/cli/linux-cli-system.html @@ -0,0 +1,256 @@ + + + + + + Linux 系统管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 系统管理

关键词:lsb_release, reboot, exit, shutdown, date, mount, umount, ps, kill, systemctl, service, crontab

# 1. Linux 系统管理要点

  • 查看 Linux 系统发行版本 +
    • 使用 lsb_release(此命令适用于所有的 Linux 发行版本)
    • 使用 cat /etc/redhat-release(此方法只适合 Redhat 系的 Linux)
  • 查看 CPU 信息 - 使用 cat /proc/cpuinfo
  • 重新启动 Linux 操作系统 - 使用 reboot
  • 退出 shell,并返回给定值 - 使用 exit
  • 关闭系统 - 使用 shutdown
  • 查看或设置系统时间与日期 - 使用 date
  • 挂载文件系统 - 使用 mount
  • 取消挂载文件系统 - 使用 umount
  • 查看系统当前进程状态 - 使用 ps
  • 删除当前正在运行的进程 - 使用 kill
  • 启动、停止、重启、关闭、显示系统服务(Centos7),使用 systemctl
  • 启动、停止、重启、关闭、显示系统服务(Centos7 以前),使用 service
  • 管理需要周期性执行的任务,使用 crontab

# 2. 命令常见用法

# 2.1. lsb_release

lsb_release 不是 bash 默认命令,如果要使用,需要先安装。

安装方法:

  1. 执行 yum provides lsb_release,查看支持 lsb_release 命令的包。
  2. 选择合适版本,执行类似这样的安装命令:yum install -y redhat-lsb-core-4.1-27.el7.centos.1.x86_64

# 2.2. reboot

reboot 命令用来重新启动正在运行的 Linux 操作系统。

参考:http://man.linuxde.net/reboot

示例:

reboot        # 重开机。
+reboot -w     # 做个重开机的模拟(只有纪录并不会真的重开机)。
+

# 2.3. exit

exit 命令同于退出 shell,并返回给定值。在 shell 脚本中可以终止当前脚本执行。执行 exit 可使 shell 以指定的状态值退出。若不设置状态值参数,则 shell 以预设值退出。状态值 0 代表执行成功,其他值代表执行失败。

参考:http://man.linuxde.net/exit

示例:

# 退出当前 shell
+[root@localhost ~]# exit
+logout
+
+# 在脚本中,进入脚本所在目录,否则退出
+cd $(dirname $0) || exit 1
+
+# 在脚本中,判断参数数量,不匹配就打印使用方式,退出
+if [ "$#" -ne "2" ]; then
+    echo "usage: $0 <area> <hours>"
+    exit 2
+fi
+
+# 在脚本中,退出时删除临时文件
+trap "rm -f tmpfile; echo Bye." EXIT
+
+# 检查上一命令的退出码
+./mycommand.sh
+EXCODE=$?
+if [ "$EXCODE" == "0" ]; then
+    echo "O.K"
+fi
+

# 2.4. shutdown

shutdown 命令用来系统关机命令。shutdown 指令可以关闭所有程序,并依用户的需要,进行重新开机或关机的动作。

参考:http://man.linuxde.net/shutdown

示例:

# 指定现在立即关机
+shutdown -h now
+
+# 指定 5 分钟后关机,同时送出警告信息给登入用户
+shutdown +5 "System will shutdown after 5 minutes"
+

# 2.5. date

date 命令是显示或设置系统时间与日期。

参考:http://man.linuxde.net/date

示例:

# 格式化输出
+date +"%Y-%m-%d"
+2009-12-07
+
+# 输出昨天日期
+date -d "1 day ago" +"%Y-%m-%d"
+2012-11-19
+
+# 2 秒后输出
+date -d "2 second" +"%Y-%m-%d %H:%M.%S"
+2012-11-20 14:21.31
+
+# 传说中的 1234567890 秒
+date -d "1970-01-01 1234567890 seconds" +"%Y-%m-%d %H:%m:%S"
+2009-02-13 23:02:30
+
+# 普通转格式
+date -d "2009-12-12" +"%Y/%m/%d %H:%M.%S"
+2009/12/12 00:00.00
+
+# apache 格式转换
+date -d "Dec 5, 2009 12:00:37 AM" +"%Y-%m-%d %H:%M.%S"
+2009-12-05 00:00.37
+
+# 格式转换后时间游走
+date -d "Dec 5, 2009 12:00:37 AM 2 year ago" +"%Y-%m-%d %H:%M.%S"
+2007-12-05 00:00.37
+
+# 加减操作
+date +%Y%m%d                   # 显示前天年月日
+date -d "+1 day" +%Y%m%d       # 显示前一天的日期
+date -d "-1 day" +%Y%m%d       # 显示后一天的日期
+date -d "-1 month" +%Y%m%d     # 显示上一月的日期
+date -d "+1 month" +%Y%m%d     # 显示下一月的日期
+date -d "-1 year" +%Y%m%d      # 显示前一年的日期
+date -d "+1 year" +%Y%m%d      # 显示下一年的日期
+
+# 设定时间
+date -s                        # 设置当前时间,只有root权限才能设置,其他只能查看
+date -s 20120523               # 设置成20120523,这样会把具体时间设置成空00:00:00
+date -s 01:01:01               # 设置具体时间,不会对日期做更改
+date -s "01:01:01 2012-05-23"  # 这样可以设置全部时间
+date -s "01:01:01 20120523"    # 这样可以设置全部时间
+date -s "2012-05-23 01:01:01"  # 这样可以设置全部时间
+date -s "20120523 01:01:01"    # 这样可以设置全部时间
+
+# 有时需要检查一组命令花费的时间
+#!/bin/bash
+
+start=$(date +%s)
+nmap man.linuxde.net &> /dev/null
+
+end=$(date +%s)
+difference=$(( end - start ))
+echo $difference seconds.
+

# 2.6. mount

mount 命令用于挂载文件系统到指定的挂载点。此命令的最常用于挂载 cdrom,使我们可以访问 cdrom 中的数据,因为你将光盘插入 cdrom 中,Linux 并不会自动挂载,必须使用 Linux mount 命令来手动完成挂载。

参考:http://man.linuxde.net/mount > https://blog.csdn.net/weishujie000/article/details/76531924

示例:

# 将 /dev/hda1 挂在 /mnt 之下
+mount /dev/hda1 /mnt
+
+# 将 /dev/hda1 用唯读模式挂在 /mnt 之下
+mount -o ro /dev/hda1 /mnt
+
+# 将 /tmp/image.iso 这个光碟的 image 档使用 loop 模式挂在 /mnt/cdrom 之下
+# 用这种方法可以将一般网络上可以找到的 Linux ISO 在不烧录成光碟的情况下检视其内容
+mount -o loop /tmp/image.iso /mnt/cdrom
+

# 2.7. umount

umount 命令用于卸载已经挂载的文件系统。利用设备名或挂载点都能 umount 文件系统,不过最好还是通过挂载点卸载,以免使用绑定挂载(一个设备,多个挂载点)时产生混乱。

参考:http://man.linuxde.net/umount

示例:

# 通过设备名卸载
+umount -v /dev/sda1
+/dev/sda1 umounted
+
+# 通过挂载点卸载
+umount -v /mnt/mymount/
+/tmp/diskboot.img umounted
+

# 2.8. ps

ps 命令用于报告当前系统的进程状态。可以搭配 kill 指令随时中断、删除不必要的程序。ps 命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。

参考:http://man.linuxde.net/ps

示例:

# 按内存资源的使用量对进程进行排序
+ps aux | sort -rnk 4
+
+# 按 CPU 资源的使用量对进程进行排序
+ps aux | sort -nk 3
+

# 2.9. kill

kill 命令用来删除执行中的程序或工作。kill 可将指定的信息送至程序。预设的信息为 SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用 SIGKILL(9) 信息尝试强制删除程序。程序或工作的编号可利用 ps 指令或 job 指令查看。

参考:http://man.linuxde.net/kill

示例:

# 列出所有信号名称
+ kill -l
+ 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
+ 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
+ 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
+13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
+17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
+21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
+25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
+29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
+35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
+39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
+43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
+47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
+51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
+55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
+59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
+63) SIGRTMAX-1  64) SIGRTMAX
+
+# 先用 ps 查找进程,然后用 kill 杀掉
+ps -ef | grep vim
+root      3268  2884  0 16:21 pts/1    00:00:00 vim install.log
+root      3370  2822  0 16:21 pts/0    00:00:00 grep vim
+
+kill 3268
+kill 3268
+-bash: kill: (3268) - 没有那个进程
+

# 2.10. systemctl

systemctl 命令是系统服务管理器指令,它实际上将 service 和 chkconfig 这两个命令组合到一起。

参考:http://man.linuxde.net/systemctl

示例:

# 1.启动 nfs 服务
+systemctl start nfs-server.service
+
+# 2.设置开机自启动
+systemctl enable nfs-server.service
+
+# 3.停止开机自启动
+systemctl disable nfs-server.service
+
+# 4.查看服务当前状态
+systemctl status nfs-server.service
+
+# 5.重新启动某服务
+systemctl restart nfs-server.service
+
+# 6.查看所有已启动的服务
+systemctl list -units --type=service
+
+# 7. 开启防火墙 22 端口
+iptables -I INPUT -p tcp --dport 22 -j accept
+
+# 8. 彻底关闭防火墙
+sudo systemctl status firewalld.service
+sudo systemctl stop firewalld.service
+sudo systemctl disable firewalld.service
+

# 2.11. service

service 命令是 Redhat Linux 兼容的发行版中用来控制系统服务的实用工具,它以启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。

参考:http://man.linuxde.net/service

示例:

service network status
+配置设备:
+lo eth0
+当前的活跃设备:
+lo eth0
+
+service network restart
+正在关闭接口 eth0:                                        [  确定  ]
+关闭环回接口:                                             [  确定  ]
+设置网络参数:                                             [  确定  ]
+弹出环回接口:                                             [  确定  ]
+弹出界面 eth0:                                            [  确定  ]
+

# 2.12. crontab

crontab 命令被用来提交和管理用户的需要周期性执行的任务,与 windows 下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动 crond 进程,crond 进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

参考:http://man.linuxde.net/crontab

示例:

# 每 1 分钟执行一次 command
+* * * * * command
+
+# 每小时的第 3 和第 15 分钟执行
+3,15 * * * * command
+
+# 在上午 8 点到 11 点的第 3 和第 15 分钟执行
+3,15 8-11 * * * command
+
+# 每隔两天的上午 8 点到 11 点的第 3 和第 15 分钟执行
+3,15 8-11 */2 * * command
+
+# 每个星期一的上午 8 点到 11 点的第 3 和第 15 分钟执行
+3,15 8-11 * * 1 command
+
+# 每晚的 21:30 重启 smb
+30 21 * * * /etc/init.d/smb restart
+
+# 每月 1、10、22 日的 4 : 45 重启 smb
+45 4 1,10,22 * * /etc/init.d/smb restart
+
+# 每周六、周日的 1:10 重启 smb
+10 1 * * 6,0 /etc/init.d/smb restart
+
+# 每天 18 : 00 至 23 : 00 之间每隔 30 分钟重启 smb
+0,30 18-23 * * * /etc/init.d/smb restart
+
+# 每星期六的晚上 11:00 pm 重启 smb
+0 23 * * 6 /etc/init.d/smb restart
+
+# 每一小时重启 smb
+* */1 * * * /etc/init.d/smb restart
+
+# 晚上 11 点到早上 7 点之间,每隔一小时重启 smb
+* 23-7/1 * * * /etc/init.d/smb restart
+
+# 每月的 4 号与每周一到周三的 11 点重启 smb
+0 11 4 * mon-wed /etc/init.d/smb restart
+
+# 一月一号的 4 点重启 smb
+0 4 1 jan * /etc/init.d/smb restart
+
+# 每小时执行`/etc/cron.hourly`目录内的脚本
+01 * * * * root run-parts /etc/cron.hourly
+
+ + + diff --git a/linux/cli/linux-cli-user.html b/linux/cli/linux-cli-user.html new file mode 100644 index 0000000..07f428d --- /dev/null +++ b/linux/cli/linux-cli-user.html @@ -0,0 +1,112 @@ + + + + + + Linux 用户管理 | LINUX-TUTORIAL + + + + + + + + +

# Linux 用户管理

关键词:groupadd, groupdel, groupmod, useradd, userdel, usermod, passwd, su, sudo

# 1. Linux 用户管理要点

  • 创建用户组 - 使用 groupadd
  • 删除用户组 - 使用 groupdel
  • 修改用户组信息 - 使用 groupmod
  • 创建用户 - 使用 useradd
  • 删除用户 - 使用 userdel
  • 修改用户信息 - 使用 usermod
  • 设置用户认证信息 - 使用 passwd
  • 切换用户 - 使用 su
  • 当前用户想执行没有权限执行的命令时,使用其他用户身份去执行 - 使用 sudo

# 2. 命令常见用法

# 2.1. groupadd

groupadd 命令用于创建一个新的用户组,新用户组的信息将被添加到系统文件中。

参考:http://man.linuxde.net/groupadd

示例:

# 建立一个新组,并设置组 ID 加入系统
+$ groupadd -g 344 jsdigname
+

# 2.2. groupdel

groupdel 命令用于删除指定的用户组,本命令要修改的系统文件包括 /ect/group/ect/gshadow。若该群组中仍包括某些用户,则必须先删除这些用户后,方能删除群组。

参考:http://man.linuxde.net/groupdel

示例:

$ groupadd damon  # 创建damon用户组
+$ groupdel damon  # 删除这个用户组
+

# 2.3. groupmod

groupmod 命令更改群组识别码或名称。需要更改群组的识别码或名称时,可用 groupmod 指令来完成这项工作。

参考:http://man.linuxde.net/groupmod

# 2.4. useradd

useradd 命令用于 Linux 中创建的新的系统用户。useradd 可用来建立用户帐号。帐号建好之后,再用 passwd 设定帐号的密码.而可用 userdel 删除帐号。使用 useradd 指令所建立的帐号,实际上是保存在 /etc/passwd 文本文件中。

参考:http://man.linuxde.net/useradd

示例:

# 新建用户加入组
+$ useradd –g sales jack –G company,employees    # -g:加入主要组、-G:加入次要组
+
+# 建立一个新用户账户,并设置 ID
+$ useradd caojh -u 544
+

# 2.5. userdel

userdel 命令用于删除给定的用户,以及与用户相关的文件。若不加选项,则仅删除用户帐号,而不删除相关文件。

参考:http://man.linuxde.net/userdel

示例:

userdel 命令很简单,比如我们现在有个用户 linuxde,其 home 目录位于/var目录中,现在我们来删除这个用户:

$ userdel linuxde       # 删除用户linuxde,但不删除其家目录及文件;
+$ userdel -r linuxde    # 删除用户linuxde,其 home 目录及文件一并删除;
+

# 2.6. usermod

usermod 命令用于修改用户的基本信息。usermod 命令不允许你改变正在线上的使用者帐号名称。当 usermod 命令用来改变 user id,必须确认这名 user 没在电脑上执行任何程序。你需手动更改使用者的 crontab 档。也需手动更改使用者的 at 工作档。采用 NIS server 须在 server 上更动相关的 NIS 设定。

参考:http://man.linuxde.net/usermod

示例:

# 将 newuser2 添加到组 staff 中
+$ usermod -G staff newuser2
+
+# 修改 newuser 的用户名为 newuser1
+$ usermod -l newuser1 newuser
+
+# 锁定账号 newuser1
+$ usermod -L newuser1
+
+# 解除对 newuser1 的锁定
+$ usermod -U newuser1
+

# 2.7. passwd

passwd 命令用于设置用户的认证信息,包括用户密码、密码过期时间等。系统管理者则能用它管理系统用户的密码。只有管理者可以指定用户名称,一般用户只能变更自己的密码。

参考:http://man.linuxde.net/passwd

示例:

# 如果是普通用户执行 passwd 只能修改自己的密码。
+# 如果新建用户后,要为新用户创建密码,则用 passwd 用户名,注意要以 root 用户的权限来创建。
+$ passwd linuxde    # 更改或创建linuxde用户的密码;
+Changing password for user linuxde.
+New UNIX password:          # 请输入新密码;
+Retype new UNIX password:   # 再输入一次;
+passwd: all authentication tokens updated successfully. # 成功;
+
+# 普通用户如果想更改自己的密码,直接运行 passwd 即可,比如当前操作的用户是 linuxde。
+$ passwd
+Changing password for user linuxde. # 更改linuxde用户的密码;
+(current) UNIX password:   # 请输入当前密码;
+New UNIX password:         # 请输入新密码;
+Retype new UNIX password:  # 确认新密码;
+passwd: all authentication tokens updated successfully. # 更改成功;
+
+# 比如我们让某个用户不能修改密码,可以用`-l`选项来锁定:
+$ passwd -l linuxde    # 锁定用户linuxde不能更改密码;
+Locking password for user linuxde.
+passwd: Success           # 锁定成功;
+
+$ su linuxde   # 通过su切换到linuxde用户;
+$ passwd      # linuxde来更改密码;
+Changing password for user linuxde.
+Changing password for linuxde
+(current) UNIX password:          # 输入linuxde的当前密码;
+passwd: Authentication token manipulation error     # 失败,不能更改密码;
+
+$ passwd -d linuxde  # 清除linuxde用户密码;
+Removing password for user linuxde.
+passwd: Success                         # 清除成功;
+
+$ passwd -S linuxde    # 查询linuxde用户密码状态;
+Empty password.                         # 空密码,也就是没有密码;
+

# 2.8. su

su 命令用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。

参考:http://man.linuxde.net/su

示例:

# 变更帐号为 root 并在执行 ls 指令后退出变回原使用者:
+$ su -c ls root
+
+# 变更帐号为 root 并传入`-f`选项给新执行的 shell:
+$ su root -f
+
+# 变更帐号为 test 并改变工作目录至 test 的家目录:
+$ su -test
+

# 2.9. sudo

sudo 命令用来以其他身份来执行命令,预设的身份为 root。在 /etc/sudoers 中设置了可执行 sudo 指令的用户。若其未经授权的用户企图使用 sudo,则会发出警告的邮件给管理员。用户使用 sudo 时,必须先输入密码,之后有 5 分钟的有效期限,超过期限则必须重新输入密码。

参考:http://man.linuxde.net/sudo

示例:

# 指定用户执行命令
+$ sudo -u userb ls -l
+# 列出目前的权限
+$ sudo -l
+# 显示sudo设置
+$ sudo -L
+

# 2.9.1. 给普通用户授权 sudo

假设要给普通用户 mary 配置 sudo 权限:

  1. /etc/sudoers 文件存放了 sudo 的相关用户,但是默认是没有写权限的,所以需要设为可写:chmod u+w /etc/sudoers
  2. 在该文件中添加 mary ALL=(ALL) ALL ,保存并退出,让 mary 具有 sudo 的所有权限
  3. 再将 /etc/sudoers 的权限恢复到默认状态:chmod u-w /etc/sudoers

# 2.9.2. 免密码授权 sudo

与给普通用户授权 sudo 类似,区别仅在于第 2 步:mary ALL=(ALL) NOPASSWD: ALL

+ + + diff --git a/linux/cli/scp.html b/linux/cli/scp.html new file mode 100644 index 0000000..482807f --- /dev/null +++ b/linux/cli/scp.html @@ -0,0 +1,64 @@ + + + + + + scp | LINUX-TUTORIAL + + + + + + + + +

# scp

加密的方式在本地主机和远程主机之间复制文件

# 补充说明

scp 命令 用于在 Linux 下进行远程拷贝文件的命令,和它类似的命令有 cp,不过 cp 只是在本机进行拷贝不能跨服务器,而且 scp 传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读 read only system 时,用 scp 可以帮你把文件移出来。另外,scp 还非常不占资源,不会提高多少系统负荷,在这一点上,rsync 就远远不及它了。虽然  rsync 比 scp 会快一点,但当小文件众多的情况下,rsync 会导致硬盘 I/O 非常高,而 scp 基本不影响系统正常使用。

# 语法

scp(选项)(参数)
+

# 选项

-1:使用ssh协议版本1;
+-2:使用ssh协议版本2;
+-4:使用ipv4;
+-6:使用ipv6;
+-B:以批处理模式运行;
+-C:使用压缩;
+-F:指定ssh配置文件;
+-i:identity_file 从指定文件中读取传输时使用的密钥文件(例如亚马逊云pem),此参数直接传递给ssh;
+-l:指定宽带限制;
+-o:指定使用的ssh选项;
+-P:指定远程主机的端口号;
+-p:保留文件的最后修改时间,最后访问时间和权限模式;
+-q:不显示复制进度;
+-r:以递归方式复制。
+

# 参数

  • 源文件:指定要复制的源文件。
  • 目标文件:目标文件。格式为user@host:filename(文件名为目标文件的名称)。

# 实例

从远程复制到本地的 scp 命令与上面的命令雷同,只要将从本地复制到远程的命令后面 2 个参数互换顺序就行了。

从远处复制文件到本地目录

scp root@10.10.10.10:/opt/soft/nginx-0.5.38.tar.gz /opt/soft/
+

从 10.10.10.10 机器上的/opt/soft/的目录中下载 nginx-0.5.38.tar.gz  文件到本地/opt/soft/目录中。

从亚马逊云复制 OpenVPN 到本地目录

scp -i amazon.pem ubuntu@10.10.10.10:/usr/local/openvpn_as/etc/exe/openvpn-connect-2.1.3.110.dmg openvpn-connect-2.1.3.110.dmg
+

从 10.10.10.10 机器上下载 openvpn 安装文件到本地当前目录来。

从远处复制到本地

scp -r root@10.10.10.10:/opt/soft/mongodb /opt/soft/
+

从 10.10.10.10 机器上的/opt/soft/中下载 mongodb 目录到本地的/opt/soft/目录来。

上传本地文件到远程机器指定目录

scp /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest
+# 指定端口 2222
+scp -rp -P 2222 /opt/soft/nginx-0.5.38.tar.gz root@10.10.10.10:/opt/soft/scptest
+

复制本地/opt/soft/目录下的文件 nginx-0.5.38.tar.gz 到远程机器 10.10.10.10 的opt/soft/scptest目录。

上传本地目录到远程机器指定目录

scp -r /opt/soft/mongodb root@10.10.10.10:/opt/soft/scptest
+

上传本地目录/opt/soft/mongodb到远程机器 10.10.10.10 上/opt/soft/scptest的目录中去。

+ + + diff --git a/linux/cli/top.html b/linux/cli/top.html new file mode 100644 index 0000000..73969e9 --- /dev/null +++ b/linux/cli/top.html @@ -0,0 +1,75 @@ + + + + + + top | LINUX-TUTORIAL + + + + + + + + +

# top

显示或管理执行中的程序

# 补充说明

top 命令 可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过 top 命令所提供的互动式界面,用热键可以管理。

# 语法

top(选项)
+

# 选项

-b:以批处理模式操作;
+-c:显示完整的治命令;
+-d:屏幕刷新间隔时间;
+-I:忽略失效过程;
+-s:保密模式;
+-S:累积模式;
+-i<时间>:设置间隔时间;
+-u<用户名>:指定用户名;
+-p<进程号>:指定进程;
+-n<次数>:循环显示的次数。
+

# top 交互命令

在 top 命令执行过程中可以使用的一些交互命令。这些命令都是单字母的,如果在命令行中使用了-s 选项,  其中一些命令可能会被屏蔽。

h:显示帮助画面,给出一些简短的命令总结说明;
+k:终止一个进程;
+i:忽略闲置和僵死进程,这是一个开关式命令;
+q:退出程序;
+r:重新安排一个进程的优先级别;
+S:切换到累计模式;
+s:改变两次刷新之间的延迟时间(单位为s),如果有小数,就换算成ms。输入0值则系统将不断刷新,默认值是5s;
+f或者F:从当前显示中添加或者删除项目;
+o或者O:改变显示项目的顺序;
+l:切换显示平均负载和启动时间信息;
+m:切换显示内存信息;
+t:切换显示进程和CPU状态信息;
+c:切换显示命令名称和完整命令行;
+M:根据驻留内存大小进行排序;
+P:根据CPU使用百分比大小进行排序;
+T:根据时间/累计时间进行排序;
+w:将当前设置写入~/.toprc文件中。
+

# 实例

top - 09:44:56 up 16 days, 21:23,  1 user,  load average: 9.59, 4.75, 1.92
+Tasks: 145 total,   2 running, 143 sleeping,   0 stopped,   0 zombie
+Cpu(s): 99.8%us,  0.1%sy,  0.0%ni,  0.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
+Mem:   4147888k total,  2493092k used,  1654796k free,   158188k buffers
+Swap:  5144568k total,       56k used,  5144512k free,  2013180k cached
+

解释:

  • top - 09:44:56[当前系统时间],
  • 16 days[系统已经运行了 16 天],
  • 1 user[个用户当前登录],
  • load average: 9.59, 4.75, 1.92[系统负载,即任务队列的平均长度]
  • Tasks: 145 total[总进程数],
  • 2 running[正在运行的进程数],
  • 143 sleeping[睡眠的进程数],
  • 0 stopped[停止的进程数],
  • 0 zombie[冻结进程数],
  • Cpu(s): 99.8%us[用户空间占用 CPU 百分比],
  • 0.1%sy[内核空间占用 CPU 百分比],
  • 0.0%ni[用户进程空间内改变过优先级的进程占用 CPU 百分比],
  • 0.2%id[空闲 CPU 百分比], 0.0%wa[等待输入输出的 CPU 时间百分比],
  • 0.0%hi[],
  • 0.0%st[],
  • Mem: 4147888k total[物理内存总量],
  • 2493092k used[使用的物理内存总量],
  • 1654796k free[空闲内存总量],
  • 158188k buffers[用作内核缓存的内存量]
  • Swap:  5144568k total[交换区总量],
  • 56k used[使用的交换区总量],
  • 5144512k free[空闲交换区总量],
  • 2013180k cached[缓冲的交换区总量],
+ + + diff --git a/linux/cli/vmstat.html b/linux/cli/vmstat.html new file mode 100644 index 0000000..3a6a02c --- /dev/null +++ b/linux/cli/vmstat.html @@ -0,0 +1,59 @@ + + + + + + vmstat | LINUX-TUTORIAL + + + + + + + + +

# vmstat

显示虚拟内存状态

# 补充说明

vmstat 命令 的含义为显示虚拟内存状态(“Viryual Memor Statics”),但是它可以报告关于进程、内存、I/O 等系统整体运行状态。

# 语法

vmstat(选项)(参数)
+

# 选项

-a:显示活动内页;
+-f:显示启动后创建的进程总数;
+-m:显示slab信息;
+-n:头信息仅显示一次;
+-s:以表格方式显示事件计数器和内存状态;
+-d:报告磁盘状态;
+-p:显示指定的硬盘分区状态;
+-S:输出信息的单位。
+

# 参数

  • 事件间隔:状态信息刷新的时间间隔;
  • 次数:显示报告的次数。

# 实例

vmstat 3
+procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
+ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
+ 0  0    320  42188 167332 1534368    0    0     4     7    1    0  0  0 99  0  0
+ 0  0    320  42188 167332 1534392    0    0     0     0 1002   39  0  0 100  0  0
+ 0  0    320  42188 167336 1534392    0    0     0    19 1002   44  0  0 100  0  0
+ 0  0    320  42188 167336 1534392    0    0     0     0 1002   41  0  0 100  0  0
+ 0  0    320  42188 167336 1534392    0    0     0     0 1002   41  0  0 100  0  0
+

字段说明:

Procs(进程)

  • r: 运行队列中进程数量,这个值也可以判断是否需要增加 CPU。(长期大于 1)
  • b: 等待 IO 的进程数量。

Memory(内存)

  • swpd: 使用虚拟内存大小,如果 swpd 的值不为 0,但是 SI,SO 的值长期为 0,这种情况不会影响系统性能。
  • free: 空闲物理内存大小。
  • buff: 用作缓冲的内存大小。
  • cache: 用作缓存的内存大小,如果 cache 的值大的时候,说明 cache 处的文件数多,如果频繁访问到的文件都能被 cache 处,那么磁盘的读 IO bi 会非常小。

Swap

  • si: 每秒从交换区写到内存的大小,由磁盘调入内存。
  • so: 每秒写入交换区的内存大小,由内存调入磁盘。

注意:内存够用的时候,这 2 个值都是 0,如果这 2 个值长期大于 0 时,系统性能会受到影响,磁盘 IO 和 CPU 资源都会被消耗。有些朋友看到空闲内存(free)很少的或接近于 0 时,就认为内存不够用了,不能光看这一点,还要结合 si 和 so,如果 free 很少,但是 si 和 so 也很少(大多时候是 0),那么不用担心,系统性能这时不会受到影响的。

IO(现在的 Linux 版本块的大小为 1kb)

  • bi: 每秒读取的块数
  • bo: 每秒写入的块数

注意:随机磁盘读写的时候,这 2 个值越大(如超出 1024k),能看到 CPU 在 IO 等待的值也会越大。

system(系统)

  • in: 每秒中断数,包括时钟中断。
  • cs: 每秒上下文切换数。

注意:上面 2 个值越大,会看到由内核消耗的 CPU 时间会越大。

CPU(以百分比表示)

  • us: 用户进程执行时间百分比(user time)

us 的值比较高时,说明用户进程消耗的 CPU 时间多,但是如果长期超 50%的使用,那么我们就该考虑优化程序算法或者进行加速。

  • sy: 内核系统进程执行时间百分比(system time)

sy 的值高时,说明系统内核消耗的 CPU 资源多,这并不是良性表现,我们应该检查原因。

  • wa: IO 等待时间百分比

wa 的值高时,说明 IO 等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。

  • id: 空闲时间百分比
+ + + diff --git a/linux/cli/命令行的艺术.html b/linux/cli/命令行的艺术.html new file mode 100644 index 0000000..aca72fc --- /dev/null +++ b/linux/cli/命令行的艺术.html @@ -0,0 +1,96 @@ + + + + + + LINUX-TUTORIAL + + + + + + + + +

转载自 https://github.com/jlevy/the-art-of-command-line

ČeštinaDeutschΕλληνικάEnglishEspañolFrançaisIndonesiaItaliano日本語한국어PortuguêsRomânăРусскийSlovenščinaУкраїнська简体中文繁體中文

# 命令行的艺术

img

img

熟练使用命令行是一种常常被忽视,或被认为难以掌握的技能,但实际上,它会提高你作为工程师的灵活性以及生产力。本文是一份我在 Linux 上工作时,发现的一些命令行使用技巧的摘要。有些技巧非常基础,而另一些则相当复杂,甚至晦涩难懂。这篇文章并不长,但当你能够熟练掌握这里列出的所有技巧时,你就学会了很多关于命令行的东西了。

这篇文章是许多作者和译者共同的成果。 +这里的部分内容 +首次 (opens new window) 出现 (opens new window) +于 Quora (opens new window), +但已经迁移到了 Github,并由众多高手做出了许多改进。 +如果你在本文中发现了错误或者存在可以改善的地方,请贡献你的一份力量

# 前言

涵盖范围:

  • 这篇文章不仅能帮助刚接触命令行的新手,而且对具有经验的人也大有裨益。本文致力于做到覆盖面广(涉及所有重要的内容),具体(给出具体的最常用的例子),以及简洁(避免冗余的内容,或是可以在其他地方轻松查到的细枝末节)。在特定应用场景下,本文的内容属于基本功或者能帮助您节约大量的时间。
  • 本文主要为 Linux 所写,但在仅限 OS X 系统章节和仅限 Windows 系统章节中也包含有对应操作系统的内容。除去这两个章节外,其它的内容大部分均可在其他类 Unix 系统或 OS X,甚至 Cygwin 中得到应用。
  • 本文主要关注于交互式 Bash,但也有很多技巧可以应用于其他 shell 和 Bash 脚本当中。
  • 除去“标准的”Unix 命令,本文还包括了一些依赖于特定软件包的命令(前提是它们具有足够的价值)。

注意事项:

  • 为了能在一页内展示尽量多的东西,一些具体的信息可以在引用的页面中找到。我们相信机智的你知道如何使用 Google 或者其他搜索引擎来查阅到更多的详细信息。文中部分命令需要您使用 apt-getyumdnfpacman, +pipbrew(以及其它合适的包管理器)来安装依赖的程序。
  • 遇到问题的话,请尝试使用 Explainshell (opens new window) 去获取相关命令、参数、管道等内容的解释。

# 基础

  • 学习 Bash 的基础知识。具体地,在命令行中输入 man bash 并至少全文浏览一遍; 它理解起来很简单并且不冗长。其他的 shell 可能很好用,但 Bash 的功能已经足够强大并且到几乎总是可用的( 如果你学习 zsh,fish 或其他的 shell 的话,在你自己的设备上会显得很方便,但过度依赖这些功能会给您带来不便,例如当你需要在服务器上工作时)。

  • 熟悉至少一个基于文本的编辑器。通常而言 Vim (vi) 会是你最好的选择,毕竟在终端中编辑文本时 Vim 是最好用的工具(甚至大部分情况下 Vim 要比 Emacs、大型 IDE 或是炫酷的编辑器更好用)。

  • 学会如何使用 man 命令去阅读文档。学会使用 apropos 去查找文档。知道有些命令并不对应可执行文件,而是在 Bash 内置好的,此时可以使用 helphelp -d 命令获取帮助信息。你可以用 type 命令 来判断这个命令到底是可执行文件、shell 内置命令还是别名。

  • 学会使用 >< 来重定向输出和输入,学会使用 | 来重定向管道。明白 > 会覆盖了输出文件而 >> 是在文件末添加。了解标准输出 stdout 和标准错误 stderr。

  • 学会使用通配符 * (或许再算上 ?[...]) 和引用以及引用中 '" 的区别(后文中有一些具体的例子)。

  • 熟悉 Bash 中的任务管理工具:&ctrl-zctrl-cjobsfgbgkill 等。

  • 学会使用 ssh 进行远程命令行登录,最好知道如何使用 ssh-agentssh-add 等命令来实现基础的无密码认证登录。

  • 学会基本的文件管理工具:lsls -l (了解 ls -l 中每一列代表的意义),lessheadtailtail -f (甚至 less +F),lnln -s (了解硬链接与软链接的区别),chownchmoddu (硬盘使用情况概述:du -hs *)。 关于文件系统的管理,学习 dfmountfdiskmkfslsblk。知道 inode 是什么(与 ls -idf -i 等命令相关)。

  • 学习基本的网络管理工具:ipifconfigdig

  • 学习并使用一种版本控制管理系统,例如 git

  • 熟悉正则表达式,学会使用 grepegrep,它们的参数中 -i-o-v-A-B-C 这些是很常用并值得认真学习的。

  • 学会使用 apt-getyumdnfpacman (具体使用哪个取决于你使用的 Linux 发行版)来查找和安装软件包。并确保你的环境中有 pip 来安装基于 Python 的命令行工具 (接下来提到的部分程序使用 pip 来安装会很方便)。

# 日常使用

  • 在 Bash 中,可以通过按 Tab 键实现自动补全参数,使用 ctrl-r 搜索命令行历史记录(按下按键之后,输入关键字便可以搜索,重复按下 ctrl-r 会向后查找匹配项,按下 Enter 键会执行当前匹配的命令,而按下右方向键会将匹配项放入当前行中,不会直接执行,以便做出修改)。

  • 在 Bash 中,可以按下 ctrl-w 删除你键入的最后一个单词,ctrl-u 可以删除行内光标所在位置之前的内容,alt-balt-f 可以以单词为单位移动光标,ctrl-a 可以将光标移至行首,ctrl-e 可以将光标移至行尾,ctrl-k 可以删除光标至行尾的所有内容,ctrl-l 可以清屏。键入 man readline 可以查看 Bash 中的默认快捷键。内容有很多,例如 alt-. 循环地移向前一个参数,而 alt-* 可以展开通配符。

  • 你喜欢的话,可以执行 set -o vi 来使用 vi 风格的快捷键,而执行 set -o emacs 可以把它改回来。

  • 为了便于编辑长命令,在设置你的默认编辑器后(例如 export EDITOR=vim),ctrl-x ctrl-e 会打开一个编辑器来编辑当前输入的命令。在 vi 风格下快捷键则是 escape-v

  • 键入 history 查看命令行历史记录,再用 !nn 是命令编号)就可以再次执行。其中有许多缩写,最有用的大概就是 !$, 它用于指代上次键入的参数,而 !! 可以指代上次键入的命令了(参考 man 页面中的“HISTORY EXPANSION”)。不过这些功能,你也可以通过快捷键 ctrl-ralt-. 来实现。

  • cd 命令可以切换工作路径,输入 cd \~ 可以进入 home 目录。要访问你的 home 目录中的文件,可以使用前缀 \~(例如 \~/.bashrc)。在 sh 脚本里则用环境变量 $HOME 指代 home 目录的路径。

  • 回到前一个工作路径:cd -

  • 如果你输入命令的时候中途改了主意,按下 alt-# 在行首添加 # 把它当做注释再按下回车执行(或者依次按下 ctrl-a#enter)。这样做的话,之后借助命令行历史记录,你可以很方便恢复你刚才输入到一半的命令。

  • 使用 xargs ( 或 parallel)。他们非常给力。注意到你可以控制每行参数个数(-L)和最大并行数(-P)。如果你不确定它们是否会按你想的那样工作,先使用 xargs echo 查看一下。此外,使用 -I{} 会很方便。例如:

      find . -name '*.py' | xargs grep some_function
+      cat hosts | xargs -I{} ssh root@{} hostname
+
  • pstree -p 以一种优雅的方式展示进程树。

  • 使用 pgreppkill 根据名字查找进程或发送信号(-f 参数通常有用)。

  • 了解你可以发往进程的信号的种类。比如,使用 kill -STOP [pid] 停止一个进程。使用 man 7 signal 查看详细列表。

  • 使用 nohupdisown 使一个后台进程持续运行。

  • 使用 netstat -lntpss -plat 检查哪些进程在监听端口(默认是检查 TCP 端口; 添加参数 -u 则检查 UDP 端口)或者 lsof -iTCP -sTCP:LISTEN -P -n (这也可以在 OS X 上运行)。

  • lsof 来查看开启的套接字和文件。

  • 使用 uptimew 来查看系统已经运行多长时间。

  • 使用 alias 来创建常用命令的快捷形式。例如:alias ll='ls -latr' 创建了一个新的命令别名 ll

  • 可以把别名、shell 选项和常用函数保存在 \~/.bashrc,具体看下这篇文章 (opens new window)。这样做的话你就可以在所有 shell 会话中使用你的设定。

  • 把环境变量的设定以及登陆时要执行的命令保存在 \~/.bash_profile。而对于从图形界面启动的 shell 和 cron 启动的 shell,则需要单独配置文件。

  • 要想在几台电脑中同步你的配置文件(例如 .bashrc.bash_profile),可以借助 Git。

  • 当变量和文件名中包含空格的时候要格外小心。Bash 变量要用引号括起来,比如 "$FOO"。尽量使用 -0-print0 选项以便用 NULL 来分隔文件名,例如 locate -0 pattern | xargs -0 ls -alfind / -print0 -type d | xargs -0 ls -al。如果 for 循环中循环访问的文件名含有空字符(空格、tab 等字符),只需用 IFS=$'\n' 把内部字段分隔符设为换行符。

  • 在 Bash 脚本中,使用 set -x 去调试输出(或者使用它的变体 set -v,它会记录原始输入,包括多余的参数和注释)。尽可能地使用严格模式:使用 set -e 令脚本在发生错误时退出而不是继续运行;使用 set -u 来检查是否使用了未赋值的变量;试试 set -o pipefail,它可以监测管道中的错误。当牵扯到很多脚本时,使用 trap 来检测 ERR 和 EXIT。一个好的习惯是在脚本文件开头这样写,这会使它能够检测一些错误,并在错误发生时中断程序并输出信息:

      set -euo pipefail
+      trap "echo 'error: Script failed: see failed command above'" ERR
+
  • 在 Bash 脚本中,子 shell(使用括号 (...))是一种组织参数的便捷方式。一个常见的例子是临时地移动工作路径,代码如下:
      # do something in current dir
+      (cd /some/other/dir && other-command)
+      # continue in original dir
+
  • 在 Bash 中,变量有许多的扩展方式。${name:?error message} 用于检查变量是否存在。此外,当 Bash 脚本只需要一个参数时,可以使用这样的代码 input_file=${1:?usage: $0 input_file}。在变量为空时使用默认值:${name:-default}。如果你要在之前的例子中再加一个(可选的)参数,可以使用类似这样的代码 output_file=${2:-logfile},如果省略了 $2,它的值就为空,于是 output_file 就会被设为 logfile。数学表达式:i=$(( (i + 1) % 5 ))。序列:{1..10}。截断字符串:${var%suffix}${var#prefix}。例如,假设 var=foo.pdf,那么 echo ${var%.pdf}.txt 将输出 foo.txt

  • 使用括号扩展({...})来减少输入相似文本,并自动化文本组合。这在某些情况下会很有用,例如 mv foo.{txt,pdf} some-dir(同时移动两个文件),cp somefile{,.bak}(会被扩展成 cp somefile somefile.bak)或者 mkdir -p test-{a,b,c}/subtest-{1,2,3}(会被扩展成所有可能的组合,并创建一个目录树)。

  • 通过使用 <(some command) 可以将输出视为文件。例如,对比本地文件 /etc/hosts 和一个远程文件:

      diff /etc/hosts <(ssh somehost cat /etc/hosts)
+
  • 编写脚本时,你可能会想要把代码都放在大括号里。缺少右括号的话,代码就会因为语法错误而无法执行。如果你的脚本是要放在网上分享供他人使用的,这样的写法就体现出它的好处了,因为这样可以防止下载不完全代码被执行。
{
+      # 在这里写代码
+}
+
  • 了解 Bash 中的“here documents”,例如 cat <<EOF ...

  • 在 Bash 中,同时重定向标准输出和标准错误:some-command >logfile 2>&1 或者 some-command &>logfile。通常,为了保证命令不会在标准输入里残留一个未关闭的文件句柄捆绑在你当前所在的终端上,在命令后添加 </dev/null 是一个好习惯。

  • 使用 man ascii 查看具有十六进制和十进制值的 ASCII 表。man unicodeman utf-8,以及 man latin1 有助于你去了解通用的编码信息。

  • 使用 screentmux (opens new window) 来使用多份屏幕,当你在使用 ssh 时(保存 session 信息)将尤为有用。而 byobu 可以为它们提供更多的信息和易用的管理工具。另一个轻量级的 session 持久化解决方案是 dtach (opens new window)

  • ssh 中,了解如何使用 -L-D(偶尔需要用 -R)开启隧道是非常有用的,比如当你需要从一台远程服务器上访问 web 页面。

  • 对 ssh 设置做一些小优化可能是很有用的,例如这个 \~/.ssh/config 文件包含了防止特定网络环境下连接断开、压缩数据、多通道等选项:

      TCPKeepAlive=yes
+      ServerAliveInterval=15
+      ServerAliveCountMax=6
+      Compression=yes
+      ControlMaster auto
+      ControlPath /tmp/%r@%h:%p
+      ControlPersist yes
+
  • 一些其他的关于 ssh 的选项是与安全相关的,应当小心翼翼的使用。例如你应当只能在可信任的网络中启用 StrictHostKeyChecking=noForwardAgent=yes

  • 考虑使用 mosh (opens new window) 作为 ssh 的替代品,它使用 UDP 协议。它可以避免连接被中断并且对带宽需求更小,但它需要在服务端做相应的配置。

  • 获取八进制形式的文件访问权限(修改系统设置时通常需要,但 ls 的功能不那么好用并且通常会搞砸),可以使用类似如下的代码:

      stat -c '%A %a %n' /etc/timezone
+
  • 使用 percol (opens new window) 或者 fzf (opens new window) 可以交互式地从另一个命令输出中选取值。

  • 使用 fppPathPicker (opens new window))可以与基于另一个命令(例如 git)输出的文件交互。

  • 将 web 服务器上当前目录下所有的文件(以及子目录)暴露给你所处网络的所有用户,使用: +python -m SimpleHTTPServer 7777 (使用端口 7777 和 Python 2)或python -m http.server 7777 (使用端口 7777 和 Python 3)。

  • 以其他用户的身份执行命令,使用 sudo。默认以 root 用户的身份执行;使用 -u 来指定其他用户。使用 -i 来以该用户登录(需要输入你自己的密码)。

  • 将 shell 切换为其他用户,使用 su username 或者 sudo - username。加入 - 会使得切换后的环境与使用该用户登录后的环境相同。省略用户名则默认为 root。切换到哪个用户,就需要输入哪个用户的密码。

  • 了解命令行的 128K 限制 (opens new window)。使用通配符匹配大量文件名时,常会遇到“Argument list too long”的错误信息。(这种情况下换用 findxargs 通常可以解决。)

  • 当你需要一个基本的计算器时,可以使用 python 解释器(当然你要用 python 的时候也是这样)。例如:

>>> 2+3
+5
+

# 文件及数据处理

  • 在当前目录下通过文件名查找一个文件,使用类似于这样的命令:find . -iname '*something*'。在所有路径下通过文件名查找文件,使用 locate something (但注意到 updatedb 可能没有对最近新建的文件建立索引,所以你可能无法定位到这些未被索引的文件)。

  • 使用 ag (opens new window) 在源代码或数据文件里检索(grep -r 同样可以做到,但相比之下 ag 更加先进)。

  • 将 HTML 转为文本:lynx -dump -stdin

  • Markdown,HTML,以及所有文档格式之间的转换,试试 pandoc (opens new window)

  • 当你要处理棘手的 XML 时候,xmlstarlet 算是上古时代流传下来的神器。

  • 使用 jq (opens new window) 处理 JSON。

  • 使用 shyaml (opens new window) 处理 YAML。

  • 要处理 Excel 或 CSV 文件的话,csvkit (opens new window) 提供了 in2csvcsvcutcsvjoincsvgrep 等方便易用的工具。

  • 当你要处理 Amazon S3 相关的工作的时候,s3cmd (opens new window) 是一个很方便的工具而 s4cmd (opens new window) 的效率更高。Amazon 官方提供的 aws (opens new window) 以及 saws (opens new window) 是其他 AWS 相关工作的基础,值得学习。

  • 了解如何使用 sortuniq,包括 uniq 的 -u 参数和 -d 参数,具体内容在后文单行脚本节中。另外可以了解一下 comm

  • 了解如何使用 cutpastejoin 来更改文件。很多人都会使用 cut,但遗忘了 join

  • 了解如何运用 wc 去计算新行数(-l),字符数(-m),单词数(-w)以及字节数(-c)。

  • 了解如何使用 tee 将标准输入复制到文件甚至标准输出,例如 ls -al | tee file.txt

  • 要进行一些复杂的计算,比如分组、逆序和一些其他的统计分析,可以考虑使用 datamash (opens new window)

  • 注意到语言设置(中文或英文等)对许多命令行工具有一些微妙的影响,比如排序的顺序和性能。大多数 Linux 的安装过程会将 LANG 或其他有关的变量设置为符合本地的设置。要意识到当你改变语言设置时,排序的结果可能会改变。明白国际化可能会使 sort 或其他命令运行效率下降许多倍。某些情况下(例如集合运算)你可以放心的使用 export LC_ALL=C 来忽略掉国际化并按照字节来判断顺序。

  • 你可以单独指定某一条命令的环境,只需在调用时把环境变量设定放在命令的前面,例如 TZ=Pacific/Fiji date 可以获取斐济的时间。

  • 了解如何使用 awksed 来进行简单的数据处理。 参阅 One-liners 获取示例。

  • 替换一个或多个文件中出现的字符串:

      perl -pi.bak -e 's/old-string/new-string/g' my-files-*.txt
+
  • 使用 repren (opens new window) 来批量重命名文件,或是在多个文件中搜索替换内容。(有些时候 rename 命令也可以批量重命名,但要注意,它在不同 Linux 发行版中的功能并不完全一样。)
      # 将文件、目录和内容全部重命名 foo -> bar:
+      repren --full --preserve-case --from foo --to bar .
+      # 还原所有备份文件 whatever.bak -> whatever:
+      repren --renames --from '(.*)\.bak' --to '\1' *.bak
+      # 用 rename 实现上述功能(若可用):
+      rename 's/\.bak$//' *.bak
+
  • 根据 man 页面的描述,rsync 是一个快速且非常灵活的文件复制工具。它闻名于设备之间的文件同步,但其实它在本地情况下也同样有用。在安全设置允许下,用 rsync 代替 scp 可以实现文件续传,而不用重新从头开始。它同时也是删除大量文件的最快方法 (opens new window)之一:
mkdir empty && rsync -r --delete empty/ some-dir && rmdir some-dir
+
  • 若要在复制文件时获取当前进度,可使用 pvpycp (opens new window)progress (opens new window)rsync --progress。若所执行的复制为 block 块拷贝,可以使用 dd status=progress

  • 使用 shuf 可以以行为单位来打乱文件的内容或从一个文件中随机选取多行。

  • 了解 sort 的参数。显示数字时,使用 -n 或者 -h 来显示更易读的数(例如 du -h 的输出)。明白排序时关键字的工作原理(-t-k)。例如,注意到你需要 -k1,1 来仅按第一个域来排序,而 -k1 意味着按整行排序。稳定排序(sort -s)在某些情况下很有用。例如,以第二个域为主关键字,第一个域为次关键字进行排序,你可以使用 sort -k1,1 | sort -s -k2,2

  • 如果你想在 Bash 命令行中写 tab 制表符,按下 ctrl-v [Tab] 或键入 $'\t' (后者可能更好,因为你可以复制粘贴它)。

  • 标准的源代码对比及合并工具是 diffpatch。使用 diffstat 查看变更总览数据。注意到 diff -r 对整个文件夹有效。使用 diff -r tree1 tree2 | diffstat 查看变更的统计数据。vimdiff 用于比对并编辑文件。

  • 对于二进制文件,使用 hdhexdump 或者 xxd 使其以十六进制显示,使用 bvihexedit 或者 biew 来进行二进制编辑。

  • 同样对于二进制文件,strings(包括 grep 等工具)可以帮助在二进制文件中查找特定比特。

  • 制作二进制差分文件(Delta 压缩),使用 xdelta3

  • 使用 iconv 更改文本编码。需要更高级的功能,可以使用 uconv,它支持一些高级的 Unicode 功能。例如,这条命令移除了所有重音符号:

      uconv -f utf-8 -t utf-8 -x '::Any-Lower; ::Any-NFD; [:Nonspacing Mark:] >; ::Any-NFC; ' < input.txt > output.txt
+
  • 拆分文件可以使用 split(按大小拆分)和 csplit(按模式拆分)。

  • 操作日期和时间表达式,可以用 dateutils (opens new window) 中的 dateadddatediffstrptime 等工具。

  • 使用 zlesszmorezcatzgrep 对压缩过的文件进行操作。

  • 文件属性可以通过 chattr 进行设置,它比文件权限更加底层。例如,为了保护文件不被意外删除,可以使用不可修改标记:sudo chattr +i /critical/directory/or/file

  • 使用 getfaclsetfacl 以保存和恢复文件权限。例如:

   getfacl -R /some/path > permissions.txt
+   setfacl --restore=permissions.txt
+
  • 为了高效地创建空文件,请使用 truncate(创建稀疏文件 (opens new window)),fallocate(用于 ext4,xfs,btrf 和 ocfs2 文件系统),xfs_mkfile(适用于几乎所有的文件系统,包含在 xfsprogs 包中),mkfile(用于类 Unix 操作系统,比如 Solaris 和 Mac OS)。

# 系统调试

  • curlcurl -I 可以被轻松地应用于 web 调试中,它们的好兄弟 wget 也是如此,或者也可以试试更潮的 httpie (opens new window)

  • 获取 CPU 和硬盘的使用状态,通常使用使用 tophtop 更佳),iostatiotop。而 iostat -mxz 15 可以让你获悉 CPU 和每个硬盘分区的基本信息和性能表现。

  • 使用 netstatss 查看网络连接的细节。

  • dstat 在你想要对系统的现状有一个粗略的认识时是非常有用的。然而若要对系统有一个深度的总体认识,使用 glances (opens new window),它会在一个终端窗口中向你提供一些系统级的数据。

  • 若要了解内存状态,运行并理解 freevmstat 的输出。值得留意的是“cached”的值,它指的是 Linux 内核用来作为文件缓存的内存大小,而与空闲内存无关。

  • Java 系统调试则是一件截然不同的事,一个可以用于 Oracle 的 JVM 或其他 JVM 上的调试的技巧是你可以运行 kill -3 <pid> 同时一个完整的栈轨迹和堆概述(包括 GC 的细节)会被保存到标准错误或是日志文件。JDK 中的 jpsjstatjstackjmap 很有用。SJK tools (opens new window) 更高级。

  • 使用 mtr (opens new window) 去跟踪路由,用于确定网络问题。

  • ncdu (opens new window) 来查看磁盘使用情况,它比寻常的命令,如 du -sh *,更节省时间。

  • 查找正在使用带宽的套接字连接或进程,使用 iftop (opens new window)nethogs (opens new window)

  • ab 工具(Apache 中自带)可以简单粗暴地检查 web 服务器的性能。对于更复杂的负载测试,使用 siege

  • wireshark (opens new window)tshark (opens new window)ngrep (opens new window) 可用于复杂的网络调试。

  • 了解 straceltrace。这俩工具在你的程序运行失败、挂起甚至崩溃,而你却不知道为什么或你想对性能有个总体的认识的时候是非常有用的。注意 profile 参数(-c)和附加到一个运行的进程参数 (-p)。

  • 了解使用 ldd 来检查共享库。但是永远不要在不信任的文件上运行 (opens new window)

  • 了解如何运用 gdb 连接到一个运行着的进程并获取它的堆栈轨迹。

  • 学会使用 /proc。它在调试正在出现的问题的时候有时会效果惊人。比如:/proc/cpuinfo/proc/meminfo/proc/cmdline/proc/xxx/cwd/proc/xxx/exe/proc/xxx/fd//proc/xxx/smaps(这里的 xxx 表示进程的 id 或 pid)。

  • 当调试一些之前出现的问题的时候,sar (opens new window) 非常有用。它展示了 cpu、内存以及网络等的历史数据。

  • 关于更深层次的系统分析以及性能分析,看看 stapSystemTap (opens new window)),perf (opens new window),以及sysdig (opens new window)

  • 查看你当前使用的系统,使用 unameuname -a(Unix/kernel 信息)或者 lsb_release -a(Linux 发行版信息)。

  • 无论什么东西工作得很欢乐(可能是硬件或驱动问题)时可以试试 dmesg

  • 如果你删除了一个文件,但通过 du 发现没有释放预期的磁盘空间,请检查文件是否被进程占用: +lsof | grep deleted | grep "filename-of-my-big-file"

# 单行脚本

一些命令组合的例子:

  • 当你需要对文本文件做集合交、并、差运算时,sortuniq 会是你的好帮手。具体例子请参照代码后面的,此处假设 ab 是两内容不同的文件。这种方式效率很高,并且在小文件和上 G 的文件上都能运用(注意尽管在 /tmp 在一个小的根分区上时你可能需要 -T 参数,但是实际上 sort 并不被内存大小约束),参阅前文中关于 LC_ALLsort-u 参数的部分。
      sort a b | uniq > c   # c 是 a 并 b
+      sort a b | uniq -d > c   # c 是 a 交 b
+      sort a b b | uniq -u > c   # c 是 a - b
+
  • 使用 grep . *(每行都会附上文件名)或者 head -100 *(每个文件有一个标题)来阅读检查目录下所有文件的内容。这在检查一个充满配置文件的目录(如 /sys/proc/etc)时特别好用。
  • 计算文本文件第三列中所有数的和(可能比同等作用的 Python 代码快三倍且代码量少三倍):
      awk '{ x += $3 } END { print x }' myfile
+
  • 如果你想在文件树上查看大小/日期,这可能看起来像递归版的 ls -l 但比 ls -lR 更易于理解:
      find . -type f -ls
+
  • 假设你有一个类似于 web 服务器日志文件的文本文件,并且一个确定的值只会出现在某些行上,假设一个 acct_id 参数在 URI 中。如果你想计算出每个 acct_id 值有多少次请求,使用如下代码:
      egrep -o 'acct_id=[0-9]+' access.log | cut -d= -f2 | sort | uniq -c | sort -rn
+
  • 要持续监测文件改动,可以使用 watch,例如检查某个文件夹中文件的改变,可以用 watch -d -n 2 'ls -rtlh | tail';或者在排查 WiFi 设置故障时要监测网络设置的更改,可以用 watch -d -n 2 ifconfig

  • 运行这个函数从这篇文档中随机获取一条技巧(解析 Markdown 文件并抽取项目):

      function taocl() {
+        curl -s https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/README-zh.md|
+          pandoc -f markdown -t html |
+          iconv -f 'utf-8' -t 'unicode' |
+          xmlstarlet fo --html --dropdtd |
+          xmlstarlet sel -t -v "(html/body/ul/li[count(p)>0])[$RANDOM mod last()+1]" |
+          xmlstarlet unesc | fmt -80
+      }
+

# 冷门但有用

  • expr:计算表达式或正则匹配

  • m4:简单的宏处理器

  • yes:多次打印字符串

  • cal:漂亮的日历

  • env:执行一个命令(脚本文件中很有用)

  • printenv:打印环境变量(调试时或在写脚本文件时很有用)

  • look:查找以特定字符串开头的单词或行

  • cutpastejoin:数据修改

  • fmt:格式化文本段落

  • pr:将文本格式化成页/列形式

  • fold:包裹文本中的几行

  • column:将文本格式化成多个对齐、定宽的列或表格

  • expandunexpand:制表符与空格之间转换

  • nl:添加行号

  • seq:打印数字

  • bc:计算器

  • factor:分解因数

  • gpg (opens new window):加密并签名文件

  • toe:terminfo 入口列表

  • nc:网络调试及数据传输

  • socat:套接字代理,与 netcat 类似

  • slurm (opens new window):网络流量可视化

  • dd:文件或设备间传输数据

  • file:确定文件类型

  • tree:以树的形式显示路径和文件,类似于递归的 ls

  • stat:文件信息

  • time:执行命令,并计算执行时间

  • timeout:在指定时长范围内执行命令,并在规定时间结束后停止进程

  • lockfile:使文件只能通过 rm -f 移除

  • logrotate: 切换、压缩以及发送日志文件

  • watch:重复运行同一个命令,展示结果并/或高亮有更改的部分

  • when-changed (opens new window):当检测到文件更改时执行指定命令。参阅 inotifywaitentr

  • tac:反向输出文件

  • shuf:文件中随机选取几行

  • comm:一行一行的比较排序过的文件

  • strings:从二进制文件中抽取文本

  • tr:转换字母

  • iconvuconv:文本编码转换

  • splitcsplit:分割文件

  • sponge:在写入前读取所有输入,在读取文件后再向同一文件写入时比较有用,例如 grep -v something some-file | sponge some-file

  • units:将一种计量单位转换为另一种等效的计量单位(参阅 /usr/share/units/definitions.units

  • apg:随机生成密码

  • xz:高比例的文件压缩

  • ldd:动态库信息

  • nm:提取 obj 文件中的符号

  • abwrk (opens new window):web 服务器性能分析

  • strace:调试系统调用

  • mtr (opens new window):更好的网络调试跟踪工具

  • cssh:可视化的并发 shell

  • rsync:通过 ssh 或本地文件系统同步文件和文件夹

  • wireshark (opens new window)tshark (opens new window):抓包和网络调试工具

  • ngrep (opens new window):网络层的 grep

  • hostdig:DNS 查找

  • lsof:列出当前系统打开文件的工具以及查看端口信息

  • dstat:系统状态查看

  • glances (opens new window):高层次的多子系统总览

  • iostat:硬盘使用状态

  • mpstat: CPU 使用状态

  • vmstat: 内存使用状态

  • htop:top 的加强版

  • last:登入记录

  • w:查看处于登录状态的用户

  • id:用户/组 ID 信息

  • sar (opens new window):系统历史数据

  • iftop (opens new window)nethogs (opens new window):套接字及进程的网络利用情况

  • ss:套接字数据

  • dmesg:引导及系统错误信息

  • sysctl: 在内核运行时动态地查看和修改内核的运行参数

  • hdparm:SATA/ATA 磁盘更改及性能分析

  • lsblk:列出块设备信息:以树形展示你的磁盘以及磁盘分区信息

  • lshwlscpulspcilsusbdmidecode:查看硬件信息,包括 CPU、BIOS、RAID、显卡、USB 设备等

  • lsmodmodinfo:列出内核模块,并显示其细节

  • fortuneddatesl:额,这主要取决于你是否认为蒸汽火车和莫名其妙的名人名言是否“有用”

# 仅限 OS X 系统

以下是仅限于 OS X 系统的技巧。

  • brew (Homebrew)或者 port (MacPorts)进行包管理。这些可以用来在 OS X 系统上安装以上的大多数命令。

  • pbcopy 复制任何命令的输出到桌面应用,用 pbpaste 粘贴输入。

  • 若要在 OS X 终端中将 Option 键视为 alt 键(例如在上面介绍的 alt-balt-f 等命令中用到),打开 偏好设置 -> 描述文件 -> 键盘 并勾选“使用 Option 键作为 Meta 键”。

  • open 或者 open -a /Applications/Whatever.app 使用桌面应用打开文件。

  • Spotlight:用 mdfind 搜索文件,用 mdls 列出元数据(例如照片的 EXIF 信息)。

  • 注意 OS X 系统是基于 BSD UNIX 的,许多命令(例如 pslstailawksed)都和 Linux 中有微妙的不同( Linux 很大程度上受到了 System V-style Unix 和 GNU 工具影响)。你可以通过标题为 "BSD General Commands Manual" 的 man 页面发现这些不同。在有些情况下 GNU 版本的命令也可能被安装(例如 gawkgsed 对应 GNU 中的 awk 和 sed )。如果要写跨平台的 Bash 脚本,避免使用这些命令(例如,考虑 Python 或者 perl )或者经过仔细的测试。

  • sw_vers 获取 OS X 的版本信息。

# 仅限 Windows 系统

以下是仅限于 Windows 系统的技巧。

# 在 Winodws 下获取 Unix 工具

  • 可以安装 Cygwin (opens new window) 允许你在 Microsoft Windows 中体验 Unix shell 的威力。这样的话,本文中介绍的大多数内容都将适用。

  • 在 Windows 10 上,你可以使用 Bash on Ubuntu on Windows (opens new window),它提供了一个熟悉的 Bash 环境,包含了不少 Unix 命令行工具。好处是它允许 Linux 上编写的程序在 Windows 上运行,而另一方面,Windows 上编写的程序却无法在 Bash 命令行中运行。

  • 如果你在 Windows 上主要想用 GNU 开发者工具(例如 GCC),可以考虑 MinGW (opens new window) 以及它的 MSYS (opens new window) 包,这个包提供了例如 bash,gawk,make 和 grep 的工具。MSYS 并不包含所有可以与 Cygwin 媲美的特性。当制作 Unix 工具的原生 Windows 端口时 MinGW 将特别地有用。

  • 另一个在 Windows 下实现接近 Unix 环境外观效果的选项是 Cash (opens new window)。注意在此环境下只有很少的 Unix 命令和命令行可用。

# 实用 Windows 命令行工具

  • 可以使用 wmic 在命令行环境下给大部分 Windows 系统管理任务编写脚本以及执行这些任务。

  • Windows 实用的原生命令行网络工具包括 pingipconfigtracert,和 netstat

  • 可以使用 Rundll32 命令来实现许多有用的 Windows 任务 (opens new window)

# Cygwin 技巧

  • 通过 Cygwin 的包管理器来安装额外的 Unix 程序。

  • 使用 mintty 作为你的命令行窗口。

  • 要访问 Windows 剪贴板,可以通过 /dev/clipboard

  • 运行 cygstart 以通过默认程序打开一个文件。

  • 要访问 Windows 注册表,可以使用 regtool

  • 注意 Windows 驱动器路径 C:\ 在 Cygwin 中用 /cygdrive/c 代表,而 Cygwin 的 / 代表 Windows 中的 C:\cygwin。要转换 Cygwin 和 Windows 风格的路径可以用 cygpath。这在需要调用 Windows 程序的脚本里很有用。

  • 学会使用 wmic,你就可以从命令行执行大多数 Windows 系统管理任务,并编成脚本。

  • 要在 Windows 下获得 Unix 的界面和体验,另一个办法是使用 Cash (opens new window)。需要注意的是,这个环境支持的 Unix 命令和命令行参数非常少。

  • 要在 Windows 上获取 GNU 开发者工具(比如 GCC)的另一个办法是使用 MinGW (opens new window) 以及它的 MSYS (opens new window) 软件包,该软件包提供了 bash、gawk、make、grep 等工具。然而 MSYS 提供的功能没有 Cygwin 完善。MinGW 在创建 Unix 工具的 Windows 原生移植方面非常有用。

# 更多资源

# 免责声明

除去特别小的工作,你编写的代码应当方便他人阅读。能力往往伴随着责任,你 有能力 在 Bash 中玩一些奇技淫巧并不意味着你应该去做!😉

# 授权条款

img

本文使用授权协议 Creative Commons Attribution-ShareAlike 4.0 International License (opens new window)

+ + + diff --git a/linux/expect.html b/linux/expect.html new file mode 100644 index 0000000..00936b0 --- /dev/null +++ b/linux/expect.html @@ -0,0 +1,130 @@ + + + + + + expect shell 脚本 | LINUX-TUTORIAL + + + + + + + + +

# expect shell 脚本

# expect 简介

expect 是一个自动化交互套件,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信。

在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用 expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是 expect

expect 自动交互流程:

  1. spawn 启动指定进程
  2. expect 获取指定关键字
  3. send 向指定程序发送指定字符
  4. 执行完成退出

# expect 安装

# yum 安装

执行命令:

yum -y install expect
+

# 手动安装

expect 依赖 tcl,所以需要先安装 tcl:

wget https://nchc.dl.sourceforge.net/project/tcl/Tcl/8.6.9/tcl8.6.9-src.tar.gz
+tar xf tcl8.6.9-src.tar.gz
+cd tcl8.6.9/unix/
+./configure && make && sudo make install
+

再安装 expect:

wget https://nchc.dl.sourceforge.net/project/expect/Expect/5.45.4/expect5.45.4.tar.gz
+tar xf expect5.45.4.tar.gz
+cd ./expect5.45.4
+./configure && make && sudo make install
+

# expect 参数

启用选项:

  • -c - 执行脚本前先执行的命令,可多次使用。
  • -d - debug 模式,可以在运行时输出一些诊断信息,与在脚本开始处使用 exp_internal 1 相似。
  • -D - 启用交换调式器,可设一整数参数。
  • -f - 从文件读取命令,仅用于使用 #! 时。如果文件名为 -,则从 stdin 读取(使用 ./- 从文件名为-的文件读取)。
  • -i - 交互式输入命令,使用 exitEOF 退出输入状态。
  • -- - 标示选项结束(如果你需要传递与 expect 选项相似的参数给脚本时),可放到 #! 行: #!/usr/bin/expect --
  • -v - 显示 expect 版本信息。

# expect 命令

  • spawn - 命令用来启动新的进程,spawn后的sendexpect命令都是和使用spawn打开的进程进行交互。
  • expect - 获取匹配信息,匹配成功则执行 expect 后面的程序动作。 +
    • exp_continue - 在 expect 中多次匹配就需要用到。
  • send - 命令接收一个字符串参数,并将该参数发送到进程。 +
    • send exp_send - 用于发送指定的字符串信息。
  • interact - 命令用的其实不是很多,一般情况下使用spawnsendexpect命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。比如我们使用spawnsendexpect命令完成了 ftp 登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在 ftp 命令行状态,以便手动的执行后续命令,此时使用interact命令就可以很好的完成这个任务。
  • send_user - 用来打印输出 相当于 shell 中的 echo
  • set - 定义变量。 +
    • set timeout - 设置超时时间。
  • puts - 输出变量。
  • exit - 退出 expect 脚本
  • eof - expect 执行结束,退出。

# 示例场景

远程登录

(1)ssh 登录远程主机执行命令,执行方法 expect 1.sh 或者 source 1.sh

#!/usr/bin/expect
+
+spawn ssh saneri@192.168.56.103 df -Th
+expect "*password"
+send "123456\n"
+expect eof
+

(2)ssh 远程登录主机执行命令,在 shell 脚本中执行 expect 命令,执行方法 sh 2.sh、bash 2.sh 或./2.sh 都可以执行.

#!/bin/bash
+
+passwd='123456'
+
+/usr/bin/expect <<-EOF
+
+set time 30
+spawn ssh saneri@192.168.56.103 df -Th
+expect {
+"*yes/no" { send "yes\r"; exp_continue }
+"*password:" { send "$passwd\r" }
+}
+expect eof
+EOF
+

(3)expect 执行多条命令

#!/usr/bin/expect -f
+
+set timeout 10
+
+spawn sudo su - root
+expect "*password*"
+send "123456\r"
+expect "#*"
+send "ls\r"
+expect "#*"
+send "df -Th\r"
+send "exit\r"
+expect eof
+

(4)创建 ssh key,将 id_rsa 和 id_rsa.pub 文件分发到各台主机上面。

#!/bin/bash
+
+# 判断id_rsa密钥文件是否存在
+if [ ! -f ~/.ssh/id_rsa ];then
+ ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
+else
+ echo "id_rsa has created ..."
+fi
+
+#分发到各个节点,这里分发到host文件中的主机中.
+while read line
+  do
+    user=`echo $line | cut -d " " -f 2`
+    ip=`echo $line | cut -d " " -f 1`
+    passwd=`echo $line | cut -d " " -f 3`
+
+    expect <<EOF
+      set timeout 10
+      spawn ssh-copy-id $user@$ip
+      expect {
+        "yes/no" { send "yes\n";exp_continue }
+        "password" { send "$passwd\n" }
+      }
+     expect "password" { send "$passwd\n" }
+EOF
+  done <  hosts
+

(5)shell 调用 expect 执行多行命令.

#!/bin/bash
+ip=$1
+user=$2
+password=$3
+
+expect <<EOF
+    set timeout 10
+    spawn ssh $user@$ip
+    expect {
+        "yes/no" { send "yes\n";exp_continue }
+        "password" { send "$password\n" }
+    }
+    expect "]#" { send "useradd hehe\n" }
+    expect "]#" { send "touch /tmp/test.txt\n" }
+    expect "]#" { send "exit\n" } expect eof
+ EOF
+ #./ssh5.sh 192.168.1.10 root 123456
+

# 参考资料

+ + + diff --git a/linux/ops/crontab.html b/linux/ops/crontab.html new file mode 100644 index 0000000..3da4f94 --- /dev/null +++ b/linux/ops/crontab.html @@ -0,0 +1,81 @@ + + + + + + 定时任务 - crontab | LINUX-TUTORIAL + + + + + + + + +

# 定时任务 - crontab

环境:CentOS

通过 crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script 脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。这个命令非常适合周期性的日志分析或数据备份等工作。

# crond 服务

Linux 通过 crond 服务来支持 crontab。

# 检查 crond 服务

使用 systemctl list-unit-files 命令确认 crond 服务是否已安装。

$ systemctl list-unit-files | grep crond
+crond.service                               enabled
+

如果为 enabled,表示服务正运行。

# crond 服务命令

开机自动启动 crond 服务:chkconfig crond on

或者,按以下命令手动启动:

systemctl enable crond.service  # 开启服务(开机自动启动服务)
+systemctl disable crond.service # 关闭服务(开机不会自动启动服务)
+systemctl start crond.service   # 启动服务
+systemctl stop crond.service    # 停止服务
+systemctl restart crond.service # 重启服务
+systemctl reload crond.service  # 重新载入配置
+systemctl status crond.service  # 查看服务状态
+

# crontab

# crontab 命令

crontab 命令格式如下:

crontab [-u user] file crontab [-u user] [ -e | -l | -r ]
+

说明:

  • -u user:用来设定某个用户的 crontab 服务;
  • file:file 是命令文件的名字,表示将 file 做为 crontab 的任务列表文件并载入 crontab。如果在命令行中没有指定这个文件,crontab 命令将接受标准输入(键盘)上键入的命令,并将它们载入 crontab。
  • -e:编辑某个用户的 crontab 文件内容。如果不指定用户,则表示编辑当前用户的 crontab 文件。
  • -l:显示某个用户的 crontab 文件内容,如果不指定用户,则表示显示当前用户的 crontab 文件内容。
  • -r:从/var/spool/cron 目录中删除某个用户的 crontab 文件,如果不指定用户,则默认删除当前用户的 crontab 文件。
  • -i:在删除用户的 crontab 文件时给确认提示。

有两种方法写入定时任务:

  • 在命令行输入:crontab -e 然后添加相应的任务,存盘退出。
  • 直接编辑 /etc/crontab 文件,即 vi /etc/crontab,添加相应的任务。

# crontab 文件

crontab 要执行的定时任务都被保存在 /etc/crontab 文件中。

crontab 的文件格式如下:

img

# 标准字段

逗号用于分隔列表。例如,在第 5 个字段(星期几)中使用 MON,WED,FRI 表示周一、周三和周五。

连字符定义范围。例如,2000-2010 表示 2000 年至 2010 年期间的每年,包括 2000 年和 2010 年。

除非用反斜杠()转义,否则命令中的**百分号(%)**会被替换成换行符,第一个百分号后面的所有数据都会作为标准输入发送给命令。

字段 是否必填 允许值 允许特殊字符
Minutes 0–59 *,-
Hours 0–23 *,-
Day of month 1–31 *,-
Month 1–12 or JAN–DEC *,-
Day of week 0–6 or SUN–SAT *,-

/etc/crontab 文件示例:

SHELL=/bin/bash
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+MAILTO=root
+
+# For details see man 4 crontabs
+
+# Example of job definition:
+# .---------------- minute (0 - 59)
+# |  .------------- hour (0 - 23)
+# |  |  .---------- day of month (1 - 31)
+# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
+# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
+# |  |  |  |  |
+# *  *  *  *  * user-name  command to be executed
+
+# 每两个小时以root身份执行 /home/hello.sh 脚本
+0 */2 * * * root /home/hello.sh
+

# crontab 实例

# 实例 1:每 1 分钟执行一次 myCommand

* * * * * myCommand
+

# 实例 2:每小时的第 3 和第 15 分钟执行

3,15 * * * * myCommand
+

# 实例 3:在上午 8 点到 11 点的第 3 和第 15 分钟执行

3,15 8-11 * * * myCommand
+

# 实例 4:每隔两天的上午 8 点到 11 点的第 3 和第 15 分钟执行

3,15 8-11 */2  *  * myCommand
+

# 实例 5:每周一上午 8 点到 11 点的第 3 和第 15 分钟执行

3,15 8-11 * * 1 myCommand
+

# 实例 6:每晚的 21:30 重启 smb

30 21 * * * /etc/init.d/smb restart
+

# 实例 7:每月 1、10、22 日的 4 : 45 重启 smb

45 4 1,10,22 * * /etc/init.d/smb restart
+

# 实例 8:每周六、周日的 1 : 10 重启 smb

10 1 * * 6,0 /etc/init.d/smb restart
+

# 实例 9:每天 18 : 00 至 23 : 00 之间每隔 30 分钟重启 smb

0,30 18-23 * * * /etc/init.d/smb restart
+

# 实例 10:每星期六的晚上 11 : 00 pm 重启 smb

0 23 * * 6 /etc/init.d/smb restart
+

# 实例 11:每一小时重启 smb

* */1 * * * /etc/init.d/smb restart
+

# 实例 12:晚上 11 点到早上 7 点之间,每隔一小时重启 smb

0 23-7 * * * /etc/init.d/smb restart
+

# 参考资料

+ + + diff --git a/linux/ops/firewalld.html b/linux/ops/firewalld.html new file mode 100644 index 0000000..14f1f16 --- /dev/null +++ b/linux/ops/firewalld.html @@ -0,0 +1,63 @@ + + + + + + 防火墙 - Firewalld | LINUX-TUTORIAL + + + + + + + + +

# 防火墙 - Firewalld

# 一、firewalld 服务命令

systemctl enable firewalld.service  # 开启服务(开机自动启动服务)
+systemctl disable firewalld.service # 关闭服务(开机不会自动启动服务)
+systemctl start firewalld.service   # 启动服务
+systemctl stop firewalld.service    # 停止服务
+systemctl restart firewalld.service # 重启服务
+systemctl reload firewalld.service  # 重新载入配置
+systemctl status firewalld.service  # 查看服务状态
+

# 二、firewall-cmd 命令

firewall-cmd 命令用于配置防火墙。

firewall-cmd --version                    # 查看版本
+firewall-cmd --help                       # 查看帮助
+firewall-cmd --state                      # 显示状态
+firewall-cmd --reload                     # 更新防火墙规则
+firewall-cmd --get-active-zones           # 查看区域信息
+firewall-cmd --get-zone-of-interface=eth0 # 查看指定接口所属区域
+firewall-cmd --panic-on                   # 拒绝所有包
+firewall-cmd --panic-off                  # 取消拒绝状态
+firewall-cmd --query-panic                # 查看是否拒绝
+
+firewall-cmd --zone=public --list-ports   # 查看所有打开的端口
+firewall-cmd --zone=public --query-port=80/tcp # 查看是否有开放的 80 TCP 端口
+firewall-cmd --zone=public --add-port=8080/tcp --permanent # 添加开放端口(--permanent永久生效,没有此参数重启后失效)
+firewall-cmd --zone=public --remove-port=80/tcp --permanent # 永久删除开放的 80 TCP 端口
+

# 参考资料

+ + + diff --git a/linux/ops/index.html b/linux/ops/index.html new file mode 100644 index 0000000..0dee803 --- /dev/null +++ b/linux/ops/index.html @@ -0,0 +1,42 @@ + + + + + + Linux 系统运维 | LINUX-TUTORIAL + + + + + + + + + + + + diff --git a/linux/ops/iptables.html b/linux/ops/iptables.html new file mode 100644 index 0000000..b6e0dd1 --- /dev/null +++ b/linux/ops/iptables.html @@ -0,0 +1,127 @@ + + + + + + Iptables 应用 | LINUX-TUTORIAL + + + + + + + + +

# Iptables 应用

iptables 是一个配置 Linux 内核 防火墙 (opens new window) 的命令行工具,是 netfilter (opens new window) 项目的一部分。 可以直接配置,也可以通过许多前端和图形界面配置。

iptables 也经常代指该内核级防火墙。iptables 用于 ipv4 (opens new window)ip6tables 用于 ipv6 (opens new window)

nftables (opens new window) 已经包含在 Linux kernel 3.13 (opens new window) 中,以后会取代 iptables 成为主要的 Linux 防火墙工具。

环境:CentOS7

# 1. 简介

iptables 可以检测、修改、转发、重定向和丢弃 IPv4 数据包

过滤 IPv4 数据包的代码已经内置于内核中,并且按照不同的目的被组织成 的集合。 由一组预先定义的 组成,包含遍历顺序规则。每一条规则包含一个谓词的潜在匹配和相应的动作(称为 目标),如果谓词为真,该动作会被执行。也就是说条件匹配。

# 2. 安装 iptables

(1)禁用 firewalld

CentOS 7 上默认安装了 firewalld 作为防火墙,使用 iptables 建议关闭并禁用 firewalld。

systemctl stop firewalld
+systemctl disable firewalld
+

(2)安装 iptables

yum install -y iptables-services
+

(3)服务管理

  • 查看服务状态:systemctl status iptables
  • 启用服务:systemctl enable iptables
  • 禁用服务:systemctl disable iptables
  • 启动服务:systemctl start iptables
  • 重启服务:systemctl restart iptables
  • 关闭服务: systemctl stop iptables

# 3. 命令

基本语法:

iptables(选项)(参数)
+

基本选项说明:

参数 作用
-P 设置默认策略:iptables -P INPUT (DROP
-F 清空规则链
-L 查看规则链
-A 在规则链的末尾加入新规则
-I num 在规则链的头部加入新规则
-D num 删除某一条规则
-s 匹配来源地址 IP/MASK,加叹号"!"表示除这个 IP 外。
-d 匹配目标地址
-i 网卡名称 匹配从这块网卡流入的数据
-o 网卡名称 匹配从这块网卡流出的数据
-p 匹配协议,如 tcp,udp,icmp
--dport num 匹配目标端口号
--sport num 匹配来源端口号

顺序:

iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作
+

# 4. iptables 示例

# 4.1. 清空当前的所有规则和计数

iptables -F  # 清空所有的防火墙规则
+iptables -X  # 删除用户自定义的空链
+iptables -Z  # 清空计数
+

# 4.2. 配置允许 ssh 端口连接

iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
+# 22为你的ssh端口, -s 192.168.1.0/24表示允许这个网段的机器来连接,其它网段的ip地址是登陆不了你的机器的。 -j ACCEPT表示接受这样的请求
+

# 4.3. 允许本地回环地址可以正常使用

iptables -A INPUT -i lo -j ACCEPT
+#本地圆环地址就是那个127.0.0.1,是本机上使用的,它进与出都设置为允许
+iptables -A OUTPUT -o lo -j ACCEPT
+

# 4.4. 设置默认的规则

iptables -P INPUT DROP # 配置默认的不让进
+iptables -P FORWARD DROP # 默认的不允许转发
+iptables -P OUTPUT ACCEPT # 默认的可以出去
+

# 4.5. 配置白名单

iptables -A INPUT -p all -s 192.168.1.0/24 -j ACCEPT  # 允许机房内网机器可以访问
+iptables -A INPUT -p all -s 192.168.140.0/24 -j ACCEPT  # 允许机房内网机器可以访问
+iptables -A INPUT -p tcp -s 183.121.3.7 --dport 3380 -j ACCEPT # 允许183.121.3.7访问本机的3380端口
+

# 4.6. 开启相应的服务端口

iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 开启80端口,因为web对外都是这个端口
+iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT # 允许被ping
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 已经建立的连接得让它进来
+

# 4.7. 保存规则到配置文件中

cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak # 任何改动之前先备份,请保持这一优秀的习惯
+iptables-save > /etc/sysconfig/iptables
+cat /etc/sysconfig/iptables
+

# 4.8. 列出已设置的规则

iptables -L [-t 表名][链名]

  • 四个表名 rawnatfiltermangle
  • 五个规则链名 INPUTOUTPUTFORWARDPREROUTINGPOSTROUTING
  • filter 表包含INPUTOUTPUTFORWARD三个规则链
iptables -L -t nat                  # 列出 nat 上面的所有规则
+#            ^ -t 参数指定,必须是 raw, nat,filter,mangle 中的一个
+iptables -L -t nat  --line-numbers  # 规则带编号
+iptables -L INPUT
+
+iptables -L -nv  # 查看,这个列表看起来更详细
+

# 4.9. 清除已有规则

iptables -F INPUT  # 清空指定链 INPUT 上面的所有规则
+iptables -X INPUT  # 删除指定的链,这个链必须没有被其它任何规则引用,而且这条上必须没有任何规则。
+                   # 如果没有指定链名,则会删除该表中所有非内置的链。
+iptables -Z INPUT  # 把指定链,或者表中的所有链上的所有计数器清零。
+

# 4.10. 删除已添加的规则

# 添加一条规则
+iptables -A INPUT -s 192.168.1.5 -j DROP
+

将所有 iptables 以序号标记显示,执行:

iptables -L -n --line-numbers
+

比如要删除 INPUT 里序号为 8 的规则,执行:

iptables -D INPUT 8
+

# 4.11. 开放指定的端口

iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT               #允许本地回环接口(即运行本机访问本机)
+iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT    #允许已建立的或相关连的通行
+iptables -A OUTPUT -j ACCEPT         #允许所有本机向外的访问
+iptables -A INPUT -p tcp --dport 22 -j ACCEPT    #允许访问22端口
+iptables -A INPUT -p tcp --dport 80 -j ACCEPT    #允许访问80端口
+iptables -A INPUT -p tcp --dport 21 -j ACCEPT    #允许ftp服务的21端口
+iptables -A INPUT -p tcp --dport 20 -j ACCEPT    #允许FTP服务的20端口
+iptables -A INPUT -j reject       #禁止其他未允许的规则访问
+iptables -A FORWARD -j REJECT     #禁止其他未允许的规则访问
+

# 4.12. 屏蔽 IP

iptables -A INPUT -p tcp -m tcp -s 192.168.0.8 -j DROP  # 屏蔽恶意主机(比如,192.168.0.8
+iptables -I INPUT -s 123.45.6.7 -j DROP       #屏蔽单个IP的命令
+iptables -I INPUT -s 123.0.0.0/8 -j DROP      #封整个段即从123.0.0.1到123.255.255.254的命令
+iptables -I INPUT -s 124.45.0.0/16 -j DROP    #封IP段即从123.45.0.1到123.45.255.254的命令
+iptables -I INPUT -s 123.45.6.0/24 -j DROP    #封IP段即从123.45.6.1到123.45.6.254的命令是
+

# 4.13. 指定数据包出去的网络接口

只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。

iptables -A FORWARD -o eth0
+

# 4.14. 查看已添加的规则

iptables -L -n -v
+Chain INPUT (policy DROP 48106 packets, 2690K bytes)
+ pkts bytes target     prot opt in     out     source               destination
+ 5075  589K ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
+ 191K   90M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22
+1499K  133M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:80
+4364K 6351M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
+ 6256  327K ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0
+
+Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
+ pkts bytes target     prot opt in     out     source               destination
+
+Chain OUTPUT (policy ACCEPT 3382K packets, 1819M bytes)
+ pkts bytes target     prot opt in     out     source               destination
+ 5075  589K ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0
+

# 4.15. 启动网络转发规则

公网210.14.67.7让内网192.168.188.0/24上网

iptables -t nat -A POSTROUTING -s 192.168.188.0/24 -j SNAT --to-source 210.14.67.127
+

# 4.16. 端口映射

本机的 2222 端口映射到内网 虚拟机的 22 端口

iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222  -j DNAT --to-dest 192.168.188.115:22
+

# 4.17. 字符串匹配

比如,我们要过滤所有 TCP 连接中的字符串test,一旦出现它我们就终止这个连接,我们可以这么做:

iptables -A INPUT -p tcp -m string --algo kmp --string "test" -j REJECT --reject-with tcp-reset
+iptables -L
+
+# Chain INPUT (policy ACCEPT)
+# target     prot opt source               destination
+# REJECT     tcp  --  anywhere             anywhere            STRING match "test" ALGO name kmp TO 65535 reject-with tcp-reset
+#
+# Chain FORWARD (policy ACCEPT)
+# target     prot opt source               destination
+#
+# Chain OUTPUT (policy ACCEPT)
+# target     prot opt source               destination
+

# 4.18. 阻止 Windows 蠕虫的攻击

iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe"
+

# 4.19. 防止 SYN 洪水攻击

iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT
+

# 5. 参考资料

  • https://wiki.archlinux.org/index.php/iptables_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
  • https://wangchujiang.com/linux-command/c/iptables.html
+ + + diff --git a/linux/ops/network-ops.html b/linux/ops/network-ops.html new file mode 100644 index 0000000..93bc6b6 --- /dev/null +++ b/linux/ops/network-ops.html @@ -0,0 +1,87 @@ + + + + + + Linux 典型运维应用 | LINUX-TUTORIAL + + + + + + + + +

# Linux 典型运维应用

💡 如果没有特殊说明,本文的案例都是针对 Centos 发行版本。

# 网络操作

# 无法访问外网域名

(1)在 hosts 中添加本机实际 IP 和本机实际域名的映射

echo "192.168.0.1 hostname" >> /etc/hosts
+

如果不知道本机域名,使用 hostname 命令查一下;如果不知道本机实际 IP,使用 ifconfig 查一下。

(2)配置信赖的 DNS 服务器

执行 vi /etc/resolv.conf ,添加以下内容:

nameserver 114.114.114.114
+nameserver 8.8.8.8
+

114.114.114.114 是国内老牌 DNS

8.8.8.8 是 Google DNS

👉 参考:公共 DNS 哪家强 (opens new window)

(3)测试一下能否 ping 通 www.baidu.com

# 配置网卡

使用 root 权限编辑 /etc/sysconfig/network-scripts/ifcfg-eno16777736X 文件

参考以下进行配置:

TYPE=Ethernet                        # 网络类型:Ethernet以太网
+BOOTPROTO=none                       # 引导协议:自动获取、static静态、none不指定
+DEFROUTE=yes                         # 启动默认路由
+IPV4_FAILURE_FATAL=no                # 不启用IPV4错误检测功能
+IPV6INIT=yes                         # 启用IPV6协议
+IPV6_AUTOCONF=yes                    # 自动配置IPV6地址
+IPV6_DEFROUTE=yes                    # 启用IPV6默认路由
+IPV6_FAILURE_FATAL=no                # 不启用IPV6错误检测功能
+IPV6_PEERDNS=yes
+IPV6_PEERROUTES=yes
+IPV6_PRIVACY="no"
+
+NAME=eno16777736                     # 网卡设备的别名(需要和文件名同名)
+UUID=90528772-9967-46da-b401-f82b64b4acbc  # 网卡设备的UUID唯一标识号
+DEVICE=eno16777736                   # 网卡的设备名称
+ONBOOT=yes                           # 开机自动激活网卡
+IPADDR=192.168.1.199                 # 网卡的固定IP地址
+PREFIX=24                            # 子网掩码
+GATEWAY=192.168.1.1                  # 默认网关IP地址
+DNS1=8.8.8.8                         # DNS域名解析服务器的IP地址
+

修改完后,执行 systemctl restart network.service 重启网卡服务。

# 系统维护

# 自动化脚本

# Linux 开机自启动脚本

(1)在 /etc/rc.local 文件中添加命令

如果不想将脚本粘来粘去,或创建链接,可以在 /etc/rc.local 文件中添加启动命令

  1. 先修改好脚本,使其所有模块都能在任意目录启动时正常执行;
  2. 再在 /etc/rc.local 的末尾添加一行以绝对路径启动脚本的行;

例:

执行 vim /etc/rc.local 命令,输入以下内容:

#!/bin/sh
+#
+# This script will be executed *after* all the other init scripts.
+# You can put your own initialization stuff in here if you don't
+# want to do the full Sys V style init stuff.
+
+touch /var/lock/subsys/local
+/opt/pjt_test/test.pl
+

(2)在 /etc/rc.d/init.d 目录下添加自启动脚本

Linux 在 /etc/rc.d/init.d 下有很多的文件,每个文件都是可以看到内容的,其实都是一些 shell 脚本或者可执行二进制文件。

Linux 开机的时候,会加载运行 /etc/rc.d/init.d 目录下的程序,因此我们可以把想要自动运行的脚本放到这个目录下即可。系统服务的启动就是通过这种方式实现的。

(3)运行级别设置

简单的说,运行级就是操作系统当前正在运行的功能级别。

不同的运行级定义如下:
+# 0 - 停机(千万不能把initdefault 设置为0 )
+# 1 - 单用户模式         进入方法#init s = init 1
+# 2 - 多用户,没有 NFS
+# 3 - 完全多用户模式(标准的运行级)
+# 4 - 没有用到
+# 5 - X11 多用户图形模式(xwindow)
+# 6 - 重新启动 (千万不要把initdefault 设置为6 )
+

这些级别在 /etc/inittab 文件里指定,这个文件是 init 程序寻找的主要文件,最先运行的服务是放在/etc/rc.d 目录下的文件。

/etc 目录下面有这么几个目录值得注意:rcS.d rc0.d rc1.d ... rc6.d (0,1... 6 代表启动级别 0 代表停止,1 代表单用户模式,2-5 代表多用户模式,6 代表重启) 它们的作用就相当于 redhat 下的 rc.d ,你可以把脚本放到 rcS.d,然后修改文件名,给它一个启动序号,如: S88mysql

不过,最好的办法是放到相应的启动级别下面。具体作法:

(1)先把脚本 mysql 放到 /etc/init.d 目录下

(2)查看当前系统的启动级别

$ runlevel
+N 3
+

(3)设定启动级别

#  98 为启动序号
+#  2 是系统的运行级别,可自己调整,注意不要忘了结尾的句点
+$ update-rc.d mysql start 98 2 .
+

现在我们到 /etc/rc2.d 下,就多了一个 S98mysql 这样的符号链接。

(4)重启系统,验证设置是否有效。

(5)移除符号链接

当你需要移除这个符号连接时,方法有三种:

  1. 直接到 /etc/rc2.d 下删掉相应的链接,当然不是最好的方法;

  2. 推荐做法:update-rc.d -f s10 remove

  3. 如果 update-rc.d 命令你不熟悉,还可以试试看 rcconf 这个命令,也很方便。

👉 参考:

# 定时执行脚本

# 配置

# 设置 Linux 启动模式

  1. 停机(记得不要把 initdefault 配置为 0,因为这样会使 Linux 不能启动)
  2. 单用户模式,就像 Win9X 下的安全模式
  3. 多用户,但是没有 NFS
  4. 完全多用户模式,准则的运行级
  5. 通常不用,在一些特殊情况下可以用它来做一些事情
  6. X11,即进到 X-Window 系统
  7. 重新启动 (记得不要把 initdefault 配置为 6,因为这样会使 Linux 不断地重新启动)

设置方法:

sed -i 's/id:5:initdefault:/id:3:initdefault:/' /etc/inittab
+

# 参考资料

+ + + diff --git a/linux/ops/ntp.html b/linux/ops/ntp.html new file mode 100644 index 0000000..8caf5ca --- /dev/null +++ b/linux/ops/ntp.html @@ -0,0 +1,111 @@ + + + + + + 时间服务器 - NTP | LINUX-TUTORIAL + + + + + + + + +

# 时间服务器 - NTP

# 一、NTP 简介

网络时间协议(英语:Network Time Protocol,缩写:NTP)是在数据网络潜伏时间可变的计算机系统之间通过分组交换进行时钟同步的一个网络协议,位于 OSI 模型的应用层。自 1985 年以来,NTP 是目前仍在使用的最古老的互联网协议之一。NTP 由特拉华大学的 David L. Mills(英语:David L. Mills)设计。

NTP 意图将所有参与计算机的协调世界时(UTC)时间同步到几毫秒的误差内

NTP 要点:

  • 地球共有 24 个时区,而以格林威治时间 (GMT) 为标准时间;
  • 中国本地时间为 GMT +8 小时;
  • 最准确的时间为使用原子钟 (Atomic clock) 所计算的,例如 UTC (Coordinated Universal Time) 就是一例;
  • Linux 系统本来就有两种时间,一种是 Linux 以 1970/01/01 开始计数的系统时间,一种则是 BIOS 记载的硬件时间;
  • Linux 可以透过网络校时,最常见的网络校时为使用 NTP 服务器,这个服务启动在 udp port 123
  • 时区档案主要放置于 /usr/share/zoneinfo/ 目录下,而本地时区则参考 /etc/localtime
  • NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 nptdntpdate 两个指令不可同时使用;
  • NTP 服务器的联机状态可以使用 ntpstatntpq -p 来查询;
  • NTP 提供的客户端软件为 ntpdate 这个指令;
  • 在 Linux 下想要手动处理时间时,需以 date 设定时间后,以 hwclock -w 来写入 BIOS 所记录的时间。
  • NTP 服务器之间的时间误差不可超过 1000 秒,否则 NTP 服务会自动关闭。

更多 NTP 详情可以参考:鸟哥的 Linux 私房菜-- NTP 时间服务器 (opens new window)

# 二、ntpd 服务

环境:CentOS

# yum 安装

CentOS 安装 NTP 很简单,执行以下命令即可:

yum -y install ntp
+

# ntpd 配置

ntp 的配置文件路径为: /etc/ntp.conf ,参考配置:

# 1. 先处理权限方面的问题,包括放行上层服务器以及开放区网用户来源:
+# restrict default kod nomodify notrap nopeer noquery     # 拒绝 IPv4 的用户
+# restrict -6 default kod nomodify notrap nopeer noquery  # 拒绝 IPv6 的用户
+restrict default nomodify notrap nopeer noquery
+#restrict 192.168.100.0 mask 255.255.255.0 nomodify # 放行同局域网来源(根据网关和子网掩码决定)
+restrict 127.0.0.1   # 默认值,放行本机 IPv4 来源
+restrict ::1         # 默认值,放行本机 IPv6 来源
+
+# 2. 设定 NTP 主机来源
+# 注释掉默认 NTP 来源
+# server 0.centos.pool.ntp.org iburst
+# server 1.centos.pool.ntp.org iburst
+# server 2.centos.pool.ntp.org iburst
+# server 3.centos.pool.ntp.org iburst
+# 设置国内 NTP 来源
+server cn.pool.ntp.org prefer # 以这个主机为优先
+server ntp1.aliyun.com
+server ntp.sjtu.edu.cn
+
+# 3. 预设时间差异分析档案与暂不用到的 keys 等,不需要更改它:
+driftfile /var/lib/ntp/drift
+keys /etc/ntp/keys
+includefile /etc/ntp/crypto/pw
+

注意:如果更改配置,必须重启 NTP 服务(systemctl restart ntpd)才能生效。

# 放开防火墙限制

NTP 服务的端口是 123,使用的是 udp 协议,所以 NTP 服务器的防火墙必须对外开放 udp 123 这个端口。

如果防火墙使用 iptables,执行以下命令:

iptables -A INPUT -p UDP -i eth0 -s 192.168.0.0/24 --dport 123 -j ACCEPT
+

如果防火墙使用 firewalld,执行以下命令:

firewall-cmd --zone=public --add-port=123/udp --permanent
+

# ntpd 服务命令

systemctl enable ntpd.service  # 开启服务(开机自动启动服务)
+systemctl disable ntpd.service # 关闭服务(开机不会自动启动服务)
+systemctl start ntpd.service   # 启动服务
+systemctl stop ntpd.service    # 停止服务
+systemctl restart ntpd.service # 重启服务
+systemctl reload ntpd.service  # 重新载入配置
+systemctl status ntpd.service  # 查看服务状态
+

# 查看 ntp 服务状态

# 验证 NTP 服务正常工作

执行 ntpstat 可以查看 ntp 服务器有无和上层 ntp 连通,,如果成功,可以看到类似以下的内容:

$ ntpstat
+synchronised to NTP server (5.79.108.34) at stratum 3
+   time correct to within 1129 ms
+   polling server every 64 s
+

# 查看 ntp 服务器与上层 ntp 的状态

ntpq -p
+     remote           refid      st t when poll reach   delay   offset  jitter
+==============================================================================
+*ntp1.ams1.nl.le 130.133.1.10     2 u   36   64  367  230.801    5.271   2.791
+ 120.25.115.20   10.137.53.7      2 u   33   64  377   25.930   15.908   3.168
+ time.cloudflare 10.21.8.251      3 u   31   64  367  251.109   16.976   3.264
+

# 三、ntpdate 命令

注意:NTP 服务器为一种阶层式的服务,所以 NTP 服务器本来就会与上层时间服务器作时间的同步化, 因此 nptdntpdate 两个指令不可同时使用。

# 手动执行时间同步

ntpdate 命令是 NTP 的客户端软件,它可以用于请求时间同步。

语法:

/usr/sbin/ntpdate <ntp_server>
+

ntp_server 可以从 [国内 NTP 服务器](#国内 NTP 服务器) 中选择。

示例:

$ ntpdate cn.pool.ntp.org
+11 Feb 10:47:12 ntpdate[30423]: step time server 84.16.73.33 offset -49.894774 sec
+

# 自动定时同步时间

如果需要自动定时同步时间,可以利用 Crontab 工具。本质就是用 crontab 定时执行一次手动时间同步命令 ntp。

示例:执行如下命令,就可以在每天凌晨 3 点同步系统时间:

echo "0 3 * * * /usr/sbin/ntpdate cn.pool.ntp.org" >> /etc/crontab # 修改 crond 服务配置
+systemctl restart crond # 重启 crond 服务以生效
+

# 四、国内 NTP 服务器

以下 NTP 服务器搜集自网络:

cn.pool.ntp.org  # 最常用的国内NTP服务器,参考:https://www.ntppool.org/zh/use.html
+cn.ntp.org.cn    # 中国
+edu.ntp.org.cn   # 中国教育网
+ntp1.aliyun.com  # 阿里云
+ntp2.aliyun.com  # 阿里云
+ntp.sjtu.edu.cn  # 上海交通大学
+s1a.time.edu.cn  # 北京邮电大学
+s1b.time.edu.cn  # 清华大学
+s1c.time.edu.cn  # 北京大学
+s1d.time.edu.cn  # 东南大学
+s1e.time.edu.cn  # 清华大学
+s2a.time.edu.cn  # 清华大学
+s2b.time.edu.cn  # 清华大学
+s2c.time.edu.cn  # 北京邮电大学
+s2d.time.edu.cn  # 西南地区网络中心
+s2e.time.edu.cn  # 西北地区网络中心
+s2f.time.edu.cn  # 东北地区网络中心
+s2g.time.edu.cn  # 华东南地区网络中心
+s2h.time.edu.cn  # 四川大学网络管理中心
+s2j.time.edu.cn  # 大连理工大学网络中心
+s2k.time.edu.cn  # CERNET桂林主节点
+

# 参考资料

+ + + diff --git a/linux/ops/samba.html b/linux/ops/samba.html new file mode 100644 index 0000000..527948f --- /dev/null +++ b/linux/ops/samba.html @@ -0,0 +1,331 @@ + + + + + + Samba 应用 | LINUX-TUTORIAL + + + + + + + + +

# Samba 应用

samba 是在 Linux 和 UNIX 系统上实现 SMB 协议的一个免费软件。

samba 提供了在不同计算机(即使操作系统不同)上共享服务的能力。

关键词:samba, selinux

# 1. 安装配置 samba

本文将以一个完整的示例来展示如何配置 samba 来实现 Linux 和 Windows 的文件共享。

目标:假设希望共享 Linux 服务器上的 /share/fs 目录。

# 1.1. 查看是否已经安装 samba

  • CentOS:rpm -qa | grep samba
  • Ubuntu:dpkg -l | grep samba

# 1.2. 安装 samba 工具

  • CentOS:yum install -y samba samba-client samba-common
  • Ubuntu:sudo apt-get install -y samba samba-client

# 1.3. 配置 samba

samba 服务的配置文件是 /etc/samba/smb.conf,如果没有则 samba 无法启动。

执行以下命令,编辑配置文件:

vim /etc/samba/smb.conf
+

修改配置如下:

[global]
+        workgroup = SAMBA
+        security = user
+
+        passdb backend = tdbsam
+
+        printing = cups
+        printcap name = cups
+        load printers = yes
+        cups options = raw
+
+[homes]
+        comment = Home Directories
+        valid users = %S, %D%w%S
+        browseable = No
+        read only = No
+        inherit acls = Yes
+
+[printers]
+        comment = All Printers
+        path = /var/tmp
+        printable = Yes
+        create mask = 0600
+        browseable = No
+
+[print$]
+        comment = Printer Drivers
+        path = /var/lib/samba/drivers
+        write list = @printadmin root
+        force group = @printadmin
+        create mask = 0664
+        directory mask = 0775
+
+[fs]
+        comment = share folder
+        path = /share/fs
+        browseable = yes
+        writable = yes
+        read only = no
+        guest ok = yes
+        create mask = 0777
+        directory mask = 0777
+        public = yes
+        valid users = root
+

说明:

  • 我在这里添加了一个 [fs] 标签,这就是共享区域的配置。
  • 这里设置 path 属性为 /share/fs,意味着准备共享 /share/fs 目录,需要根据实际需要设置路径。/share/fs 目录的权限要设置为 777chmod 777 /share/fs
  • browseablewritable 等属性就比较容易理解了,即配置共享目录的访问权限。
  • valid users 属性指定允许访问的用户,需要注意的是指定的用户必须是 Linux 机器上实际存在的用户。

# 1.4. 创建 samba 用户

创建的 samba 用户必须是 Linux 机器上实际存在的用户。

$ sudo smbpasswd -a root
+New SMB password:
+Retype new SMB password:
+Added user root.
+

根据提示输入 samba 用户的密码。当 samba 服务成功安装、启动后,通过 Windows 系统访问机器共享目录时,就要输入这里配置的用户名、密码。

  • 查看 samba 服务器中已拥有哪些用户 - pdbedit -L
  • 删除 samba 服务中的某个用户 - smbpasswd -x 用户名

# 1.5. 启动 samba 服务

CentOS 6

$ sudo service samba restart  # 重启 samba
+$ sudo service smb restart    # 重启 samba
+

CentOS 7

$ sudo systemctl start smb.service     # 启动 samba
+$ sudo systemctl restart smb.service   # 重启 samba
+$ sudo systemctl enable smb.service    # 设置开机自动启动
+$ sudo systemctl status smb.service    # 查询 samba 状态
+

Ubuntu 16.04.3

$ sudo service smbd restart
+

# 1.6. 为 samba 添加防火墙规则

$ sudo firewall-cmd --permanent --zone=public --add-service=samba
+$ sudo firewall-cmd --reload
+

# 1.7. 测试 samba 服务

$ smbclient //localhost/fs -U root
+

输入 samba 用户的密码,如果成功,就会进入 smb: \>

# 1.8. 访问 samba 服务共享的目录

Windows:

访问:\\<你的ip>\<你的共享路径>

img

Mac:

与 Windows 类似,直接在 Finder 中访问 smb://<你的ip>/<你的共享路径> 即可。

# 2. 配置详解

# 2.1. samba 默认配置

你可以从 这里 (opens new window) 获取到默认配置文件:

$ cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
+$ wget "https://git.samba.org/samba.git/?p=samba.git;a=blob_plain;f=examples/smb.conf.default;hb=HEAD" -O /etc/samba/smb.conf
+

smb.conf 默认内容如下:

[global]
+        workgroup = SAMBA
+        security = user
+
+        passdb backend = tdbsam
+
+        printing = cups
+        printcap name = cups
+        load printers = yes
+        cups options = raw
+
+[homes]
+        comment = Home Directories
+        valid users = %S, %D%w%S
+        browseable = No
+        read only = No
+        inherit acls = Yes
+
+[printers]
+        comment = All Printers
+        path = /var/tmp
+        printable = Yes
+        create mask = 0600
+        browseable = No
+
+[print$]
+        comment = Printer Drivers
+        path = /var/lib/samba/drivers
+        write list = root
+        create mask = 0664
+        directory mask = 0775
+

# 2.2. 全局参数 [global]

[global]
+
+config file = /usr/local/samba/lib/smb.conf.%m
+说明:config file可以让你使用另一个配置文件来覆盖缺省的配置文件。如果文件 不存在,则该项无效。这个参数很有用,可以使得samba配置更灵活,可以让一台samba服务器模拟多台不同配置的服务器。比如,你想让PC1(主机名)这台电脑在访问Samba Server时使用它自己的配置文件,那么先在/etc/samba/host/下为PC1配置一个名为smb.conf.pc1的文件,然后在smb.conf中加入:config file=/etc/samba/host/smb.conf.%m。这样当PC1请求连接Samba Server时,smb.conf.%m就被替换成smb.conf.pc1。这样,对于PC1来说,它所使用的Samba服务就是由smb.conf.pc1定义的,而其他机器访问Samba Server则还是应用smb.conf。
+
+workgroup = WORKGROUP
+说明:设定 Samba Server 所要加入的工作组或者域。
+
+server string = Samba Server Version %v
+说明:设定 Samba Server 的注释,可以是任何字符串,也可以不填。宏%v表示显示Samba的版本号。
+
+netbios name = smbserver
+说明:设置Samba Server的NetBIOS名称。如果不填,则默认会使用该服务器的DNS名称的第一部分。netbios name和workgroup名字不要设置成一样了。
+
+interfaces = lo eth0 192.168.12.2/24 192.168.13.2/24
+说明:设置Samba Server监听哪些网卡,可以写网卡名,也可以写该网卡的IP地址。
+
+hosts allow = 127.192.168.1 192.168.10.1
+说明:表示允许连接到Samba Server的客户端,多个参数以空格隔开。可以用一个IP表示,也可以用一个网段表示。hosts deny 与hosts allow 刚好相反。
+例如:
+# 表示容许来自172.17.2.*.*的主机连接,但排除172.17.2.50
+hosts allow=172.17.2.EXCEPT172.17.2.50
+# 表示容许来自172.17.2.0/255.255.0.0子网中的所有主机连接
+hosts allow=172.17.2.0/255.255.0.0
+# 表示容许来自M1和M2两台计算机连接
+hosts allow=M1,M2
+# 表示容许来自SC域的所有计算机连接
+hosts allow=@SC
+max connections = 0
+说明:max connections用来指定连接Samba Server的最大连接数目。如果超出连接数目,则新的连接请求将被拒绝。0表示不限制。
+
+deadtime = 0
+说明:deadtime用来设置断掉一个没有打开任何文件的连接的时间。单位是分钟,0代表Samba Server不自动切断任何连接。
+
+time server = yes/no
+说明:time server用来设置让nmdb成为windows客户端的时间服务器。
+
+log file = /var/log/samba/log.%m
+说明:设置Samba Server日志文件的存储位置以及日志文件名称。在文件名后加个宏%m(主机名),表示对每台访问Samba Server的机器都单独记录一个日志文件。如果pc1、pc2访问过Samba Server,就会在/var/log/samba目录下留下log.pc1和log.pc2两个日志文件。
+
+max log size = 50
+说明:设置Samba Server日志文件的最大容量,单位为kB,0代表不限制。
+
+security = user
+说明:设置用户访问Samba Server的验证方式,一共有四种验证方式。
+1. share:用户访问Samba Server不需要提供用户名和口令, 安全性能较低。
+2. user:Samba Server共享目录只能被授权的用户访问,由Samba Server负责检查账号和密码的正确性。账号和密码要在本Samba Server中建立。
+3. server:依靠其他Windows NT/2000或Samba Server来验证用户的账号和密码,是一种代理验证。此种安全模式下,系统管理员可以把所有的Windows用户和口令集中到一个NT系统上,使用Windows NT进行Samba认证, 远程服务器可以自动认证全部用户和口令,如果认证失败,Samba将使用用户级安全模式作为替代的方式。
+4. domain:域安全级别,使用主域控制器(PDC)来完成认证。
+
+passdb backend = tdbsam
+说明:passdb backend就是用户后台的意思。目前有三种后台:smbpasswd、tdbsam和ldapsam。sam应该是security account manager(安全账户管理)的简写。
+
+smbpasswd:该方式是使用smb自己的工具smbpasswd来给系统用户(真实
+用户或者虚拟用户)设置一个Samba密码,客户端就用这个密码来访问Samba的资源。
+1. smbpasswd文件默认在/etc/samba目录下,不过有时候要手工建立该文件。
+2. tdbsam:该方式则是使用一个数据库文件来建立用户数据库。数据库文件叫passdb.tdb,默认在/etc/samba目录下。passdb.tdb用户数据库可以使用smbpasswd –a来建立Samba用户,不过要建立的Samba用户必须先是系统用户。我们也可以使用pdbedit命令来建立Samba账户。pdbedit命令的参数很多,我们列出几个主要的。
+  pdbedit –a username:新建Samba账户。
+  pdbedit –x username:删除Samba账户。
+  pdbedit –L:列出Samba用户列表,读取passdb.tdb数据库文件。
+  pdbedit –Lv:列出Samba用户列表的详细信息。
+  pdbedit –c “[D]” –u username:暂停该Samba用户的账号。
+  pdbedit –c “[]” –u username:恢复该Samba用户的账号。
+3. ldapsam:该方式则是基于LDAP的账户管理方式来验证用户。首先要建立LDAP服务,然后设置“passdb backend = ldapsam:ldap://LDAP Server”
+
+encrypt passwords = yes/no
+说明:是否将认证密码加密。因为现在windows操作系统都是使用加密密码,所以一般要开启此项。不过配置文件默认已开启。
+
+smb passwd file = /etc/samba/smbpasswd
+说明:用来定义samba用户的密码文件。smbpasswd文件如果没有那就要手工新建。
+
+username map = /etc/samba/smbusers
+说明:用来定义用户名映射,比如可以将root换成administrator、admin等。不过要事先在smbusers文件中定义好。比如:root = administrator admin,这样就可以用administrator或admin这两个用户来代替root登陆Samba Server,更贴近windows用户的习惯。
+
+guest account = nobody
+说明:用来设置guest用户名。
+
+socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+说明:用来设置服务器和客户端之间会话的Socket选项,可以优化传输速度。
+
+domain master = yes/no
+说明:设置Samba服务器是否要成为网域主浏览器,网域主浏览器可以管理跨子网域的浏览服务。
+
+local master = yes/no
+说明:local master用来指定Samba Server是否试图成为本地网域主浏览器。如果设为no,则永远不会成为本地网域主浏览器。但是即使设置为yes,也不等于该Samba Server就能成为主浏览器,还需要参加选举。
+
+preferred master = yes/no
+说明:设置Samba Server一开机就强迫进行主浏览器选举,可以提高Samba Server成为本地网域主浏览器的机会。如果该参数指定为yes时,最好把domain master也指定为yes。使用该参数时要注意:如果在本Samba Server所在的子网有其他的机器(不论是windows NT还是其他Samba Server)也指定为首要主浏览器时,那么这些机器将会因为争夺主浏览器而在网络上大发广播,影响网络性能。如果同一个区域内有多台Samba Server,将上面三个参数设定在一台即可。
+
+os level = 200
+说明:设置samba服务器的os level。该参数决定Samba Server是否有机会成为本地网域的主浏览器。os level从0到255,winNT的os level是32,win95/98的os level是1。Windows 2000的os level是64。如果设置为0,则意味着Samba Server将失去浏览选择。如果想让Samba Server成为PDC,那么将它的os level值设大些。
+
+domain logons = yes/no
+说明:设置Samba Server是否要做为本地域控制器。主域控制器和备份域控制器都需要开启此项。
+
+logon . = %u.bat
+说明:当使用者用windows客户端登陆,那么Samba将提供一个登陆档。如果设置成%u.bat,那么就要为每个用户提供一个登陆档。如果人比较多,那就比较麻烦。可以设置成一个具体的文件名,比如start.bat,那么用户登陆后都会去执行start.bat,而不用为每个用户设定一个登陆档了。这个文件要放置在[netlogon]的path设置的目录路径下。
+
+wins support = yes/no
+说明:设置samba服务器是否提供wins服务。
+
+wins server = wins服务器IP地址
+说明:设置Samba Server是否使用别的wins服务器提供wins服务。
+
+wins proxy = yes/no
+说明:设置Samba Server是否开启wins代理服务。
+
+dns proxy = yes/no
+说明:设置Samba Server是否开启dns代理服务。
+
+load printers = yes/no
+说明:设置是否在启动Samba时就共享打印机。
+
+printcap name = cups
+说明:设置共享打印机的配置文件。
+
+printing = cups
+说明:设置Samba共享打印机的类型。现在支持的打印系统有:bsd, sysv, plp, lprng, aix, hpux, qnx
+

# 2.3. 共享参数 [共享名]

[共享名]
+
+comment = 任意字符串
+说明:comment是对该共享的描述,可以是任意字符串。
+
+path = 共享目录路径
+说明:path用来指定共享目录的路径。可以用%u、%m这样的宏来代替路径里的unix用户和客户机的Netbios名,用宏表示主要用于[homes]共享域。例如:如果我们不打算用home段做为客户的共享,而是在/home/share/下为每个Linux用户以他的用户名建个目录,作为他的共享目录,这样path就可以写成:path = /home/share/%u; 。用户在连接到这共享时具体的路径会被他的用户名代替,要注意这个用户名路径一定要存在,否则,客户机在访问时会找不到网络路径。同样,如果我们不是以用户来划分目录,而是以客户机来划分目录,为网络上每台可以访问samba的机器都各自建个以它的netbios名的路径,作为不同机器的共享资源,就可以这样写:path = /home/share/%m 。
+
+browseable = yes/no
+说明:browseable用来指定该共享是否可以浏览。
+
+writable = yes/no
+说明:writable用来指定该共享路径是否可写。
+
+available = yes/no
+说明:available用来指定该共享资源是否可用。
+
+admin users = 该共享的管理者
+说明:admin users用来指定该共享的管理员(对该共享具有完全控制权限)。在samba 3.0中,如果用户验证方式设置成“security=share”时,此项无效。
+例如:admin users =bobyuan,jane(多个用户中间用逗号隔开)。
+
+valid users = 允许访问该共享的用户
+说明:valid users用来指定允许访问该共享资源的用户。
+例如:valid users = bobyuan,@bob,@tech(多个用户或者组中间用逗号隔开,如果要加入一个组就用“@+组名”表示。)
+
+invalid users = 禁止访问该共享的用户
+说明:invalid users用来指定不允许访问该共享资源的用户。
+例如:invalid users = root,@bob(多个用户或者组中间用逗号隔开。)
+
+write list = 允许写入该共享的用户
+说明:write list用来指定可以在该共享下写入文件的用户。
+例如:write list = bobyuan,@bob
+
+public = yes/no
+说明:public用来指定该共享是否允许guest账户访问。
+
+guest ok = yes/no
+说明:意义同“public”。
+
+几个特殊共享:
+[homes]
+comment = Home Directories
+browseable = no
+writable = yes
+valid users = %S
+; valid users = MYDOMAIN\%S
+
+[printers]
+comment = All Printers
+path = /var/spool/samba
+browseable = no
+guest ok = no
+writable = no
+printable = yes
+
+[netlogon]
+comment = Network Logon Service
+path = /var/lib/samba/netlogon
+guest ok = yes
+writable = no
+share modes = no
+
+[Profiles]
+path = /var/lib/samba/profiles
+browseable = no
+guest ok = yes
+

# 3. 常见问题

# 3.1. 你可能没有权限访问网络资源

问题现象:

  • 出现 NT_STATUS_ACCESS_DENIED 错误
  • Windows 下成功登陆 samba 后,点击共享目录仍然提示——你可能没有权限访问网络资源。

解决步骤:

  1. 检查是否配置了防火墙规则
# 一种方法是强行关闭防火墙
+$ sudo service iptables stop
+
+# 另一种方法是配置防火墙规则
+$ sudo firewall-cmd --permanent --zone=public --add-service=samba
+$ sudo firewall-cmd --reload
+
  1. 关闭 selinux
# 将 /etc/selinux/config 文件中的 SELINUX 设为 disabled
+$ sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
+
+# 重启生效
+$ reboot
+

# 3.2. window 下对 samba 的清理操作

  1. windows 清除访问 samba 局域网密码缓存 +
    • 在 dos 窗口中输入 control userpasswords2 或者 control keymgr.dll,然后【高级】/【密码管理】,删掉保存的该机器密码。
  2. windows 清除连接的 linux 的 samba 服务缓存 +
    1. 打开 win 的命令行。
    2. 输入 net use,就会打印出当前缓存的连接上列表。
    3. 根据列表,一个个删除连接: net use 远程连接名称 /del;或者一次性全部删除:net use * /del

# 4. 参考资料

  • http://blog.51cto.com/yuanbin/115761
  • https://www.jianshu.com/p/750be209a6f0
  • https://github.com/judasn/Linux-Tutorial/blob/master/markdown-file/Samba.md
  • https://blog.csdn.net/lan120576664/article/details/50396511
+ + + diff --git a/linux/ops/systemd.html b/linux/ops/systemd.html new file mode 100644 index 0000000..9ce54b7 --- /dev/null +++ b/linux/ops/systemd.html @@ -0,0 +1,474 @@ + + + + + + Systemd 应用 | LINUX-TUTORIAL + + + + + + + + +

# Systemd 应用

搬运自:Systemd 入门教程:命令篇 (opens new window)Systemd 入门教程:实战篇

Systemd 是 Linux 系统工具,用来启动守护进程 (opens new window),已成为大多数发行版的标准配置。

本文介绍它的基本用法,分为上下两篇。今天介绍它的主要命令,下一篇 (opens new window)介绍如何用于实战。

# 1. 由来

历史上,Linux 的启动 (opens new window)一直采用init (opens new window)进程。

下面的命令用来启动服务。

$ sudo /etc/init.d/apache2 start
+# 或者
+$ service apache2 start
+

这种方法有两个缺点。

一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。

二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种 +情况,这往往使得脚本变得很长。

# 2. Systemd 概述

Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套 +完整的解决方案。

根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就 +是它要守护整个系统。

使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进 +程(PID 等于 1),其他进程都是它的子进程。

$ systemctl --version
+

上面的命令查看 Systemd 的版本。

Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。事实上,现在还有很 +多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反"keep +simple, keep stupid" +的Unix 哲学 (opens new window)

img

(上图为 Systemd 架构图)

# 3. 系统管理

Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。

# 3.1. systemctl

systemctl是 Systemd 的主命令,用于管理系统。

# 重启系统
+$ sudo systemctl reboot
+
+# 关闭系统,切断电源
+$ sudo systemctl poweroff
+
+# CPU停止工作
+$ sudo systemctl halt
+
+# 暂停系统
+$ sudo systemctl suspend
+
+# 让系统进入冬眠状态
+$ sudo systemctl hibernate
+
+# 让系统进入交互式休眠状态
+$ sudo systemctl hybrid-sleep
+
+# 启动进入救援状态(单用户状态)
+$ sudo systemctl rescue
+

# 3.2. systemd-analyze

systemd-analyze命令用于查看启动耗时。

# 查看启动耗时
+$ systemd-analyze
+
+# 查看每个服务的启动耗时
+$ systemd-analyze blame
+
+# 显示瀑布状的启动过程流
+$ systemd-analyze critical-chain
+
+# 显示指定服务的启动流
+$ systemd-analyze critical-chain atd.service
+

# 3.3. hostnamectl

hostnamectl命令用于查看当前主机的信息。

# 显示当前主机的信息
+$ hostnamectl
+
+# 设置主机名。
+$ sudo hostnamectl set-hostname rhel7
+

# 3.4. localectl

localectl命令用于查看本地化设置。

# 查看本地化设置
+$ localectl
+
+# 设置本地化参数。
+$ sudo localectl set-locale LANG=en_GB.utf8
+$ sudo localectl set-keymap en_GB
+

# 3.5. timedatectl

timedatectl命令用于查看当前时区设置。

# 查看当前时区设置
+$ timedatectl
+
+# 显示所有可用的时区
+$ timedatectl list-timezones
+
+# 设置当前时区
+$ sudo timedatectl set-timezone America/New_York
+$ sudo timedatectl set-time YYYY-MM-DD
+$ sudo timedatectl set-time HH:MM:SS
+

# 3.6. loginctl

loginctl命令用于查看当前登录的用户。

# 列出当前session
+$ loginctl list-sessions
+
+# 列出当前登录用户
+$ loginctl list-users
+
+# 列出显示指定用户的信息
+$ loginctl show-user ruanyf
+

# 4. Unit

# 4.1. 含义

Systemd 可以管理所有系统资源。不同的资源统称为 Unit(单位)。

Unit 一共分成 12 种。

  • Service unit:系统服务
  • Target unit:多个 Unit 构成的一个组
  • Device Unit:硬件设备
  • Mount Unit:文件系统的挂载点
  • Automount Unit:自动挂载点
  • Path Unit:文件或路径
  • Scope Unit:不是由 Systemd 启动的外部进程
  • Slice Unit:进程组
  • Snapshot Unit:Systemd 快照,可以切回某个快照
  • Socket Unit:进程间通信的 socket
  • Swap Unit:swap 文件
  • Timer Unit:定时器

systemctl list-units命令可以查看当前系统的所有 Unit 。

# 列出正在运行的 Unit
+$ systemctl list-units
+
+# 列出所有Unit,包括没有找到配置文件的或者启动失败的
+$ systemctl list-units --all
+
+# 列出所有没有运行的 Unit
+$ systemctl list-units --all --state=inactive
+
+# 列出所有加载失败的 Unit
+$ systemctl list-units --failed
+
+# 列出所有正在运行的、类型为 service 的 Unit
+$ systemctl list-units --type=service
+

# 4.2. Unit 的状态

systemctl status命令用于查看系统状态和单个 Unit 的状态。

# 显示系统状态
+$ systemctl status
+
+# 显示单个 Unit 的状态
+$ sysystemctl status bluetooth.service
+
+# 显示远程主机的某个 Unit 的状态
+$ systemctl -H root@rhel7.example.com status httpd.service
+

除了status命令,systemctl还提供了三个查询状态的简单方法,主要供脚本内部的判 +断语句使用。

# 显示某个 Unit 是否正在运行
+$ systemctl is-active application.service
+
+# 显示某个 Unit 是否处于启动失败状态
+$ systemctl is-failed application.service
+
+# 显示某个 Unit 服务是否建立了启动链接
+$ systemctl is-enabled application.service
+

# 4.3. Unit 管理

对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。

# 立即启动一个服务
+$ sudo systemctl start apache.service
+
+# 立即停止一个服务
+$ sudo systemctl stop apache.service
+
+# 重启一个服务
+$ sudo systemctl restart apache.service
+
+# 杀死一个服务的所有子进程
+$ sudo systemctl kill apache.service
+
+# 重新加载一个服务的配置文件
+$ sudo systemctl reload apache.service
+
+# 重载所有修改过的配置文件
+$ sudo systemctl daemon-reload
+
+# 显示某个 Unit 的所有底层参数
+$ systemctl show httpd.service
+
+# 显示某个 Unit 的指定属性的值
+$ systemctl show -p CPUShares httpd.service
+
+# 设置某个 Unit 的指定属性
+$ sudo systemctl set-property httpd.service CPUShares=500
+

# 4.4. 依赖关系

Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启 +动 B。

systemctl list-dependencies命令列出一个 Unit 的所有依赖。

$ systemctl list-dependencies nginx.service
+

上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如 +果要展开 Target,就需要使用--all参数。

$ systemctl list-dependencies --all nginx.service
+

# 5. Unit 的配置文件

# 5.1. 概述

每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。

Systemd 默认从目录/etc/systemd/system/读取配置文件。但是,里面存放的大部分文件 +都是符号链接,指向目录/usr/lib/systemd/system/,真正的配置文件存放在那个目录。

systemctl enable命令用于在上面两个目录之间,建立符号链接关系。

$ sudo systemctl enable clamd@scan.service
+# 等同于
+$ sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service'
+

如果配置文件里面设置了开机启动,systemctl enable命令相当于激活开机启动。

与之对应的,systemctl disable命令用于在两个目录之间,撤销符号链接关系,相当于 +撤销开机启动。

$ sudo systemctl disable clamd@scan.service
+

配置文件的后缀名,就是该 Unit 的种类,比如sshd.socket。如果省略,Systemd 默认 +后缀名为.service,所以sshd会被理解成sshd.service

# 5.2. 配置文件的状态

systemctl list-unit-files命令用于列出所有配置文件。

# 列出所有配置文件
+$ systemctl list-unit-files
+
+# 列出指定类型的配置文件
+$ systemctl list-unit-files --type=service
+

这个命令会输出一个列表。

$ systemctl list-unit-files
+
+UNIT FILE              STATE
+chronyd.service        enabled
+clamd@.service         static
+clamd@scan.service     disabled
+

这个列表显示每个配置文件的状态,一共有四种。

  • enabled:已建立启动链接
  • disabled:没建立启动链接
  • static:该配置文件没有[Install]部分(无法执行),只能作为其他配置文件的依赖
  • masked:该配置文件被禁止建立启动链接

注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到 +的systemctl status命令。

$ systemctl status bluetooth.service
+

一旦修改配置文件,就要让 SystemD 重新加载配置文件,然后重新启动,否则修改不会生 +效。

$ sudo systemctl daemon-reload
+$ sudo systemctl restart httpd.service
+

# 5.3. 配置文件的格式

配置文件就是普通的文本文件,可以用文本编辑器打开。

systemctl cat命令可以查看配置文件的内容。

$ systemctl cat atd.service
+
+[Unit]
+Description=ATD daemon
+
+[Service]
+Type=forking
+ExecStart=/usr/bin/atd
+
+[Install]
+WantedBy=multi-user.target
+

从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,是用方括号表示的区 +别名,比如[Unit]。注意,配置文件的区块名和字段名,都是大小写敏感的。

每个区块内部是一些等号连接的键值对。

[Section]
+Directive1=value
+Directive2=value
+
+. . .
+

注意,键值对的等号两侧不能有空格。

# 5.4. 配置文件的区块

[Unit]区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 +Unit 的关系。它的主要字段如下。

  • Description:简短描述
  • Documentation:文档地址
  • Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
  • Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
  • BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
  • Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
  • After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
  • Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行
  • Condition...:当前 Unit 运行必须满足的条件,否则不会运行
  • Assert...:当前 Unit 运行必须满足的条件,否则会报启动失败

[Install]通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它 +的主要字段如下。

  • WantedBy:它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放 +入/etc/systemd/system目录下面以 Target 名 + .wants后缀构成的子目录中
  • RequiredBy:它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放 +入/etc/systemd/system目录下面以 Target 名 + .required后缀构成的子目录中
  • Alias:当前 Unit 可用于启动的别名
  • Also:当前 Unit 激活(enable)时,会被同时激活的其他 Unit

[Service]区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的 +主要字段如下。

  • Type:定义启动时的进程行为。它有以下几种值。
  • Type=simple:默认值,执行ExecStart指定的命令,启动主进程
  • Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出
  • Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行
  • Type=dbus:当前服务通过 D-Bus 启动
  • Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
  • Type=idle:若有其他任务执行完毕,当前服务才会运行
  • ExecStart:启动当前服务的命令
  • ExecStartPre:启动当前服务之前执行的命令
  • ExecStartPost:启动当前服务之后执行的命令
  • ExecReload:重启当前服务时执行的命令
  • ExecStop:停止当前服务时执行的命令
  • ExecStopPost:停止当其服务之后执行的命令
  • RestartSec:自动重启当前服务间隔的秒数
  • Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是 +重启)、on-successon-failureon-abnormalon-aborton-watchdog
  • TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数
  • Environment:指定环境变量

Unit 配置文件的完整字段清单,请参 +考官方文档 (opens new window)

# 6. Target

启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要 +哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。

简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候 +,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于"状态点 +",启动某个 Target 就好比启动到某种状态。

传统的init启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是 +,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动 +。

# 查看当前系统的所有 Target
+$ systemctl list-unit-files --type=target
+
+# 查看一个 Target 包含的所有 Unit
+$ systemctl list-dependencies multi-user.target
+
+# 查看启动时的默认 Target
+$ systemctl get-default
+
+# 设置启动时的默认 Target
+$ sudo systemctl set-default multi-user.target
+
+# 切换 Target 时,默认不关闭前一个 Target 启动的进程,
+# systemctl isolate 命令改变这种行为,
+# 关闭前一个 Target 里面所有不属于后一个 Target 的进程
+$ sudo systemctl isolate multi-user.target
+

Target 与 传统 RunLevel 的对应关系如下。

Traditional runlevel      New target name     Symbolically linked to...
+
+Runlevel 0           |    runlevel0.target -> poweroff.target
+Runlevel 1           |    runlevel1.target -> rescue.target
+Runlevel 2           |    runlevel2.target -> multi-user.target
+Runlevel 3           |    runlevel3.target -> multi-user.target
+Runlevel 4           |    runlevel4.target -> multi-user.target
+Runlevel 5           |    runlevel5.target -> graphical.target
+Runlevel 6           |    runlevel6.target -> reboot.target
+

它与init进程的主要差别如下。

(1)默认的 RunLevel(在/etc/inittab文件设置)现在被默认的 Target 取代, +位置是/etc/systemd/system/default.target,通常符号链接到graphical.target( +图形界面)或者multi-user.target(多用户命令行)。

(2)启动脚本的位置,以前是/etc/init.d目录,符号链接到不同的 RunLevel 目 +录 (比如/etc/rc3.d/etc/rc5.d等),现在则存放 +在/lib/systemd/system/etc/systemd/system目录。

(3)配置文件的位置,以前init进程的配置文件是/etc/inittab,各种服务的 +配置文件存放在/etc/sysconfig目录。现在的配置文件主要存放在/lib/systemd目录 +,在/etc/systemd目录里面的修改可以覆盖原始设置。

# 7. 日志管理

Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl一个命 +令,查看所有日志(内核日志和应用日志)。日志的配置文件 +是/etc/systemd/journald.conf

journalctl功能强大,用法非常多。

# 查看所有日志(默认情况下 ,只保存本次启动的日志)
+$ sudo journalctl
+
+# 查看内核日志(不显示应用日志)
+$ sudo journalctl -k
+
+# 查看系统本次启动的日志
+$ sudo journalctl -b
+$ sudo journalctl -b -0
+
+# 查看上一次启动的日志(需更改设置)
+$ sudo journalctl -b -1
+
+# 查看指定时间的日志
+$ sudo journalctl --since="2012-10-30 18:17:16"
+$ sudo journalctl --since "20 min ago"
+$ sudo journalctl --since yesterday
+$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
+$ sudo journalctl --since 09:00 --until "1 hour ago"
+
+# 显示尾部的最新10行日志
+$ sudo journalctl -n
+
+# 显示尾部指定行数的日志
+$ sudo journalctl -n 20
+
+# 实时滚动显示最新日志
+$ sudo journalctl -f
+
+# 查看指定服务的日志
+$ sudo journalctl /usr/lib/systemd/systemd
+
+# 查看指定进程的日志
+$ sudo journalctl _PID=1
+
+# 查看某个路径的脚本的日志
+$ sudo journalctl /usr/bin/bash
+
+# 查看指定用户的日志
+$ sudo journalctl _UID=33 --since today
+
+# 查看某个 Unit 的日志
+$ sudo journalctl -u nginx.service
+$ sudo journalctl -u nginx.service --since today
+
+# 实时滚动显示某个 Unit 的最新日志
+$ sudo journalctl -u nginx.service -f
+
+# 合并显示多个 Unit 的日志
+$ journalctl -u nginx.service -u php-fpm.service --since today
+
+# 查看指定优先级(及其以上级别)的日志,共有8级
+# 0: emerg
+# 1: alert
+# 2: crit
+# 3: err
+# 4: warning
+# 5: notice
+# 6: info
+# 7: debug
+$ sudo journalctl -p err -b
+
+# 日志默认分页输出,--no-pager 改为正常的标准输出
+$ sudo journalctl --no-pager
+
+# 以 JSON 格式(单行)输出
+$ sudo journalctl -b -u nginx.service -o json
+
+# 以 JSON 格式(多行)输出,可读性更好
+$ sudo journalctl -b -u nginx.serviceqq
+ -o json-pretty
+
+# 显示日志占据的硬盘空间
+$ sudo journalctl --disk-usage
+
+# 指定日志文件占据的最大空间
+$ sudo journalctl --vacuum-size=1G
+
+# 指定日志文件保存多久
+$ sudo journalctl --vacuum-time=1years
+

# 8. 实战

# 8.1. 开机启动

对于那些支持 Systemd 的软件,安装的时候,会自动在/usr/lib/systemd/system目录添 +加一个配置文件。

如果你想让该软件开机启动,就执行下面的命令(以httpd.service为例)。

$ sudo systemctl enable httpd
+

上面的命令相当于在/etc/systemd/system目录添加一个符号链接,指 +向/usr/lib/systemd/system里面的httpd.service文件。

这是因为开机时,Systemd只执行/etc/systemd/system目录里面的配置文件。这也意味 +着,如果把修改后的配置文件放在该目录,就可以达到覆盖原始配置的效果。

# 8.2. 启动服务

设置开机启动以后,软件并不会立即启动,必须等到下一次开机。如果想现在就运行该软件 +,那么要执行systemctl start命令。

$ sudo systemctl start httpd
+

执行上面的命令以后,有可能启动失败,因此要用systemctl status命令查看一下该服务 +的状态。

$ sudo systemctl status httpd
+
+httpd.service - The Apache HTTP Server
+Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled)
+Active: active (running) since 金 2014-12-05 12:18:22 JST; 7min ago
+Main PID: 4349 (httpd)
+Status: "Total requests: 1; Current requests/sec: 0; Current traffic:   0 B/sec"
+CGroup: /system.slice/httpd.service
+        ├─4349 /usr/sbin/httpd -DFOREGROUND
+        ├─4350 /usr/sbin/httpd -DFOREGROUND
+        ├─4351 /usr/sbin/httpd -DFOREGROUND
+        ├─4352 /usr/sbin/httpd -DFOREGROUND
+        ├─4353 /usr/sbin/httpd -DFOREGROUND
+        └─4354 /usr/sbin/httpd -DFOREGROUND
+
+12月 05 12:18:22 localhost.localdomain systemd[1]: Starting The Apache HTTP Server...
+12月 05 12:18:22 localhost.localdomain systemd[1]: Started The Apache HTTP Server.
+12月 05 12:22:40 localhost.localdomain systemd[1]: Started The Apache HTTP Server.
+

上面的输出结果含义如下。

  • Loaded行:配置文件的位置,是否设为开机启动
  • Active行:表示正在运行
  • Main PID行:主进程 ID
  • Status行:由应用本身(这里是 httpd )提供的软件当前状态
  • CGroup块:应用的所有子进程
  • 日志块:应用的日志

# 8.3. 停止服务

终止正在运行的服务,需要执行systemctl stop命令。

$ sudo systemctl stop httpd.service
+

有时候,该命令可能没有响应,服务停不下来。这时候就不得不"杀进程"了,向正在运行的 +进程发出kill信号。

$ sudo systemctl kill httpd.service
+

此外,重启服务要执行systemctl restart命令。

$ sudo systemctl restart httpd.service
+

# 8.4. 读懂配置文件

一个服务怎么启动,完全由它的配置文件决定。下面就来看,配置文件有些什么内容。

前面说过,配置文件主要放在/usr/lib/systemd/system目录,也可能 +在/etc/systemd/system目录。找到配置文件以后,使用文本编辑器打开即可。

systemctl cat命令可以用来查看配置文件,下面以sshd.service文件为例,它的作用 +是启动一个 SSH 服务器,供其他用户以 SSH 方式登录。

$ systemctl cat sshd.service
+
+[Unit]
+Description=OpenSSH server daemon
+Documentation=man:sshd(8) man:sshd_config(5)
+After=network.target sshd-keygen.service
+Wants=sshd-keygen.service
+
+[Service]
+EnvironmentFile=/etc/sysconfig/sshd
+ExecStart=/usr/sbin/sshd -D $OPTIONS
+ExecReload=/bin/kill -HUP $MAINPID
+Type=simple
+KillMode=process
+Restart=on-failure
+RestartSec=42s
+
+[Install]
+WantedBy=multi-user.target
+

可以看到,配置文件分成几个区块,每个区块包含若干条键值对。

下面依次解释每个区块的内容。

# 8.5. [Unit] 区块:启动顺序与依赖关系。

Unit区块的Description字段给出当前服务的简单描述,Documentation字段给出文档 +位置。

接下来的设置是启动顺序和依赖关系,这个比较重要。

After字段:表示如果network.targetsshd-keygen.service需要启动,那 +么sshd.service应该在它们之后启动。

相应地,还有一个Before字段,定义sshd.service应该在哪些服务之前启动。

注意,AfterBefore字段只涉及启动顺序,不涉及依赖关系。

举例来说,某 Web 应用需要 postgresql 数据库储存数据。在配置文件中,它只定义要在 +postgresql 之后启动,而没有定义依赖 postgresql 。上线后,由于某种原因 +,postgresql 需要重新启动,在停止服务期间,该 Web 应用就会无法建立数据库连接。

设置依赖关系,需要使用Wants字段和Requires字段。

Wants字段:表示sshd.servicesshd-keygen.service之间存在"弱依赖"关系,即 +如果"sshd-keygen.service"启动失败或停止运行,不影响sshd.service继续执行。

Requires字段则表示"强依赖"关系,即如果该服务启动失败或异常退出,那 +么sshd.service也必须退出。

注意,Wants字段与Requires字段只涉及依赖关系,与启动顺序无关,默认情况下是同 +时启动的。

# 8.6. [Service] 区块:启动行为

Service区块定义如何启动当前服务。

# 8.6.1. 启动命令

许多软件都有自己的环境参数文件,该文件可以用EnvironmentFile字段读取。

EnvironmentFile字段:指定当前服务的环境参数文件。该文件内部的key=value键值 +对,可以用$key的形式,在当前配置文件中获取。

上面的例子中,sshd 的环境参数文件是/etc/sysconfig/sshd

配置文件里面最重要的字段是ExecStart

ExecStart字段:定义启动进程时执行的命令。

上面的例子中,启动sshd,执行的命令是/usr/sbin/sshd -D $OPTIONS,其中的变 +量$OPTIONS就来自EnvironmentFile字段指定的环境参数文件。

与之作用相似的,还有如下这些字段。

  • ExecReload字段:重启服务时执行的命令
  • ExecStop字段:停止服务时执行的命令
  • ExecStartPre字段:启动服务之前执行的命令
  • ExecStartPost字段:启动服务之后执行的命令
  • ExecStopPost字段:停止服务之后执行的命令

请看下面的例子。

[Service]
+ExecStart=/bin/echo execstart1
+ExecStart=
+ExecStart=/bin/echo execstart2
+ExecStartPost=/bin/echo post1
+ExecStartPost=/bin/echo post2
+

上面这个配置文件,第二行ExecStart设为空值,等于取消了第一行的设置,运行结果如 +下。

execstart2
+post1
+post2
+

所有的启动设置之前,都可以加上一个连词号(-),表示"抑制错误",即发生错误的时 +候,不影响其他命令的执行。比如,EnvironmentFile=-/etc/sysconfig/sshd(注意等号 +后面的那个连词号),就表示即使/etc/sysconfig/sshd文件不存在,也不会抛出错误。

# 8.6.2. 启动类型

Type字段定义启动类型。它可以设置的值如下。

  • simple(默认值):ExecStart字段启动的进程为主进程
  • forking:ExecStart字段将以fork()方式启动,此时父进程将会退出,子进程将成 +为主进程
  • oneshot:类似于simple,但只执行一次,Systemd 会等它执行完,才启动其他服务
  • dbus:类似于simple,但会等待 D-Bus 信号后启动
  • notify:类似于simple,启动结束后会发出通知信号,然后 Systemd 再启动其他服 +务
  • idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场 +合是为让该服务的输出,不与其他服务的输出相混合

下面是一个oneshot的例子,笔记本电脑启动时,要把触摸板关掉,配置文件可以这样写 +。

[Unit]
+Description=Switch-off Touchpad
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/touchpad-off
+
+[Install]
+WantedBy=multi-user.target
+

上面的配置文件,启动类型设为oneshot,就表明这个服务只要运行一次就够了,不需要 +长期运行。

如果关闭以后,将来某个时候还想打开,配置文件修改如下。

[Unit]
+Description=Switch-off Touchpad
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/touchpad-off start
+ExecStop=/usr/bin/touchpad-off stop
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
+

上面配置文件中,RemainAfterExit字段设为yes,表示进程退出以后,服务仍然保持执 +行。这样的话,一旦使用systemctl stop命令停止服务,ExecStop指定的命令就会执行 +,从而重新开启触摸板。

# 8.6.3. 重启行为

Service区块有一些字段,定义了重启行为。

KillMode字段:定义 Systemd 如何停止 sshd 服务。

上面这个例子中,将KillMode设为process,表示只停止主进程,不停止任何 sshd 子 +进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对 sshd 很重 +要,否则你停止服务的时候,会连自己打开的 SSH session 一起杀掉。

KillMode字段可以设置的值如下。

  • control-group(默认值):当前控制组里面的所有子进程,都会被杀掉
  • process:只杀主进程
  • mixed:主进程将收到 SIGTERM 信号,子进程收到 SIGKILL 信号
  • none:没有进程会被杀掉,只是执行服务的 stop 命令。

接下来是Restart字段。

Restart字段:定义了 sshd 退出后,Systemd 的重启方式。

上面的例子中,Restart设为on-failure,表示任何意外的失败,就将重启 sshd。如果 +sshd 正常停止(比如执行systemctl stop命令),它就不会重启。

Restart字段可以设置的值如下。

  • no(默认值):退出后不会重启
  • on-success:只有正常退出时(退出状态码为 0),才会重启
  • on-failure:非正常退出时(退出状态码非 0),包括被信号终止和超时,才会重启
  • on-abnormal:只有被信号终止和超时,才会重启
  • on-abort:只有在收到没有捕捉到的信号终止时,才会重启
  • on-watchdog:超时退出,才会重启
  • always:不管是什么退出原因,总是重启

对于守护进程,推荐设为on-failure。对于那些允许发生错误退出的服务,可以设 +为on-abnormal

最后是RestartSec字段。

RestartSec字段:表示 Systemd 重启服务之前,需要等待的秒数。上面的例子设为等 +待 42 秒。

# 8.7. [Install] 区块

Install区块,定义如何安装这个配置文件,即怎样做到开机启动。

WantedBy字段:表示该服务所在的 Target。

Target的含义是服务组,表示一组服务。WantedBy=multi-user.target指的是,sshd +所在的 Target 是multi-user.target

这个设置非常重要,因为执行systemctl enable sshd.service命令时 +,sshd.service的一个符号链接,就会放在/etc/systemd/system目录下面 +的multi-user.target.wants子目录之中。

Systemd 有默认的启动 Target。

$ systemctl get-default
+multi-user.target
+

上面的结果表示,默认的启动 Target 是multi-user.target。在这个组里的所有服务, +都将开机启动。这就是为什么systemctl enable命令能设置开机启动的原因。

使用 Target 的时候,systemctl list-dependencies命令和systemctl isolate命令也 +很有用。

# 查看 multi-user.target 包含的所有服务
+$ systemctl list-dependencies multi-user.target
+
+# 切换到另一个 target
+# shutdown.target 就是关机状态
+$ sudo systemctl isolate shutdown.target
+

一般来说,常用的 Target 有两个:一个是multi-user.target,表示多用户命令行状态 +;另一个是graphical.target,表示图形用户状态,它依赖于multi-user.target。官 +方文档有一张非常清晰的 +Target 依赖关系图 (opens new window)

# 8.8. Target 的配置文件

Target 也有自己的配置文件。

$ systemctl cat multi-user.target
+
+[Unit]
+Description=Multi-User System
+Documentation=man:systemd.special(7)
+Requires=basic.target
+Conflicts=rescue.service rescue.target
+After=basic.target rescue.service rescue.target
+AllowIsolate=yes
+

注意,Target 配置文件里面没有启动命令。

上面输出结果中,主要字段含义如下。

  • Requires字段:要求basic.target一起运行。
  • Conflicts字段:冲突字段。如果rescue.servicerescue.target正在运行 +,multi-user.target就不能运行,反之亦然。
  • After:表示multi-user.targetbasic.targetrescue.service、 +rescue.target之后启动,如果它们有启动的话。
  • AllowIsolate:允许使用systemctl isolate命令切换到multi-user.target

# 8.9. 修改配置文件后重启

修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。

# 重新加载配置文件
+$ sudo systemctl daemon-reload
+
+# 重启相关服务
+$ sudo systemctl restart foobar
+

# 9. 参考资料

+ + + diff --git a/linux/ops/vim.html b/linux/ops/vim.html new file mode 100644 index 0000000..0762197 --- /dev/null +++ b/linux/ops/vim.html @@ -0,0 +1,44 @@ + + + + + + Vim 应用 | LINUX-TUTORIAL + + + + + + + + +

# Vim 应用

# 1. 概念

# 1.1. 什么是 vim

Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。和 Emacs 并列成为类 Unix 系统用户最喜欢的编辑器。

# 1.2. Vim 的模式

基本上 vi/vim 共分为三种模式,分别是命令模式(Command mode)插入模式(Insert mode)底线命令模式(Last line mode)

# 1.2.1. 命令模式

用户刚刚启动 vi/vim,便进入了命令模式。

此状态下敲击键盘动作会被 Vim 识别为命令,而非输入字符。

# 1.2.2. 插入模式

在命令模式下按下 i 就进入了输入模式。

在输入模式下,你可以输入文本内容。

# 1.2.3. 底线命令模式

在命令模式下按下 :(英文冒号)就进入了底线命令模式。

底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。

# 2. Vim 渐进学习

# 2.1. 存活

  1. 安装 vim (opens new window)
  2. 启动 vim
  3. **什么也别干!**请先阅读

当你安装好一个编辑器后,你一定会想在其中输入点什么东西,然后看看这个编辑器是什么样子。但 vim 不是这样的,请按照下面的命令操作:

  • 启 动 Vim 后,vim 在 Normal 模式下。
  • 让我们进入 Insert 模式,请按下键 i 。(注:你会看到 vim 左下角有一个–insert–字样,表示,你可以以插入的方式输入了)
  • 此时,你可以输入文本了,就像你用“记事本”一样。
  • 如果你想返回 Normal 模式,请按 ESC 键。

现在,你知道如何在 InsertNormal 模式下切换了。下面是一些命令,可以让你在 Normal 模式下幸存下来:

  • iInsert 模式,按 ESC 回到 Normal 模式.
  • x → 删当前光标所在的一个字符。
  • :wq → 存盘 + 退出 (:w 存盘, :q 退出) (注::w 后可以跟文件名)
  • dd → 删除当前行,并把删除的行存到剪贴板里
  • p → 粘贴剪贴板

推荐

  • hjkl (强例推荐使用其移动光标,但不必需) → 你也可以使用光标键 (←↓↑→). 注: j 就像下箭头。
  • :help <command> → 显示相关命令的帮助。你也可以就输入 :help 而不跟命令。(注:退出帮助需要输入:q)

你能在 vim 幸存下来只需要上述的那 5 个命令,你就可以编辑文本了,你一定要把这些命令练成一种下意识的状态。于是你就可以开始进阶到第二级了。

当是,在你进入第二级时,需要再说一下 Normal 模式。在一般的编辑器下,当你需要 copy 一段文字的时候,你需要使用 Ctrl 键,比如:Ctrl-C。也就是说,Ctrl 键就好像功能键一样,当你按下了功能键 Ctrl 后,C 就不在是 C 了,而且就是一个命令或是一个快键键了,在 vim 的 Normal 模式下,所有的键都是功能键。这个你需要知道。

标记

  • 下面的文字中,如果是 Ctrl-λ我会写成 <C-λ>.
  • : 开始的命令你需要输入 <enter>回车,例如 — 如果我写成 :q 也就是说你要输入 :q<enter>.

# 2.2. 感觉良好

上面的那些命令只能让你存活下来,现在是时候学习一些更多的命令了,下面是我的建议:(注:所有的命令都需要在 Normal 模式下使用,如果你不知道现在在什么样的模式,你就狂按几次 ESC 键)

  1. 各种插入模式

    • a → 在光标后插入
    • o → 在当前行后插入一个新行
    • O → 在当前行前插入一个新行
    • cw → 替换从光标所在位置后到一个单词结尾的字符
  2. 简单的移动光标

    • 0 → 数字零,到行头
    • ^ → 到本行第一个不是 blank 字符的位置(所谓 blank 字符就是空格,tab,换行,回车等)
    • $ → 到本行行尾
    • g_ → 到本行最后一个不是 blank 字符的位置。
    • /pattern → 搜索 pattern 的字符串(注:如果搜索出多个匹配,可按 n 键到下一个)
  3. 拷贝/粘贴

    (注:p/P 都可以,p 是表示在当前位置之后,P 表示在当前位置之前)

    • P → 粘贴
    • yy → 拷贝当前行当行于 ddP
  4. Undo/Redo

    • u → undo
    • <C-r> → redo
  5. 打开/保存/退出/改变文件

    (Buffer)

    • :e <path/to/file> → 打开一个文件
    • :w → 存盘
    • :saveas <path/to/file> → 另存为 <path/to/file>
    • :xZZ:wq → 保存并退出 (:x 表示仅在需要时保存,ZZ 不需要输入冒号并回车)
    • :q! → 退出不保存 :qa! 强行退出所有的正在编辑的文件,就算别的文件有更改。
    • :bn:bp → 你可以同时打开很多文件,使用这两个命令来切换下一个或上一个文件。(注:我喜欢使用:n 到下一个文件)

花点时间熟悉一下上面的命令,一旦你掌握他们了,你就几乎可以干其它编辑器都能干的事了。但是到现在为止,你还是觉得使用 vim 还是有点笨拙,不过没关系,你可以进阶到第三级了。

# 2.3. 更好,更强,更快

先恭喜你!你干的很不错。我们可以开始一些更为有趣的事了。在第三级,我们只谈那些和 vi 可以兼容的命令。

# 2.3.1. 更好

下面,让我们看一下 vim 是怎么重复自己的:1515G

  1. . → (小数点) 可以重复上一次的命令
  2. N<command> → 重复某个命令 N 次

下面是一个示例,找开一个文件你可以试试下面的命令:

  • 2dd → 删除 2 行
  • 3p → 粘贴文本 3 次
  • 100idesu [ESC] → 会写下 “desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu desu “
  • . → 重复上一个命令—— 100 “desu “.
  • 3. → 重复 3 次 “desu” (注意:不是 300,你看,VIM 多聪明啊).

# 2.3.2. 更强

你要让你的光标移动更有效率,你一定要了解下面的这些命令,千万别跳过

  1. NG → 到第 N 行 (注:注意命令中的 G 是大写的,另我一般使用 : N 到第 N 行,如 :137 到第 137 行)

  2. gg → 到第一行。(注:相当于 1G,或 :1)

  3. G → 到最后一行。

  4. 按单词移动:

    1. w → 到下一个单词的开头。
    2. e → 到下一个单词的结尾。

    > 如果你认为单词是由默认方式,那么就用小写的 e 和 w。默认上来说,一个单词由字母,数字和下划线组成(注:程序变量)

    > 如果你认为单词是由 blank 字符分隔符,那么你需要使用大写的 E 和 W。(注:程序语句)

    img

下面,让我来说说最强的光标移动:

  • % : 匹配括号移动,包括 (, {, [. (注:你需要把光标先移到括号上)
  • *#: 匹配光标当前所在的单词,移动光标到下一个(或上一个)匹配单词(*是下一个,#是上一个)

相信我,上面这三个命令对程序员来说是相当强大的。

# 2.3.3. 更快

你一定要记住光标的移动,因为很多命令都可以和这些移动光标的命令连动。很多命令都可以如下来干:

<start position><command><end position>

例如 0y$ 命令意味着:

  • 0 → 先到行头
  • y → 从这里开始拷贝
  • $ → 拷贝到本行最后一个字符

你可可以输入 ye,从当前位置拷贝到本单词的最后一个字符。

你也可以输入 y2/foo 来拷贝 2 个 “foo” 之间的字符串。

还有很多时间并不一定你就一定要按 y 才会拷贝,下面的命令也会被拷贝:

  • d (删除 )
  • v (可视化的选择)
  • gU (变大写)
  • gu (变小写)
  • 等等

(注:可视化选择是一个很有意思的命令,你可以先按 v,然后移动光标,你就会看到文本被选择,然后,你可能 d,也可 y,也可以变大写等)

# 2.4. Vim 超能力

你只需要掌握前面的命令,你就可以很舒服的使用 VIM 了。但是,现在,我们向你介绍的是 VIM 杀手级的功能。下面这些功能是我只用 vim 的原因。

# 2.4.1. 在当前行上移动光标: 0 ^ ####fFtT,``;`

  • 0 → 到行头
  • ^ → 到本行的第一个非 blank 字符
  • $ → 到行尾
  • g_ → 到本行最后一个不是 blank 字符的位置。
  • fa → 到下一个为 a 的字符处,你也可以 fs 到下一个为 s 的字符。
  • t, → 到逗号前的第一个字符。逗号可以变成其它字符。
  • 3fa → 在当前行查找第三个出现的 a。
  • FT → 和 ft 一样,只不过是相反方向。 +img

还有一个很有用的命令是 dt" → 删除所有的内容,直到遇到双引号—— "。

# 2.4.2. 区域选择 <action>a<object><action>i<object>

在 visual 模式下,这些命令很强大,其命令格式为

<action>a<object><action>i<object>

  • action 可以是任何的命令,如 d (删除), y (拷贝), v (可以视模式选择)。
  • object 可能是: w 一个单词, W 一个以空格为分隔的单词, s 一个句字, p 一个段落。也可以是一个特别的字符:"、 '、 )、 }、 ]。

假设你有一个字符串 (map (+) ("foo")).而光标键在第一个 o的位置。

  • vi" → 会选择 foo.
  • va" → 会选择 "foo".
  • vi) → 会选择 "foo".
  • va) → 会选择("foo").
  • v2i) → 会选择 map (+) ("foo")
  • v2a) → 会选择 (map (+) ("foo"))

img

# 2.4.3. 块操作: <C-v>

块操作,典型的操作: 0 <C-v> <C-d> I-- [ESC]

  • ^ → 到行头
  • <C-v> → 开始块操作
  • <C-d> → 向下移动 (你也可以使用 hjkl 来移动光标,或是使用%,或是别的)
  • I-- [ESC] → I 是插入,插入“--”,按 ESC 键来为每一行生效。

img

在 Windows 下的 vim,你需要使用 <C-q> 而不是 <C-v><C-v> 是拷贝剪贴板。

# 2.4.4. 自动提示: <C-n><C-p>

在 Insert 模式下,你可以输入一个词的开头,然后按 <C-p>或是<C-n>,自动补齐功能就出现了……

img

# 2.4.5. 宏录制: qa 操作序列 q, @a, @@

  • qa 把你的操作记录在寄存器 a。
  • 于是 @a 会 replay 被录制的宏。
  • @@ 是一个快捷键用来 replay 最新录制的宏。

示例

在一个只有一行且这一行只有“1”的文本中,键入如下命令:

  • qaYp<C-a>q
    +

    • qa 开始录制
    • Yp 复制行.
    • <C-a> 增加 1.
    • q 停止录制.
  • @a → 在 1 下面写下 2

  • @@ → 在 2 正面写下 3

  • 现在做 100@@ 会创建新的 100 行,并把数据增加到 103.

img

# 2.4.6. 可视化选择: v,V,<C-v>

前面,我们看到了 <C-v>的示例 (在 Windows 下应该是),我们可以使用 vV。一但被选好了,你可以做下面的事:

  • J → 把所有的行连接起来(变成一行)
  • <> → 左右缩进
  • = → 自动给缩进 (注:这个功能相当强大,我太喜欢了)

img

在所有被选择的行后加上点东西:

  • <C-v>
  • 选中相关的行 (可使用 j<C-d> 或是 /pattern 或是 % 等……)
  • $ 到行最后
  • A, 输入字符串,按 ESC。

img

# 2.4.7. 分屏: :splitvsplit.

下面是主要的命令,你可以使用 VIM 的帮助 :help split. 你可以参考本站以前的一篇文章VIM 分屏 (opens new window)

  • :split → 创建分屏 (:vsplit创建垂直分屏)
  • <C-w><dir> : dir 就是方向,可以是 hjkl 或是 ←↓↑→ 中的一个,其用来切换分屏。
  • <C-w>_ (或 <C-w>|) : 最大化尺寸 (| 垂直分屏)
  • <C-w>+ (或 <C-w>-) : 增加尺寸

img

# 3. Vim Cheat Sheet

本节内容的原文地址:http://cenalulu.github.io/linux/all-vim-cheatsheat/ (opens new window)

# 3.1. 经典版

下面这个键位图应该是大家最常看见的经典版了。其实这个版本是一系列的入门教程键位图的组合结果。要查看不同编辑模式下的键位图,可以看这里打包下载 (opens new window)

此外,这里 (opens new window)还有简体中文版。

img

# 3.2. 入门版

基本操作的入门版。原版出处 (opens new window)还有 keynote 版本可供 DIY 以及其他相关有用的 cheatsheet。

img

# 3.3. 进阶版

下图是 300DPI 的超清大图,另外查看原文 (opens new window)还有更多版本:黑白,低分辨率,色盲等

img

# 3.4. 增强版

下图是一个更新时间较新的现代版,含有的信息也更丰富。原文链接 (opens new window)

img

# 3.5. 文字版

原文链接 (opens new window)

img

img

# 4. 资料

+ + + diff --git a/linux/ops/zsh.html b/linux/ops/zsh.html new file mode 100644 index 0000000..63bd4f9 --- /dev/null +++ b/linux/ops/zsh.html @@ -0,0 +1,69 @@ + + + + + + oh-my-zsh 应用 | LINUX-TUTORIAL + + + + + + + + +

# oh-my-zsh 应用

# 1. Zsh 简介

# 1.1. Zsh 是什么

使用 Linux 的人都知道:*Shell_ 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言

Shell 的类型有很多种,linux 下默认的是 bash,虽然 bash 的功能已经很强大,但对于以懒惰为美德的程序员来说,bash 的提示功能不够强大,界面也不够炫,并非理想工具。

Zsh (opens new window) 也是一种 Shell(据传说 99% 的 Bash 操作 和 Zsh 是相同的),它的功能极其强大,只是配置过于复杂,起初只有极客才在用。后来,出现了一个名叫 oh-my-zsh (opens new window) 的开源项目,使用 zsh 就变得十分简易了。

# 2. Zsh 安装

# 2.1. 环境要求

  • CentOS 6.7 64 bit
  • root 用户

# 2.2. 安装 zsh

  • 先看下你的 CentOS 支持哪些 shell:cat /etc/shells,正常结果应该是这样的:
/bin/sh
+/bin/bash
+/sbin/nologin
+/bin/dash
+/bin/tcsh
+/bin/csh
+

如果已经有 zsh ,那么我们就不必安装了。

  • CentOS 安装:sudo yum install -y zsh
  • Ubuntu 安装:sudo apt-get install -y zsh
  • 检查系统的 shell:cat /etc/shells,你会发现多了一个:/bin/zsh

# 2.3. 安装 oh-my-zsh

使用 Zsh (opens new window),怎么能离开灵魂伴侣 oh-my-zsh (opens new window)

# 安装 oh-my-zsh
+wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh
+

# 2.4. 配置 oh-my-zsh

# 2.4.1. 插件

oh-my-zsh 插件太多,不一一列举,请参考:oh-my-zsh 插件列表 (opens new window)

  • 启用 oh-my-zsh 中自带的插件。
  • 查看 oh-my-zsh 插件数:ls -l /root/.oh-my-zsh/plugins |grep "^d"|wc -l
  • 编辑配置文件:vim /root/.zshrc
  • 插件推荐: +
    • zsh-autosuggestions (opens new window)
      • 这个插件会对历史命令一些补全,类似 fish 终端
      • 安装,复制该命令:git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-\~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions - 编辑:vim \~/.zshrc,找到这一行,后括号里面的后面添加:plugins=( 前面的一些插件名称,换行,加上:zsh-autosuggestions) - 刷新下配置:source \~/.zshrc
    • extract +
      • 功能强大的解压插件,所有类型的文件解压一个命令 x 全搞定,再也不需要去记 tar 后面到底是哪几个参数了。
    • z +
      • 强大的目录自动跳转命令,会记忆你曾经进入过的目录,用模糊匹配快速进入你想要的目录。
    • zsh-syntax-highlighting (opens new window)
      • 这个插件会对终端命令高亮显示,比如正确的拼写会是绿色标识,否则是红色,另外对于一些 shell 输出语句也会有高亮显示,算是不错的辅助插件
      • 安装,复制该命令:git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-\~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
      • 编辑:vim \~/.zshrc,找到这一行,后括号里面的后面添加:plugins=( 前面的一些插件名称,换行,加上:zsh-syntax-highlighting) - 刷新下配置:source \~/.zshrc
    • wd (opens new window)
      • 简单地讲就是给指定目录映射一个全局的名字,以后方便直接跳转到这个目录,比如:
      • 编辑配置文件,添加上 wd 的名字:vim /root/.zshrc
      • 我常去目录:/opt/setups,每次进入该目录下都需要这样:cd /opt/setups
      • 现在用 wd 给他映射一个快捷方式:cd /opt/setups ; wd add setups
      • 以后我在任何目录下只要运行:wd setups 就自动跑到 /opt/setups 目录下了
    • autojump (opens new window)
      • 这个插件会记录你常去的那些目录,然后做一下权重记录,你可以用这个命令看到你的习惯:j --stat,如果这个里面有你的记录,那你就只要敲最后一个文件夹名字即可进入,比如我个人习惯的 program:j program,就可以直接到:/usr/program
      • 插件下载:wget https://github.com/downloads/wting/autojump/autojump_v21.1.2.tar.gz
      • 解压:tar zxvf autojump_v21.1.2.tar.gz
      • 进入解压后目录并安装:cd autojump_v21.1.2/ ; ./install.sh
      • 再执行下这个:source /etc/profile.d/autojump.sh
      • 编辑配置文件,添加上 autojump 的名字:vim /root/.zshrc

# 2.4.2. 主题

oh-my-zsh 主题太多,不一一列举,请参考:oh-my-zsh 主题列表 (opens new window)

  • 查看 oh-my-zsh 主题数:ls -l /root/.oh-my-zsh/themes |grep "^-"|wc -l
  • 个人比较推荐的是(排名有先后): +
    • ys
    • agnoster
    • avit
    • blinks
  • 编辑配置文件:vim /root/.zshrc
  • 配置好新主题需要重新连接 shell 才能看到效果

zsh 效果如下:

img

# 3. 快捷键

  • 呃,这个其实可以不用讲的,你自己用的时候你自己会发现的,各种便捷,特别是用 Tab 多的人一定会有各种惊喜的。
  • 使用 ctrl-r 来搜索命令历史记录。按完此快捷键后,可以输入关键命令词语,如果历史记录有含有此词语会显示出来。
  • 命令别名: - 在命令行中输入 alias 可以查看已经有的命令别名 - 自己新增一些别名,编辑文件:vim \~/.zshrc,在文件加入下面格式的命令,比如以下是网友提供的一些思路:
alias cls='clear'
+alias ll='ls -l'
+alias la='ls -a'
+alias grep="grep --color=auto"
+alias -s html='vim'   # 在命令行直接输入后缀为 html 的文件名,会在 Vim 中打开
+alias -s rb='vim'     # 在命令行直接输入 ruby 文件,会在 Vim 中打开
+alias -s py='vim'      # 在命令行直接输入 python 文件,会用 vim 中打开,以下类似
+alias -s js='vim'
+alias -s c='vim'
+alias -s java='vim'
+alias -s txt='vim'
+alias -s gz='tar -xzvf' # 在命令行直接输入后缀为 gz 的文件名,会自动解压打开
+alias -s tgz='tar -xzvf'
+alias -s zip='unzip'
+alias -s bz2='tar -xjvf'
+

# 4. 参考资料

+ + + diff --git a/linux/soft/apollo/index.html b/linux/soft/apollo/index.html new file mode 100644 index 0000000..cedcf9d --- /dev/null +++ b/linux/soft/apollo/index.html @@ -0,0 +1,42 @@ + + + + + + Apollo | LINUX-TUTORIAL + + + + + + + + +

# Apollo

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

官方 Github:https://github.com/ctripcorp/apollo

由于官方示例不能直接使用,所以我 Fork 后,略作修改:https://github.com/dunwu/apollo

+ + + diff --git a/linux/soft/elastic/elastic-beats.html b/linux/soft/elastic/elastic-beats.html new file mode 100644 index 0000000..d6fa393 --- /dev/null +++ b/linux/soft/elastic/elastic-beats.html @@ -0,0 +1,102 @@ + + + + + + Elastic 技术栈之 Filebeat | LINUX-TUTORIAL + + + + + + + + +

# Elastic 技术栈之 Filebeat

# 简介

Beats 是安装在服务器上的数据中转代理。

Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash 。

img

Beats 有多种类型,可以根据实际应用需要选择合适的类型。

常用的类型有:

  • **Packetbeat:**网络数据包分析器,提供有关您的应用程序服务器之间交换的事务的信息。
  • **Filebeat:**从您的服务器发送日志文件。
  • **Metricbeat:**是一个服务器监视代理程序,它定期从服务器上运行的操作系统和服务收集指标。
  • **Winlogbeat:**提供Windows事件日志。

参考

更多 Beats 类型可以参考:community-beats (opens new window)

说明

由于本人工作中只应用了 FileBeat,所以后面内容仅介绍 FileBeat 。

# FileBeat 的作用

相比 Logstash,FileBeat 更加轻量化。

在任何环境下,应用程序都有停机的可能性。 Filebeat 读取并转发日志行,如果中断,则会记住所有事件恢复联机状态时所在位置。

Filebeat带有内部模块(auditd,Apache,Nginx,System和MySQL),可通过一个指定命令来简化通用日志格式的收集,解析和可视化。

FileBeat 不会让你的管道超负荷。FileBeat 如果是向 Logstash 传输数据,当 Logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决,FileBeat 将恢复到原来的速度并继续传播。

img

# 安装

Unix / Linux 系统建议使用下面方式安装,因为比较通用。

wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.1-linux-x86_64.tar.gz
+tar -zxf filebeat-6.1.1-linux-x86_64.tar.gz
+

参考

更多内容可以参考:filebeat-installation (opens new window)

# 配置

# 配置文件

首先,需要知道的是:filebeat.yml 是 filebeat 的配置文件。配置文件的路径会因为你安装方式的不同而变化。

Beat 所有系列产品的配置文件都基于 YAML (opens new window) 格式,FileBeat 当然也不例外。

filebeat.yml 部分配置示例:

filebeat:
+  prospectors:
+    - type: log
+      paths:
+        - /var/log/*.log
+      multiline:
+        pattern: '^['
+        match: after
+

参考

更多 filebeat 配置内容可以参考:配置 filebeat (opens new window)

更多 filebeat.yml 文件格式内容可以参考:filebeat.yml 文件格式 (opens new window)

# 重要配置项

# filebeat.prospectors

(文件监视器)用于指定需要关注的文件。

示例

filebeat.prospectors:
+- type: log
+  enabled: true
+  paths:
+    - /var/log/*.log
+

# output.elasticsearch

如果你希望使用 filebeat 直接向 elasticsearch 输出数据,需要配置 output.elasticsearch 。

示例

output.elasticsearch:
+  hosts: ["192.168.1.42:9200"]
+

# output.logstash

如果你希望使用 filebeat 向 logstash输出数据,然后由 logstash 再向elasticsearch 输出数据,需要配置 output.logstash。

注意

相比于向 elasticsearch 输出数据,个人更推荐向 logstash 输出数据。

因为 logstash 和 filebeat 一起工作时,如果 logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决,FileBeat 将恢复到原来的速度并继续传播。这样,可以减少管道超负荷的情况。

示例

output.logstash:
+  hosts: ["127.0.0.1:5044"]
+

此外,还需要在 logstash 的配置文件(如 logstash.conf)中指定 beats input 插件:

input {
+  beats {
+    port => 5044 # 此端口需要与 filebeat.yml 中的端口相同
+  }
+}
+
+# The filter part of this file is commented out to indicate that it is
+# optional.
+# filter {
+#
+# }
+
+output {
+  elasticsearch {
+    hosts => "localhost:9200"
+    manage_template => false
+    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}" 
+    document_type => "%{[@metadata][type]}" 
+  }
+}
+

# setup.kibana

如果打算使用 Filebeat 提供的 Kibana 仪表板,需要配置 setup.kibana 。

示例

setup.kibana:
+  host: "localhost:5601"
+

# setup.template.settings

在 Elasticsearch 中,索引模板 (opens new window)用于定义设置和映射,以确定如何分析字段。

在 Filebeat 中,setup.template.settings 用于配置索引模板。

Filebeat 推荐的索引模板文件由 Filebeat 软件包安装。如果您接受 filebeat.yml 配置文件中的默认配置,Filebeat在成功连接到 Elasticsearch 后自动加载模板。

您可以通过在 Filebeat 配置文件中配置模板加载选项来禁用自动模板加载,或加载自己的模板。您还可以设置选项来更改索引和索引模板的名称。

参考

更多内容可以参考:filebeat-template (opens new window)

说明

如无必要,使用 Filebeat 配置文件中的默认索引模板即可。

# setup.dashboards

Filebeat 附带了示例 Kibana 仪表板。在使用仪表板之前,您需要创建索引模式 filebeat- *,并将仪表板加载到Kibana 中。为此,您可以运行 setup 命令或在 filebeat.yml 配置文件中配置仪表板加载。

为了在 Kibana 中加载 Filebeat 的仪表盘,需要在 filebeat.yml 配置中启动开关:

setup.dashboards.enabled: true
+

参考

更多内容可以参考:configuration-dashboards (opens new window)

# 命令

filebeat 提供了一系列命令来完成各种功能。

执行命令方式:

./filebeat COMMAND
+

参考

更多内容可以参考:command-line-options (opens new window)

说明

个人认为命令行没有必要一一掌握,因为绝大部分功能都可以通过配置来完成。且通过命令行指定功能这种方式要求每次输入同样参数,不利于固化启动方式。

最重要的当然是启动命令 run 了。

示例 指定配置文件启动

./filebeat run -e -c filebeat.yml -d "publish"
+./filebeat -e -c filebeat.yml -d "publish" # run 可以省略
+

# 模块

Filebeat 提供了一套预构建的模块,让您可以快速实施和部署日志监视解决方案,并附带示例仪表板和数据可视化。这些模块支持常见的日志格式,例如Nginx,Apache2和MySQL 等。

# 运行模块的步骤

  • 配置 elasticsearch 和 kibana
output.elasticsearch:
+  hosts: ["myEShost:9200"]
+  username: "elastic"
+  password: "elastic"
+setup.kibana:
+  host: "mykibanahost:5601"
+  username: "elastic" 
+  password: "elastic
+

username 和 password 是可选的,如果不需要认证则不填。

  • 初始化环境

执行下面命令,filebeat 会加载推荐索引模板。

./filebeat setup -e
+
  • 指定模块

执行下面命令,指定希望加载的模块。

./filebeat -e --modules system,nginx,mysql
+

参考

更多内容可以参考: 配置 filebeat 模块 (opens new window) | filebeat 支持模块 (opens new window)

# 原理

Filebeat 有两个主要组件:

harvester:负责读取一个文件的内容。它会逐行读取文件内容,并将内容发送到输出目的地。

prospector:负责管理 harvester 并找到所有需要读取的文件源。比如类型是日志,prospector 就会遍历制定路径下的所有匹配要求的文件。

filebeat.prospectors:
+- type: log
+  paths:
+    - /var/log/*.log
+    - /var/path2/*.log
+

Filebeat保持每个文件的状态,并经常刷新注册表文件中的磁盘状态。状态用于记住 harvester 正在读取的最后偏移量,并确保发送所有日志行。

Filebeat 将每个事件的传递状态存储在注册表文件中。所以它能保证事件至少传递一次到配置的输出,没有数据丢失。

# 资料

Beats 官方文档 (opens new window)

+ + + diff --git a/linux/soft/elastic/elastic-kibana.html b/linux/soft/elastic/elastic-kibana.html new file mode 100644 index 0000000..a9d9b5e --- /dev/null +++ b/linux/soft/elastic/elastic-kibana.html @@ -0,0 +1,71 @@ + + + + + + Elastic 技术栈之 Kibana | LINUX-TUTORIAL + + + + + + + + +

# Elastic 技术栈之 Kibana

# Discover

单击侧面导航栏中的 Discover ,可以显示 Kibana 的数据查询功能功能。

img

在搜索栏中,您可以输入Elasticsearch查询条件来搜索您的数据。您可以在 Discover 页面中浏览结果并在 Visualize 页面中创建已保存搜索条件的可视化。

当前索引模式显示在查询栏下方。索引模式确定提交查询时搜索哪些索引。要搜索一组不同的索引,请从下拉菜单中选择不同的模式。要添加索引模式(index pattern),请转至 Management/Kibana/Index Patterns 并单击 Add New

您可以使用字段名称和您感兴趣的值构建搜索。对于数字字段,可以使用比较运算符,如大于(>),小于(<)或等于(=)。您可以将元素与逻辑运算符 ANDORNOT 链接,全部使用大写。

默认情况下,每个匹配文档都显示所有字段。要选择要显示的文档字段,请将鼠标悬停在“可用字段”列表上,然后单击要包含的每个字段旁边的添加按钮。例如,如果只添加account_number,则显示将更改为包含五个帐号的简单列表:

img

# 查询语义

kibana 的搜索栏遵循 query-string-syntax (opens new window) 文档中所说明的查询语义。

这里说明一些最基本的查询语义。

查询字符串会被解析为一系列的术语和运算符。一个术语可以是一个单词(如:quick、brown)或用双引号包围的短语(如"quick brown")。

查询操作允许您自定义搜索 - 下面介绍了可用的选项。

# 字段名称

正如查询字符串查询中所述,将在搜索条件中搜索default_field,但可以在查询语法中指定其他字段:

例如:

  • 查询 status 字段中包含 active 关键字
status:active
+
  • title 字段包含 quickbrown 关键字。如果您省略 OR 运算符,则将使用默认运算符
title:(quick OR brown)
+title:(quick brown)
+
  • author 字段查找精确的短语 "john smith",即精确查找。
author:"John Smith"
+
  • 任意字段 book.titlebook.contentbook.date 都包含 quickbrown(注意我们需要如何使用 \* 表示通配符)
book.\*:(quick brown)
+
  • title 字段包含任意非 null 值
_exists_:title
+

# 通配符

ELK 提供了 ? 和 * 两个通配符。

  • ? 表示任意单个字符;
  • * 表示任意零个或多个字符。
qu?ck bro*
+

注意:通配符查询会使用大量的内存并且执行性能较为糟糕,所以请慎用。 提示:纯通配符 * 被写入 exsits (opens new window) 查询,从而提高了查询效率。因此,通配符 field:* 将匹配包含空值的文档,如:{“field”:“”},但是如果字段丢失或显示将值置为null则不匹配,如:“field”:null} 提示:在一个单词的开头(例如:*ing)使用通配符这种方式的查询量特别大,因为索引中的所有术语都需要检查,以防万一匹配。通过将 allow_leading_wildcard 设置为 false,可以禁用。

# 正则表达式

可以通过 / 将正则表达式包裹在查询字符串中进行查询

例:

name:/joh?n(ath[oa]n)/
+

支持的正则表达式语义可以参考:Regular expression syntax (opens new window)

# 模糊查询

我们可以使用 ~ 运算符来进行模糊查询。

例:

假设我们实际想查询

quick brown forks
+

但是,由于拼写错误,我们的查询关键字变成如下情况,依然可以查到想要的结果。

quikc\~ brwn\~ foks\~
+

这种模糊查询使用 Damerau-Levenshtein 距离来查找所有匹配最多两个更改的项。所谓的更改是指单个字符的插入,删除或替换,或者两个相邻字符的换位。

默认编辑距离为 2,但编辑距离为 1 应足以捕捉所有人类拼写错误的80%。它可以被指定为:

quikc\~1
+

# 近似检索

尽管短语查询(例如,john smith)期望所有的词条都是完全相同的顺序,但是近似查询允许指定的单词进一步分开或以不同的顺序排列。与模糊查询可以为单词中的字符指定最大编辑距离一样,近似搜索也允许我们指定短语中单词的最大编辑距离:

"fox quick"\~5
+

字段中的文本越接近查询字符串中指定的原始顺序,该文档就越被认为是相关的。当与上面的示例查询相比时,短语 "quick fox" 将被认为比 "quick brown fox" 更近似查询条件。

# 范围

可以为日期,数字或字符串字段指定范围。闭区间范围用方括号 [min TO max] 和开区间范围用花括号 {min TO max} 来指定。

我们不妨来看一些示例。

  • 2012 年的所有日子
date:[2012-01-01 TO 2012-12-31]
+
  • 数字 1 到 5
count:[1 TO 5]
+
  • alphaomega 之间的标签,不包括 alphaomega
tag:{alpha TO omega}
+
  • 10 以上的数字
count:[10 TO *]
+
  • 2012 年以前的所有日期
date:{* TO 2012-01-01}
+

此外,开区间和闭区间也可以组合使用

  • 数组 1 到 5,但不包括 5
count:[1 TO 5}
+

一边无界的范围也可以使用以下语法:

age:>10
+age:>=10
+age:<10
+age:<=10
+

当然,你也可以使用 AND 运算符来得到连个查询结果的交集

age:(>=10 AND <20)
+age:(+>=10 +<20)
+

# Boosting

使用操作符 ^ 使一个术语比另一个术语更相关。例如,如果我们想查找所有有关狐狸的文档,但我们对狐狸特别感兴趣:

quick^2 fox
+

默认提升值是1,但可以是任何正浮点数。 0到1之间的提升减少了相关性。

增强也可以应用于短语或组:

"john smith"^2   (foo bar)^4
+

# 布尔操作

默认情况下,只要一个词匹配,所有词都是可选的。搜索 foo bar baz 将查找包含 foobarbaz 中的一个或多个的任何文档。我们已经讨论了上面的default_operator,它允许你强制要求所有的项,但也有布尔运算符可以在查询字符串本身中使用,以提供更多的控制。

首选的操作符是 +(此术语必须存在)和 - (此术语不得存在)。所有其他条款是可选的。例如,这个查询:

quick brown +fox -news
+

这条查询意味着:

  • fox 必须存在
  • news 必须不存在
  • quick 和 brown 是可有可无的

熟悉的运算符 ANDORNOT(也写成 &&||!)也被支持。然而,这些操作符有一定的优先级:NOT 优先于 ANDAND 优先于 OR。虽然 +- 仅影响运算符右侧的术语,但 ANDOR 会影响左侧和右侧的术语。

# 分组

多个术语或子句可以用圆括号组合在一起,形成子查询

(quick OR brown) AND fox
+

可以使用组来定位特定的字段,或者增强子查询的结果:

status:(active OR pending) title:(full text search)^2
+

# 保留字

如果你需要使用任何在你的查询本身中作为操作符的字符(而不是作为操作符),那么你应该用一个反斜杠来转义它们。例如,要搜索(1 + 1)= 2,您需要将查询写为 \(1\+1\)\=2

保留字符是:+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /

无法正确地转义这些特殊字符可能会导致语法错误,从而阻止您的查询运行。

# 空查询

如果查询字符串为空或仅包含空格,则查询将生成一个空的结果集。

# Visualize

要想使用可视化的方式展示您的数据,请单击侧面导航栏中的 Visualize

Visualize工具使您能够以多种方式(如饼图、柱状图、曲线图、分布图等)查看数据。要开始使用,请点击蓝色的 Create a visualization+ 按钮。

https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png

有许多可视化类型可供选择。

https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png

下面,我们来看创建几个图标示例:

# Pie

您可以从保存的搜索中构建可视化文件,也可以输入新的搜索条件。要输入新的搜索条件,首先需要选择一个索引模式来指定要搜索的索引。

默认搜索匹配所有文档。最初,一个“切片”包含整个饼图:

https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png

要指定在图表中展示哪些数据,请使用Elasticsearch存储桶聚合。分组汇总只是将与您的搜索条件相匹配的文档分类到不同的分类中,也称为分组。

为每个范围定义一个存储桶:

  1. 单击 Split Slices
  2. Aggregation 列表中选择 Terms注意:这里的 Terms 是 Elk 采集数据时定义好的字段或标签。
  3. Field 列表中选择 level.keyword
  4. 点击 images/apply-changes-button.png 按钮来更新图表。

image.png

完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 Save 按钮。

# Vertical Bar

我们在展示一下如何创建柱状图。

  1. 点击蓝色的 Create a visualization+ 按钮。选择 Vertical Bar
  2. 选择索引模式。由于您尚未定义任何 bucket ,因此您会看到一个大栏,显示与默认通配符查询匹配的文档总数。
  3. 指定 Y 轴所代表的字段
  4. 指定 X 轴所代表的字段
  5. 点击 images/apply-changes-button.png 按钮来更新图表。

image.png

完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 Save 按钮。

# Dashboard

Dashboard 可以整合和共享 Visualize 集合。

  1. 点击侧面导航栏中的 Dashboard。
  2. 点击添加显示保存的可视化列表。
  3. 点击之前保存的 Visualize,然后点击列表底部的小向上箭头关闭可视化列表。
  4. 将鼠标悬停在可视化对象上会显示允许您编辑,移动,删除和调整可视化对象大小的容器控件。
+ + + diff --git a/linux/soft/elastic/elastic-logstash.html b/linux/soft/elastic/elastic-logstash.html new file mode 100644 index 0000000..d5eb24e --- /dev/null +++ b/linux/soft/elastic/elastic-logstash.html @@ -0,0 +1,166 @@ + + + + + + Elastic 技术栈之 Logstash 基础 | LINUX-TUTORIAL + + + + + + + + +

# Elastic 技术栈之 Logstash 基础

本文是 Elastic 技术栈(ELK)的 Logstash 应用。

如果不了解 Elastic 的安装、配置、部署,可以参考:Elastic 技术栈之快速入门 (opens new window)

# 简介

Logstash 可以传输和处理你的日志、事务或其他数据。

# 功能

Logstash 是 Elasticsearch 的最佳数据管道。

Logstash 是插件式管理模式,在输入、过滤、输出以及编码过程中都可以使用插件进行定制。Logstash 社区有超过 200 种可用插件。

# 工作原理

Logstash 有两个必要元素:inputoutput ,一个可选元素:filter

这三个元素,分别代表 Logstash 事件处理的三个阶段:输入 > 过滤器 > 输出。

img

  • input 负责从数据源采集数据。
  • filter 将数据修改为你指定的格式或内容。
  • output 将数据传输到目的地。

在实际应用场景中,通常输入、输出、过滤器不止一个。Logstash 的这三个元素都使用插件式管理方式,用户可以根据应用需要,灵活的选用各阶段需要的插件,并组合使用。

后面将对插件展开讲解,暂且不表。

# 设置

# 设置文件

  • logstash.yml:logstash 的默认启动配置文件
  • jvm.options:logstash 的 JVM 配置文件。
  • startup.options (Linux):包含系统安装脚本在 /usr/share/logstash/bin 中使用的选项为您的系统构建适当的启动脚本。安装 Logstash 软件包时,系统安装脚本将在安装过程结束时执行,并使用 startup.options 中指定的设置来设置用户,组,服务名称和服务描述等选项。

# logstash.yml 设置项

节选部分设置项,更多项请参考:https://www.elastic.co/guide/en/logstash/current/logstash-settings-file.html

参数 描述 默认值
node.name 节点名 机器的主机名
path.data Logstash及其插件用于任何持久性需求的目录。 LOGSTASH_HOME/data
pipeline.workers 同时执行管道的过滤器和输出阶段的工作任务数量。如果发现事件正在备份,或CPU未饱和,请考虑增加此数字以更好地利用机器处理能力。 Number of the host’s CPU cores
pipeline.batch.size 尝试执行过滤器和输出之前,单个工作线程从输入收集的最大事件数量。较大的批量处理大小一般来说效率更高,但是以增加的内存开销为代价。您可能必须通过设置 LS_HEAP_SIZE 变量来有效使用该选项来增加JVM堆大小。 125
pipeline.batch.delay 创建管道事件批处理时,在将一个尺寸过小的批次发送给管道工作任务之前,等待每个事件需要多长时间(毫秒)。 5
pipeline.unsafe_shutdown 如果设置为true,则即使在内存中仍存在inflight事件时,也会强制Logstash在关闭期间退出。默认情况下,Logstash将拒绝退出,直到所有接收到的事件都被推送到输出。启用此选项可能会导致关机期间数据丢失。 false
path.config 主管道的Logstash配置路径。如果您指定一个目录或通配符,配置文件将按字母顺序从目录中读取。 Platform-specific. See [dir-layout] (opens new window).
config.string 包含用于主管道的管道配置的字符串。使用与配置文件相同的语法。 None
config.test_and_exit 设置为true时,检查配置是否有效,然后退出。请注意,使用此设置不会检查grok模式的正确性。 Logstash可以从目录中读取多个配置文件。如果将此设置与log.level:debug结合使用,则Logstash将记录组合的配置文件,并注掉其源文件的配置块。 false
config.reload.automatic 设置为true时,定期检查配置是否已更改,并在配置更改时重新加载配置。这也可以通过SIGHUP信号手动触发。 false
config.reload.interval Logstash 检查配置文件更改的时间间隔。 3s
config.debug 设置为true时,将完全编译的配置显示为调试日志消息。您还必须设置log.level:debug。警告:日志消息将包括任何传递给插件配置作为明文的“密码”选项,并可能导致明文密码出现在您的日志! false
config.support_escapes 当设置为true时,带引号的字符串将处理转义字符。 false
modules 配置时,模块必须处于上表所述的嵌套YAML结构中。 None
http.host 绑定地址 "127.0.0.1"
http.port 绑定端口 9600
log.level 日志级别。有效选项:fatal > error > warn > info > debug > trace info
log.format 日志格式。json (JSON 格式)或 plain (原对象) plain
path.logs Logstash 自身日志的存储路径 LOGSTASH_HOME/logs
path.plugins 在哪里可以找到自定义的插件。您可以多次指定此设置以包含多个路径。

# 启动

# 命令行

通过命令行启动 logstash 的方式如下:

bin/logstash [options]
+

其中 [options] 是您可以指定用于控制 Logstash 执行的命令行标志。

在命令行上设置的任何标志都会覆盖 Logstash 设置文件(logstash.yml)中的相应设置,但设置文件本身不会更改。

虽然可以通过指定命令行参数的方式,来控制 logstash 的运行方式,但显然这么做很麻烦。

建议通过指定配置文件的方式,来控制 logstash 运行,启动命令如下:

bin/logstash -f logstash.conf
+

若想了解更多的命令行参数细节,请参考:https://www.elastic.co/guide/en/logstash/current/running-logstash-command-line.html

# 配置文件

上节,我们了解到,logstash 可以执行 bin/logstash -f logstash.conf ,按照配置文件中的参数去覆盖默认设置文件(logstash.yml)中的设置。

这节,我们就来学习一下这个配置文件如何配置参数。

# 配置文件结构

在工作原理一节中,我们已经知道了 Logstash 主要有三个工作阶段 input 、filter、output。而 logstash 配置文件文件结构也与之相对应:

input {}
+
+filter {}
+
+output {}
+

每个部分都包含一个或多个插件的配置选项。如果指定了多个过滤器,则会按照它们在配置文件中的显示顺序应用它们。

# 插件配置

插件的配置由插件名称和插件的一个设置块组成。

下面的例子中配置了两个输入文件配置:

input {
+  file {
+    path => "/var/log/messages"
+    type => "syslog"
+  }
+
+  file {
+    path => "/var/log/apache/access.log"
+    type => "apache"
+  }
+}
+

您可以配置的设置因插件类型而异。你可以参考: Input Plugins (opens new window), Output Plugins (opens new window), Filter Plugins (opens new window), 和 Codec Plugins (opens new window)

# 值类型

一个插件可以要求设置的值是一个特定的类型,比如布尔值,列表或哈希值。以下值类型受支持。

  • Array
  users => [ {id => 1, name => bob}, {id => 2, name => jane} ]
+
  • Lists
  path => [ "/var/log/messages", "/var/log/*.log" ]
+  uris => [ "http://elastic.co", "http://example.net" ]
+
  • Boolean
  ssl_enable => true
+
  • Bytes
  my_bytes => "1113"   # 1113 bytes
+  my_bytes => "10MiB"  # 10485760 bytes
+  my_bytes => "100kib" # 102400 bytes
+  my_bytes => "180 mb" # 180000000 bytes
+
  • Codec
  codec => "json"
+
  • Hash
match => {
+  "field1" => "value1"
+  "field2" => "value2"
+  ...
+}
+
  • Number
  port => 33
+
  • Password
  my_password => "password"
+
  • URI
  my_uri => "http://foo:bar@example.net"
+
  • Path
  my_path => "/tmp/logstash"
+
  • String

  • 转义字符

# 插件

# input

Logstash 支持各种输入选择 ,可以在同一时间从众多常用来源捕捉事件。能够以连续的流式传输方式,轻松地从您的日志、指标、Web 应用、数据存储以及各种 AWS 服务采集数据。

# 常用 input 插件

  • file:从文件系统上的文件读取,就像UNIX命令 tail -0F 一样
  • **syslog:**在众所周知的端口514上侦听系统日志消息,并根据RFC3164格式进行解析
  • **redis:**从redis服务器读取,使用redis通道和redis列表。 Redis经常用作集中式Logstash安装中的“代理”,它将来自远程Logstash“托运人”的Logstash事件排队。
  • **beats:**处理由Filebeat发送的事件。

更多详情请见:Input Plugins (opens new window)

# filter

过滤器是Logstash管道中的中间处理设备。如果符合特定条件,您可以将条件过滤器组合在一起,对事件执行操作。

# 常用 filter 插件

  • **grok:**解析和结构任意文本。 Grok目前是Logstash中将非结构化日志数据解析为结构化和可查询的最佳方法。

  • **mutate:**对事件字段执行一般转换。您可以重命名,删除,替换和修改事件中的字段。

  • **drop:**完全放弃一个事件,例如调试事件。

  • **clone:**制作一个事件的副本,可能会添加或删除字段。

  • **geoip:**添加有关IP地址的地理位置的信息(也可以在Kibana中显示惊人的图表!)

更多详情请见:Filter Plugins (opens new window)

# output

输出是Logstash管道的最后阶段。一个事件可以通过多个输出,但是一旦所有输出处理完成,事件就完成了执行。

# 常用 output 插件

  • **elasticsearch:**将事件数据发送给 Elasticsearch(推荐模式)。
  • **file:**将事件数据写入文件或磁盘。
  • **graphite:**将事件数据发送给 graphite(一个流行的开源工具,存储和绘制指标。 http://graphite.readthedocs.io/en/latest/)。
  • **statsd:**将事件数据发送到 statsd (这是一种侦听统计数据的服务,如计数器和定时器,通过UDP发送并将聚合发送到一个或多个可插入的后端服务)。

更多详情请见:Output Plugins (opens new window)

# codec

用于格式化对应的内容。

# 常用 codec 插件

  • **json:**以JSON格式对数据进行编码或解码。
  • **multiline:**将多行文本事件(如java异常和堆栈跟踪消息)合并为单个事件。

更多插件请见:Codec Plugins (opens new window)

# 实战

前面的内容都是对 Logstash 的介绍和原理说明。接下来,我们来实战一些常见的应用场景。

# 传输控制台数据

stdin input 插件从标准输入读取事件。这是最简单的 input 插件,一般用于测试场景。

应用

(1)创建 logstash-input-stdin.conf

input { stdin { } }
+output {
+  elasticsearch { hosts => ["localhost:9200"] }
+  stdout { codec => rubydebug }
+}
+

更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-stdin.html

(2)执行 logstash,使用 -f 来指定你的配置文件:

bin/logstash -f logstash-input-stdin.conf
+

# 传输 logback 日志

elk 默认使用的 Java 日志工具是 log4j2 ,并不支持 logback 和 log4j。

想使用 logback + logstash ,可以使用 logstash-logback-encoder (opens new window)logstash-logback-encoder (opens new window) 提供了 UDP / TCP / 异步方式来传输日志数据到 logstash。

如果你使用的是 log4j ,也不是不可以用这种方式,只要引入桥接 jar 包即可。如果你对 log4j 、logback ,或是桥接 jar 包不太了解,可以参考我的这篇博文:细说 Java 主流日志工具库 (opens new window)

# TCP 应用

  1. logstash 配置

    (1)创建 logstash-input-tcp.conf

input {
+tcp {
+  port => 9251
+  codec => json_lines
+  mode => server
+}
+}
+output {
+ elasticsearch { hosts => ["localhost:9200"] }
+ stdout { codec => rubydebug }
+}
+

更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-tcp.html

(2)执行 logstash,使用 -f 来指定你的配置文件:bin/logstash -f logstash-input-udp.conf

  1. java 应用配置

    (1)在 Java 应用的 pom.xml 中引入 jar 包:

<dependency>
+ <groupId>net.logstash.logback</groupId>
+ <artifactId>logstash-logback-encoder</artifactId>
+ <version>4.11</version>
+</dependency>
+
+<!-- logback 依赖包 -->
+<dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <version>1.2.3</version>
+</dependency>
+<dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+</dependency>
+<dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-access</artifactId>
+ <version>1.2.3</version>
+</dependency>
+

(2)接着,在 logback.xml 中添加 appender

<appender name="ELK-TCP" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+ <!--
+ destination 是 logstash 服务的 host:port,
+ 相当于和 logstash 建立了管道,将日志数据定向传输到 logstash
+ -->
+ <destination>192.168.28.32:9251</destination>
+ <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
+</appender>
+<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
+ <appender-ref ref="ELK-TCP" />
+</logger>
+

(3)接下来,就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:细说 Java 主流日志工具库 (opens new window)

实例:我的logback.xml (opens new window)

# UDP 应用

UDP 和 TCP 的使用方式大同小异。

  1. logstash 配置

    (1)创建 logstash-input-udp.conf

input {
+udp {
+  port => 9250
+  codec => json
+}
+}
+output {
+ elasticsearch { hosts => ["localhost:9200"] }
+ stdout { codec => rubydebug }
+}
+

更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-udp.html

(2)执行 logstash,使用 -f 来指定你的配置文件:bin/logstash -f logstash-input-udp.conf

  1. java 应用配置

    (1)在 Java 应用的 pom.xml 中引入 jar 包:

    TCP 应用 一节中的引入依赖包完全相同。

    (2)接着,在 logback.xml 中添加 appender

<appender name="ELK-UDP" class="net.logstash.logback.appender.LogstashSocketAppender">
+  <host>192.168.28.32</host>
+  <port>9250</port>
+</appender>
+<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
+  <appender-ref ref="ELK-UDP" />
+</logger>
+

(3)接下来,就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:细说 Java 主流日志工具库 (opens new window)

实例:我的logback.xml (opens new window)

# 传输文件

在 Java Web 领域,需要用到一些重要的工具,例如 Tomcat 、Nginx 、Mysql 等。这些不属于业务应用,但是它们的日志数据对于定位问题、分析统计同样很重要。这时无法使用 logback 方式将它们的日志传输到 logstash。

如何采集这些日志文件呢?别急,你可以使用 logstash 的 file input 插件。

需要注意的是,传输文件这种方式,必须在日志所在的机器上部署 logstash 。

应用

logstash 配置

(1)创建 logstash-input-file.conf

input {
+	file {
+		path => ["/var/log/nginx/access.log"]
+		type => "nginx-access-log"
+		start_position => "beginning"
+	}
+}
+
+output {
+	if [type] == "nginx-access-log" {
+		elasticsearch {
+			hosts => ["localhost:9200"]
+			index => "nginx-access-log"
+		}
+	}
+}
+

(2)执行 logstash,使用 -f 来指定你的配置文件:bin/logstash -f logstash-input-file.conf

更多配置项可以参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html

# 小技巧

# 启动、终止应用

如果你的 logstash 每次都是通过指定配置文件方式启动。不妨建立一个启动脚本。

# cd xxx 进入 logstash 安装目录下的 bin 目录
+logstash -f logstash.conf
+

如果你的 logstash 运行在 linux 系统下,不妨使用 nohup 来启动一个守护进程。这样做的好处在于,即使关闭终端,应用仍会运行。

创建 startup.sh

nohup ./logstash -f logstash.conf >> nohup.out 2>&1 &
+

终止应用没有什么好方法,你只能使用 ps -ef | grep logstash ,查出进程,将其kill 。不过,我们可以写一个脚本来干这件事:

创建 shutdown.sh

脚本不多解释,请自行领会作用。

PID=`ps -ef | grep logstash | awk '{ print $2}' | head -n 1`
+kill -9 ${PID}
+

# 资料

# 推荐阅读

+ + + diff --git a/linux/soft/elastic/elastic-quickstart.html b/linux/soft/elastic/elastic-quickstart.html new file mode 100644 index 0000000..771bcae --- /dev/null +++ b/linux/soft/elastic/elastic-quickstart.html @@ -0,0 +1,100 @@ + + + + + + Elastic 技术栈之快速入门 | LINUX-TUTORIAL + + + + + + + + +

# Elastic 技术栈之快速入门

# 概念

# ELK 是什么

ELK 是 elastic 公司旗下三款产品 ElasticSearch (opens new window)Logstash (opens new window)Kibana (opens new window) 的首字母组合。

ElasticSearch (opens new window) 是一个基于 Lucene (opens new window) 构建的开源,分布式,RESTful 搜索引擎。

Logstash (opens new window) 传输和处理你的日志、事务或其他数据。

Kibana (opens new window) 将 Elasticsearch 的数据分析并渲染为可视化的报表。

# 为什么使用 ELK ?

对于有一定规模的公司来说,通常会很多个应用,并部署在大量的服务器上。运维和开发人员常常需要通过查看日志来定位问题。如果应用是集群化部署,试想如果登录一台台服务器去查看日志,是多么费时费力。

而通过 ELK 这套解决方案,可以同时实现日志收集、日志搜索和日志分析的功能。

# Elastic 架构

img

说明

以上是 ELK 技术栈的一个架构图。从图中可以清楚的看到数据流向。

Beats (opens new window) 是单一用途的数据传输平台,它可以将多台机器的数据发送到 Logstash 或 ElasticSearch。但 Beats 并不是不可或缺的一环,所以本文中暂不介绍。

Logstash (opens new window) 是一个动态数据收集管道。支持以 TCP/UDP/HTTP 多种方式收集数据(也可以接受 Beats 传输来的数据),并对数据做进一步丰富或提取字段处理。

ElasticSearch (opens new window) 是一个基于 JSON 的分布式的搜索和分析引擎。作为 ELK 的核心,它集中存储数据。

Kibana (opens new window) 是 ELK 的用户界面。它将收集的数据进行可视化展示(各种报表、图形化数据),并提供配置、管理 ELK 的界面。

# 安装

# 准备

ELK 要求本地环境中安装了 JDK 。如果不确定是否已安装,可使用下面的命令检查:

java -version
+

注意

本文使用的 ELK 是 6.0.0,要求 jdk 版本不低于 JDK8。

友情提示:安装 ELK 时,三个应用请选择统一的版本,避免出现一些莫名其妙的问题。例如:由于版本不统一,导致三个应用间的通讯异常。

# Elasticsearch

安装步骤如下:

  1. elasticsearch 官方下载地址 (opens new window)下载所需版本包并解压到本地。
  2. 运行 bin/elasticsearch (Windows 上运行 bin\elasticsearch.bat
  3. 验证运行成功:linux 上可以执行 curl http://localhost:9200/ ;windows 上可以用访问 REST 接口的方式来访问 http://localhost:9200/

说明

Linux 上可以执行下面的命令来下载压缩包:

curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.tar.gz
+

Mac 上可以执行以下命令来进行安装:

brew install elasticsearch
+

Windows 上可以选择 MSI 可执行安装程序,将应用安装到本地。

# Logstash

安装步骤如下:

  1. logstash 官方下载地址 (opens new window)下载所需版本包并解压到本地。

  2. 添加一个 logstash.conf 文件,指定要使用的插件以及每个插件的设置。举个简单的例子:

    input { stdin { } }
    +output {
    +  elasticsearch { hosts => ["localhost:9200"] }
    +  stdout { codec => rubydebug }
    +}
    +
  3. 运行 bin/logstash -f logstash.conf (Windows 上运行bin/logstash.bat -f logstash.conf

# Kibana

安装步骤如下:

  1. kibana 官方下载地址 (opens new window)下载所需版本包并解压到本地。
  2. 修改 config/kibana.yml 配置文件,设置 elasticsearch.url 指向 Elasticsearch 实例。
  3. 运行 bin/kibana (Windows 上运行 bin\kibana.bat
  4. 在浏览器上访问 http://localhost:5601

# 安装 FAQ

# elasticsearch 不允许以 root 权限来运行

**问题:**在 Linux 环境中,elasticsearch 不允许以 root 权限来运行。

如果以 root 身份运行 elasticsearch,会提示这样的错误:

can not run elasticsearch as root
+

**解决方法:**使用非 root 权限账号运行 elasticsearch

# 创建用户组
+groupadd elk
+# 创建新用户,-g elk 设置其用户组为 elk,-p elk 设置其密码为 elk
+useradd elk -g elk -p elk
+# 更改 /opt 文件夹及内部文件的所属用户及组为 elk:elk
+chown -R elk:elk /opt # 假设你的 elasticsearch 安装在 opt 目录下
+# 切换账号
+su elk
+

# vm.max_map_count 不低于 262144

问题:vm.max_map_count 表示虚拟内存大小,它是一个内核参数。elasticsearch 默认要求 vm.max_map_count 不低于 262144。

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
+

解决方法:

你可以执行以下命令,设置 vm.max_map_count ,但是重启后又会恢复为原值。

sysctl -w vm.max_map_count=262144
+

持久性的做法是在 /etc/sysctl.conf 文件中修改 vm.max_map_count 参数:

echo "vm.max_map_count=262144" > /etc/sysctl.conf
+sysctl -p
+

注意

如果运行环境为 docker 容器,可能会限制执行 sysctl 来修改内核参数。

这种情况下,你只能选择直接修改宿主机上的参数了。

# nofile 不低于 65536

问题: nofile 表示进程允许打开的最大文件数。elasticsearch 进程要求可以打开的最大文件数不低于 65536。

max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
+

解决方法:

/etc/security/limits.conf 文件中修改 nofile 参数:

echo "* soft nofile 65536" > /etc/security/limits.conf
+echo "* hard nofile 131072" > /etc/security/limits.conf
+

# nproc 不低于 2048

问题: nproc 表示最大线程数。elasticsearch 要求最大线程数不低于 2048。

max number of threads [1024] for user [user] is too low, increase to at least [2048]
+

解决方法:

/etc/security/limits.conf 文件中修改 nproc 参数:

echo "* soft nproc 2048" > /etc/security/limits.conf
+echo "* hard nproc 4096" > /etc/security/limits.conf
+

# Kibana No Default Index Pattern Warning

**问题:**安装 ELK 后,访问 kibana 页面时,提示以下错误信息:

Warning No default index pattern. You must select or create one to continue.
+...
+Unable to fetch mapping. Do you have indices matching the pattern?
+

这就说明 logstash 没有把日志写入到 elasticsearch。

解决方法:

检查 logstash 与 elasticsearch 之间的通讯是否有问题,一般问题就出在这。

# 使用

本人使用的 Java 日志方案为 slf4j + logback,所以这里以 logback 来讲解。

# Java 应用输出日志到 ELK

修改 logstash.conf 配置

首先,我们需要修改一下 logstash 服务端 logstash.conf 中的配置

input { 
+  # stdin { }
+  tcp { 
+    # host:port就是上面appender中的 destination,
+	# 这里其实把logstash作为服务,开启9250端口接收logback发出的消息 
+    host => "127.0.0.1" port => 9250 mode => "server" tags => ["tags"] codec => json_lines 
+  }
+}
+output {
+  elasticsearch { hosts => ["localhost:9200"] }
+  stdout { codec => rubydebug }
+}
+

说明

这个 input 中的配置其实是 logstash 服务端监听 9250 端口,接收传递来的日志数据。

然后,在 Java 应用的 pom.xml 中引入 jar 包:

<dependency>
+  <groupId>net.logstash.logback</groupId>
+  <artifactId>logstash-logback-encoder</artifactId>
+  <version>4.11</version>
+</dependency>
+

接着,在 logback.xml 中添加 appender

<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+  <!--
+  destination 是 logstash 服务的 host:port,
+  相当于和 logstash 建立了管道,将日志数据定向传输到 logstash
+  -->
+  <destination>127.0.0.1:9250</destination>
+  <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
+</appender>
+<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
+  <appender-ref ref="LOGSTASH" />
+</logger>
+

大功告成,此后,io.github.dunwu.spring 包中的 TRACE 及以上级别的日志信息都会被定向输出到 logstash 服务。

img

# 资料

+ + + diff --git a/linux/soft/elastic/index.html b/linux/soft/elastic/index.html new file mode 100644 index 0000000..45671bc --- /dev/null +++ b/linux/soft/elastic/index.html @@ -0,0 +1,42 @@ + + + + + + Elastic 技术栈 | LINUX-TUTORIAL + + + + + + + + +

# Elastic 技术栈

Elastic 技术栈通常被用来作为日志中心。

ELK 是 elastic 公司旗下三款产品 ElasticSearch (opens new window)Logstash (opens new window)Kibana (opens new window) 的首字母组合。

ElasticSearch (opens new window) 是一个基于 Lucene (opens new window) 构建的开源,分布式,RESTful 搜索引擎。

Logstash (opens new window) 传输和处理你的日志、事务或其他数据。

Kibana (opens new window) 将 Elasticsearch 的数据分析并渲染为可视化的报表。

Elastic 技术栈,在 ELK 的基础上扩展了一些新的产品,如:Beats (opens new window)X-Pack (opens new window)

# 目录

Elastic 技术栈之入门指南

Elastic 技术栈之 Logstash 基础

# 资源

官方资源

Elastic 官方文档 (opens new window)

第三方工具

logstash-logback-encoder (opens new window)

教程

Elasticsearch 权威指南(中文版) (opens new window)

ELK Stack权威指南 (opens new window)

博文

Elasticsearch+Logstash+Kibana教程 (opens new window)

ELK(Elasticsearch、Logstash、Kibana)安装和配置 (opens new window)

+ + + diff --git a/linux/soft/fastdfs.html b/linux/soft/fastdfs.html new file mode 100644 index 0000000..be5b886 --- /dev/null +++ b/linux/soft/fastdfs.html @@ -0,0 +1,43 @@ + + + + + + FastDFS | LINUX-TUTORIAL + + + + + + + + +

# FastDFS

# 简介

FastDFS 是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。 +FastDFS 为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

# 概念

FastDFS 服务端有三个角色:跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)。

tracker server:跟踪服务器,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的枢纽。相比 GFS 中的 master 更为精简,不记录文件索引信息,占用的内存量很少。

Tracker 是 FastDFS 的协调者,负责管理所有的 storage server 和 group,每个 storage 在启动后会连接 Tracker,告知自己所属的 group 等信息,并保持周期性的心跳,tracker 根据 storage 的心跳信息,建立 group==>[storage server list]的映射表。

Tracker 需要管理的元信息很少,会全部存储在内存中;另外 tracker 上的元信息都是由 storage 汇报的信息生成的,本身不需要持久化任何数据,这样使得 tracker 非常容易扩展,直接增加 tracker 机器即可扩展为 tracker cluster 来服务,cluster 里每个 tracker 之间是完全对等的,所有的 tracker 都接受 stroage 的心跳信息,生成元数据信息来提供读写服务。

storage server:存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。Storage server 直接利用 OS 的文件系统调用管理文件。

Storage server(后简称 storage)以组(卷,group 或 volume)为单位组织,一个 group 内包含多台 storage 机器,数据互为备份,存储空间以 group 内容量最小的 storage 为准,所以建议 group 内的多个 storage 尽量配置相同,以免造成存储空间的浪费。

以 group 为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group 内 storage server 数量即为该 group 的副本数),比如将不同应用数据存到不同的 group 就能隔离应用数据,同时还可根据应用的访问特性来将应用分配到不同的 group 来做负载均衡;缺点是 group 的容量受单机存储容量的限制,同时当 group 内有机器坏掉时,数据恢复只能依赖 group 内地其他机器,使得恢复时间会很长。

group 内每个 storage 的存储依赖于本地文件系统,storage 可配置多个数据存储目录,比如有 10 块磁盘,分别挂载在/data/disk1-/data/disk10,则可将这 10 个目录都配置为 storage 的数据存储目录。

storage 接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在 storage 第一次启动时,会在每个数据存储目录里创建 2 级子目录,每级 256 个,总共 65536 个文件,新写的文件会以 hash 的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。

client:客户端,作为业务请求的发起方,通过专有接口,使用 TCP/IP 协议与跟踪器服务器或存储节点进行数据交互。FastDFS 向使用者提供基本文件访问接口,比如 upload、download、append、delete 等,以客户端库的方式提供给用户使用。

另外两个概念:

group :组, 也可称为卷。 同组内服务器上的文件是完全相同的 ,同一组内的 storage server 之间是对等的, 文件上传、 删除等操作可以在任意一台 storage server 上进行 。

meta data :文件相关属性,键值对( Key Value Pair) 方式,如:width=1024,heigth=768 。

img

Tracker 相当于 FastDFS 的大脑,不论是上传还是下载都是通过 tracker 来分配资源;客户端一般可以使用 ngnix 等静态服务器来调用或者做一部分的缓存;存储服务器内部分为卷(或者叫做组),卷于卷之间是平行的关系,可以根据资源的使用情况随时增加,卷内服务器文件相互同步备份,以达到容灾的目的。

# 参考资料

+ + + diff --git a/linux/soft/gitlab-ops.html b/linux/soft/gitlab-ops.html new file mode 100644 index 0000000..02f0c47 --- /dev/null +++ b/linux/soft/gitlab-ops.html @@ -0,0 +1,122 @@ + + + + + + Gitlab 运维 | LINUX-TUTORIAL + + + + + + + + +

# Gitlab 运维

# 一、gitlab 安装

# Gitlab 的普通安装

# 下载

进入官方下载地址:https://about.gitlab.com/install/ ,如下图,选择合适的版本。

img

以 CentOS7 为例:

# 安装和配置必要依赖

在系统防火墙中启用 HTTP 和 SSH

sudo yum install -y curl policycoreutils-python openssh-server
+sudo systemctl enable sshd
+sudo systemctl start sshd
+sudo firewall-cmd --permanent --add-service=http
+sudo systemctl reload firewalld
+

安装 Postfix ,使得 Gitlab 可以发送通知邮件

sudo yum install postfix
+sudo systemctl enable postfix
+sudo systemctl start postfix
+

# 添加 Gitlab yum 仓库并安装包

添加 Gitlab yum 仓库

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
+

通过 yum 安装 gitlab-ce

sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce
+

安装完成后,即可通过默认的 root 账户进行登录。更多细节可以参考:documentation for detailed instructions on installing and configuration (opens new window)

# Gitlab 的 Docker 安装

拉取镜像

docker pull docker.io/gitlab/gitlab-ce
+

启动

docker run -d \
+    --hostname gitlab.zp.io \
+    --publish 8443:443 --publish 80:80 --publish 2222:22 \
+    --name gitlab \
+    --restart always \
+    --volume $GITLAB_HOME/config:/etc/gitlab \
+    --volume $GITLAB_HOME/logs:/var/log/gitlab \
+    --volume $GITLAB_HOME/data:/var/opt/gitlab \
+    gitlab/gitlab-ce
+

img

# 自签名证书

首先,创建认证目录

sudo mkdir -p /etc/gitlab/ssl
+sudo chmod 700 /etc/gitlab/ssl
+

(1)创建 Private Key

sudo openssl genrsa -des3 -out /etc/gitlab/ssl/gitlab.domain.com.key 2048
+

会提示输入密码,请记住

(2)生成 Certificate Request

sudo openssl req -new -key /etc/gitlab/ssl/gitlab.domain.com.key -out /etc/gitlab/ssl/gitlab.domain.com.csr
+

根据提示,输入信息

Country Name (2 letter code) [XX]:CN
+State or Province Name (full name) []:JS
+Locality Name (eg, city) [Default City]:NJ
+Organization Name (eg, company) [Default Company Ltd]:xxxxx
+Organizational Unit Name (eg, section) []:
+Common Name (eg, your name or your server's hostname) []:gitlab.xxxx.io
+Email Address []:
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+

(3)移除 Private Key 中的密码短语

sudo cp -v /etc/gitlab/ssl/gitlab.domain.com.{key,original}
+sudo openssl rsa -in /etc/gitlab/ssl/gitlab.domain.com.original -out /etc/gitlab/ssl/gitlab.domain.com.key
+sudo rm -v /etc/gitlab/ssl/gitlab.domain.com.original
+

(4)设置文件权限

sudo chmod 600 /etc/gitlab/ssl/gitlab.domain.com.*
+

# 二、gitlab-ci-multi-runner 安装

参考:https://docs.gitlab.com/runner/install/

# 常规安装 gitlab-ci-multi-runner

# 下载

sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
+

# 配置执行权限

sudo chmod +x /usr/local/bin/gitlab-runner
+

# 如果想使用 Docker,安装 Docker(可选的)

curl -sSL https://get.docker.com/ | sh
+

# 创建 CI 用户

sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
+

# 安装并启动服务

sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
+sudo gitlab-runner start
+

# 注册 Runner

(1)执行命令:

sudo gitlab-runner register
+

(2)输入 Gitlab URL 和 令牌

URL 和令牌信息在 Gitlab 的 Runner 管理页面获取:

img

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
+https://gitlab.com
+
+Please enter the gitlab-ci token for this runner
+xxx
+

(3)输入 Runner 的描述

 Please enter the gitlab-ci description for this runner
+ [hostame] my-runner
+

(4)输入 Runner 相关的标签

 Please enter the gitlab-ci tags for this runner (comma separated):
+ my-tag,another-tag
+

(5)输入 Runner 执行器

 Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
+ docker
+

如果想选择 Docker 作为执行器,你需要指定默认镜像( .gitlab-ci.yml 中没有此配置)

 Please enter the Docker image (eg. ruby:2.1):
+ alpine:latest
+

# Docker 安装 gitlab-ci-multi-runner

拉取镜像

docker pull docker.io/gitlab/gitlab-runner
+

启动

docker run -d --name gitlab-runner --restart always \
+   -v /srv/gitlab-runner/config:/etc/gitlab-runner \
+   -v /var/run/docker.sock:/var/run/docker.sock \
+   gitlab/gitlab-runner:latest
+

# 三、gitlab 配置

# 基本配置

sudo vim /etc/gitlab/gitlab.rb
+external_url 'https://gitlab.domain.com'
+

# gitlab 网站 https:

nginx['redirect_http_to_https'] = true
+

# gitlab ci 网站 https:

ci_nginx['redirect_http_to_https'] = true
+

# 复制证书到 gitlab 目录:

sudo cp /etc/gitlab/ssl/gitlab.domain.com.crt /etc/gitlab/trusted-certs/
+

# gitlab 重新配置+更新:

sudo gitlab-ctl reconfigure
+sudo gitlab-ctl restart
+

# 创建你的 SSH key

  1. 使用 Gitlab 的第一步是生成你自己的 SSH 密钥对(Github 也类似)。

  2. 登录 Gitlab

  3. 打开 Profile settings.

img

  1. 跳转到 SSH keys tab 页

img

  1. 黏贴你的 SSH 公钥内容到 Key 文本框

img

  1. 为了便于识别,你可以为其命名

img

  1. 点击 Add key 将 SSH 公钥添加到 GitLab

img

# 创建项目

img

输入项目信息,点击 Create project 按钮,在 Gitlab 创建项目。

img

# 克隆项目到本地

可以选择 SSH 或 HTTPS 方式克隆项目到本地(推荐 SSH)

拷贝项目地址,然后在本地执行 git clone <url>

# 创建 Issue

依次点击 Project’s Dashboard > Issues > New Issue 可以新建 Issue

img

在项目中直接添加 issue

img

在未关闭 issue 中,点击 New Issue 添加 issue

img

通过项目面板添加 issue

img

通过 issue 面板添加 issue

img

# 四、gitlab 权限配置

# 用户组的权限

  • 用户组有这几种权限的概念:Guest、Reporter、Developer、Master、Owner
  • 这个概念在设置用户组的时候会遇到,叫做:Add user(s) to the group,比如链接:https://<gitlab_host>/<group>
行为 Guest Reporter Developer Master Owner
浏览组
编辑组
创建项目
管理组成员
移除组

# 五、备份/迁移/升级

# 备份

# 手动备份

执行 gitlab-rake gitlab:backup:create 开始备份全量数据,成功后,会在 /var/opt/gitlab/backups 下生产一个名称类似 1585910556_2020_04_03_11.3.0_gitlab_backup.tar 的压缩包。

# 定时自动备份

可以利用 crontab 来定时执行备份命令。

执行 vim /etc/crontabcrontab -e 手动编辑定时任务。

# 迁移

迁移前,需要确保新老机器的 Gitlab 版本号一致。

将备份的压缩包拷贝到新机器的备份路径下(默认为 /var/opt/gitlab/backups)。

(1)将备份文件权限修改为 777,不然可能恢复的时候会出现权限不够,不能解压的问题

chmod 777 1585910556_2020_04_03_11.3.0_gitlab_backup.tar
+

(2)停止相关数据连接服务

gitlab-ctl stop unicorn
+gitlab-ctl stop sidekiq
+

(3)从备份文件中恢复 Gitlab

# gitlab-rake gitlab:backup:restore BACKUP=备份文件编号
+gitlab-rake gitlab:backup:restore BACKUP=1585910556_2020_04_03_11.3.0
+

# 升级

升级前,一定要做好备份,记录当前 gitlab 的版本号。

第一步还是使用官方命令进行升级。

sudo yum install -y gitlab-ce
+

如果下载速度理想,就无需手动升级安装。不理想就需要停止自动更新,并手动下载安装包

访问官方地址,下载对应版本,对应系统的安装包。

注:可以根据自动升级时下载的版本,选择对应文件。

https://packages.gitlab.com/gitlab/gitlab-ce
+

安装包手动上传至服务器,并替换下载未完成的安装包。下面是升级缓存地址:

/var/cache/yum/x86_64/7/gitlab_gitlab-ce/packages/
+

再次执行官方升级命令即可完成自动安装。

# 参考资料

+ + + diff --git a/linux/soft/index.html b/linux/soft/index.html new file mode 100644 index 0000000..97d0aa9 --- /dev/null +++ b/linux/soft/index.html @@ -0,0 +1,48 @@ + + + + + + 软件安装配置 | LINUX-TUTORIAL + + + + + + + + + + + + diff --git a/linux/soft/jdk-install.html b/linux/soft/jdk-install.html new file mode 100644 index 0000000..42f12bc --- /dev/null +++ b/linux/soft/jdk-install.html @@ -0,0 +1,48 @@ + + + + + + JDK 安装 | LINUX-TUTORIAL + + + + + + + + +

# JDK 安装

关键词:JDK, JAVA_HOME, CLASSPATH, PATH

# JDK 安装步骤

JDK 安装步骤:

(1)下载 JDK

a. 进入 Java 官网下载页面 (opens new window)

b. 选择需要的版本:

img

c. 选择对应操作系统的安装包:

Windows 系统选择 exe 安装包;Mac 系统选择 dmp 安装包;Linux 系统选择 tar.gz 压缩包(RedHat 发行版可以安装 rpm 包)。

img

(2)运行安装包,按提示逐步安装

(3)配置系统环境变量:JAVA_HOME, CLASSPATH, PATH

(4)验证 Java 是否安装成功

# Windows 系统安装方法

(1)下载 JDK

需要根据 Windows 系统实际情况,选择 exe 安装文件:

  • 32 位计算机选择 Windows x86
  • 64 位计算机选择 Windows x64

(2)运行安装包,按提示逐步安装

(3)配置系统环境变量

a. 安装完成后,右击"我的电脑",点击"属性",选择"高级系统设置";

img

b. 选择"高级"选项卡,点击"环境变量";

img

然后就会出现如下图所示的画面:

在"系统变量"中设置 3 项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击"编辑",不存在则点击"新建"。

变量设置参数如下:

  • 变量名:JAVA_HOME

  • 变量值:C:\Program Files (x86)\Java\jdk1.8.0_91 // 要根据自己的实际路径配置

  • 变量名:CLASSPATH

  • 变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; //记得前面有个"."

  • 变量名:Path

  • 变量值:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

(4)验证 Java 是否安装成功

a. "开始"->"运行",键入"cmd";

b. 键入命令: java -versionjavajavac 几个命令,出现以下信息,说明环境变量配置成功;

img

# Linux 系统安装方法

(1)下载 JDK

需要根据 Linux 系统实际情况,选择 tar.gz 压缩包:

  • 32 位计算机选择 Linux x86
  • 64 位计算机选择 Linux x64

(2)解压压缩包到本地

$ tar -zxf jdk-8u162-linux-x64.tar.gz
+

(3)配置系统环境变量

执行 /etc/profile 命令,添加以下内容:

# JDK 的根路径
+export JAVA_HOME=/opt/java/jdk1.8.0_162
+export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
+export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
+

执行 source /etc/profile ,立即生效

(4)验证 Java 是否安装成功

执行 java -version 命令,验证安装是否成功。

# RedHat 发行版本使用 rpm 安装方法

(1)下载 JDK

下载 rpm 安装包

(2)选择一个合适的版本安装

$ rpm -ivh jdk-8u181-linux-x64.rpm
+

安装成功后,默认安装路径在 /usr/local 下:

(3)设置环境变量,同压缩包安装。

(4)检验是否安装成功,执行 java -version 命令

# 更多内容

+ + + diff --git a/linux/soft/jenkins-ops.html b/linux/soft/jenkins-ops.html new file mode 100644 index 0000000..fee3691 --- /dev/null +++ b/linux/soft/jenkins-ops.html @@ -0,0 +1,67 @@ + + + + + + Jenkins 运维 | LINUX-TUTORIAL + + + + + + + + +

# Jenkins 运维

环境要求

  • JDK:JDK7+,官网推荐是 JDK 8
  • Jenkins:2.190.1

# Jenkins 简介

# Jenkins 是什么

Jenkins 是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。

Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。

# CI/CD 是什么

CI(Continuous integration,中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。借用网络图片对 CI 加以理解。

img

CD(Continuous Delivery, 中文意思持续交付)是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。下图反应的是 CI/CD 的大概工作模式。

img

# Jenkins 安装

更详细内容请参考:Jenkins 官方安装文档 (opens new window)

# War 包部署

安装步骤如下:

(1)下载并解压到本地

进入官网下载地址 (opens new window),选择合适的版本下载。

我选择的是最新稳定 war 版本 2.89.4:http://mirrors.jenkins.io/war-stable/latest/jenkins.war

我个人喜欢存放在:/opt/software/jenkins

mkdir -p /opt/software/jenkins
+wget -O /opt/software/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.wa
+

(2)启动

如果你和我一样,选择 war 版本,那么你可以将 war 移到 Tomcat 的 webapps 目录下,通过 Tomcat 来启动。

当然,也可以通过 java -jar 方式来启动。

cd /opt/software/jenkins
+nohup java -jar jenkins.war --httpPort=8080 >> nohup.out 2>&1 &
+

# rpm 包部署

(1)下载安装

sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
+sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
+yum install jenkins
+

(2)启动

systemctl start jenkins
+

# 访问

  1. 打开浏览器进入链接 http://localhost:8080.
  2. 按照说明完成安装.

# Jenkins 基本使用

Jenkins 是一个强大的 CI 工具,虽然本身使用 Java 开发,但也能用来做其他语言开发的项目 CI。下面讲解如何使用 Jenkins 创建一个构建任务。

登录 Jenkins, 点击左侧的新建,创建新的构建任务。

img

跳转到如下界面。任务名称可以自行设定,但需要全局唯一。输入名称后选择构建一个自由风格的软件项目(其他选项不作介绍)。并点击下方的确定按钮即创建了一个构建任务。之后会自动跳转到该 job 的配置页面。

img

新建自由风格的软件项目

下图是构建任务设置界面,可以看到上方的几个选项**"General", "源码管理", "构建触发器","构建环境", "构建", "构建后操作"**。下面逐一介绍。

img

# General

General 是构建任务的一些基本配置。名称,描述之类的。

img

重要配置项:

  • Description:对构建任务的描述。
  • Discard old builds:服务器资源是有限的,有时候保存了太多的历史构建,会导致 Jenkins 速度变慢,并且服务器硬盘资源也会被占满。当然下方的"保持构建天数" 和 保持构建的最大个数是可以自定义的,需要根据实际情况确定一个合理的值。

点击右方的问号图标可以查看帮助信息。

# Source Code Management

Source Code Management,即源码管理,就是配置你代码的存放位置。

img

  • Git: 支持主流的 Github 和 Gitlab 代码仓库。因我们的研发团队使用的是 gitlab,所以下面我只会对该项进行介绍。
  • Repository URL:仓库地址。
  • Credentials:凭证。可以使用 HTTP 方式的用户名密码,也可以是 RSA 文件。 但要通过后面的"ADD"按钮添加凭证。
  • Branches to build:构建的分支。*/master 表示 master 分支,也可以设置为其他分支。
  • Repository browser:你所使用的代码仓库管理工具,如 Github、Gitlab.
  • Subversion:即 SVN,这里不作介绍。

# Build Triggers

Build Triggers,即构建触发器,用于构建任务的触发器。

img

配置说明:

  • Trigger builds remotely (e.g., from scripts):触发远程构建(例如,使用脚本)。该选项会提供一个接口,可以用来在代码层面触发构建。
  • Build after other projects are built:该选项意思是"在其他项目构建后再构建"。
  • Build periodically:周期性的构建。就是每隔一段时间进行构建。日程表类似 linux crontab 书写格式。如:H/30 * * * *,表示每隔 30 分钟进行一次构建。
  • **Build when a change is pushed to GitLab:**当有 git push 到 Gitlab 仓库,即触发构建。后面会有一个触发构建的地址,一般被称为 webhooks。需要将这个地址配置到 gitlab 中,webhooks 如何配置后面介绍。这个是常用的构建触发器。
  • **Poll SCM:**该选项是配合上面这个选项使用的。当代码仓库发生改动,jenkins 并不知道。需要配置这个选项,周期性的去检查代码仓库是否发生改动。

# Build Environment

Build Environment,即构建环境,配置构建前的一些准备工作,如指定构建工具。

img

# Build

Build,即构建。

点击下图中的 Add build step 按钮,会弹出一个构建任务菜单,可以根据实际需要来选择。

img

【说明】

  • Copy artifacts from another project:从其他项目获取构建。一般当本任务有上游任务,需要获取上游任务的构件时使用。比如:有个 Java Web 项目,需要依赖于上一个前端构建任务输出的静态文件压缩包。
  • Eexcute NodeJS script:执行 Nodejs 脚本。默认支持 nodejs、npm 命令。
  • Eexcute shell: 执行 shell 脚本。用于 Linux 环境。
  • Execute Windows batch command:执行 batch 脚本。用于 Windows 环境。
  • Invoke Ant:Ant 是一款 java 项目构建工具。
  • Invoke Gradle script:Gradle 构建项目。
  • Invoke top-level Maven targets:Maven 构建项目。

# Post-build Actions

Post-build Actions,即构建后操作,用于构建完本项目的一些后续操作,比如生成相应的代码测试报告。

img

img

img

个人较常用的配置:

  • Archive the artifacts:归档构件。
  • Build other projects:构建其他项目。
  • Trigger parameterized build on other projects:构建其他项目,并传输构建参数。
  • Publish JUnit test result report:发布 Junit 测试报告。
  • E-mail Notification:邮件通知,构建完成后发邮件到指定的邮箱。

以上配置完成后,点击保存即可。

# 开始构建

img

如上图所示,一切配置好后,即可点击 Build Now 开始构建。

# 构建结果

img

  • 构建状态
    • Successful 蓝色:构建完成,并且被认为是稳定的。
    • Unstable 黄色:构建完成,但被认为是不稳定的。
    • Failed 红色:构建失败。
    • Disable 灰色:构建已禁用
  • 构建稳定性
    • 构建稳定性用天气表示:晴、晴转多云、多云、小雨、雷阵雨。天气越好表示构建越稳定,反之亦然。
  • 构建历史界面 +
    • console output:输出构建的日志信息

# 其他相关配置

# SSH Server 配置

登录 jenkins -> 系统管理 -> 系统设置

配置请看下图:

img

重要配置:

  • SSH Servers: 由于 jenkins 服务器公钥文件我已经配置好,所以之后新增 SSH Servers 只需要配置这一项即可。

  • Name: 自定义,需要全局唯一。

  • HostName: 主机名,直接用 ip 地址即可。

  • Username: 新增 Server 的用户名,这里配置的是 root。

  • Remote Directory: 远程目录。jenkins 服务器发送文件给新增的 server 默认是在这个目录。

# 配置 Gitlab webhooks

在 gitlab 的 project 页面 打开settings,再打开 web hooks 。点击**"ADD WEB HOOK"** 添加 webhook。把之前 jenkins 配置中的那个 url 添加到这里,添加完成后,点击**"TEST HOOK"**进行测试,如果显示 SUCCESS 则表示添加成功。

img

img

img

img

img

配置 phpunit.xml

phpunit.xml 是 phpunit 这个工具用来单元测试所需要的配置文件。这个文件的名称同样也是可以自定义的,但是要在"build.xml"中配置好名字就行。默认情况下,用"phpunit.xml", 则不需要在"build.xml"中配置文件名。

img

build.xml 中 phpunit 配置

fileset dir 指定单元测试文件所在路径,include 指定包含哪些文件,支持通配符匹配。当然也可以用 exclude 关键字指定不包含的文件。

img

# jenkins 权限管理

由于 jenkins 默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,本文将使用 Role Strategy Plugin。基于这个插件的权限管理设置请参考这篇文章:http://blog.csdn.net/russ44/article/details/52276222 (opens new window),这里不作详细介绍。

至此,就可以用 jenkins 周而复始的进行 CI 了,当然 jenkins 是一个强大的工具,功能绝不仅仅是以上这些,其他方面要是以后用到,我会更新到这篇文章中。有疑问欢迎在下方留言。

# Jenkins FAQ

# 登录密码

如果不知道初始登录密码,可以通过以下方式查看:

执行命令 cat /root/.jenkins/secrets/initialAdminPassword,打印出来的即是初始登录密码。

# 忘记密码

1.执行 vim /root/.jenkins/config.xml ,删除以下内容

<useSecurity>true</useSecurity>
+<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
+  <denyAnonymousReadAccess>true</denyAnonymousReadAccess>
+</authorizationStrategy>
+<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
+  <disableSignup>true</disableSignup>
+  <enableCaptcha>false</enableCaptcha>
+</securityRealm>
+

2.重启 Jenkins 服务;

3.进入首页>“系统管理”>“Configure Global Security”;

4.勾选“启用安全”;

5.点选“Jenkins 专有用户数据库”,并点击“保存”;

6.重新点击首页>“系统管理”,发现此时出现“管理用户”;

7.点击进入展示“用户列表”;

8.点击右侧进入修改密码页面,修改后即可重新登录。

# 卡在 check 页面

现象:输入密码后,卡在 check 页面

原因:jenkins 在安装插件前总是尝试连接 www.google.com,来判断网络是否连通。谷歌的网站在大陆是连不上的,所以会出现这个问题。

解决方案:执行vim /root/.jenkins/updates/default.json,将 connectionCheckUrl 后的 www.google.com 改为 www.baidu.com 。然后重启即可。

或者直接执行命令:

sed -i 's/www.google.com/www.baidu.com/g' /root/.jenkins/updates/default.json
+

# 卡在 getting startted 页面

现象:卡在 getting startted 页面

原因:jenkins 默认的插件下载服务器地址在国外,如果不翻墙下载不了。

解决方案:执行vim /root/.jenkins/hudson.model.UpdateCenter.xml,将 <url> 改为 http://mirror.xmission.com/jenkins/updates/update-center.json 。然后重启即可。

或者直接执行命令:

sed -i '/^<url>/s/.*/<url>http:\/\/mirror.xmission.com\/jenkins\/updates\/update-center.json<\/url>/g' /root/.jenkins/hudson.model.UpdateCenter.xml
+

# 以 root 用户运行

(1)修改 jenkins 用户

vim /etc/sysconfig/jenkins
+

修改用户

$JENKINS_USER="root"
+

(2)修改 Jenkins 相关文件夹用户权限

chown -R root:root /var/lib/jenkins
+chown -R root:root /var/cache/jenkins
+chown -R root:root /var/log/jenkins
+

(3)重启 Jenkins

systemctl restart jenkins
+

# 参考资料

+ + + diff --git a/linux/soft/kafka-install.html b/linux/soft/kafka-install.html new file mode 100644 index 0000000..e1d7c44 --- /dev/null +++ b/linux/soft/kafka-install.html @@ -0,0 +1,80 @@ + + + + + + Kafka 安装部署 | LINUX-TUTORIAL + + + + + + + + +

# Kafka 安装部署

环境要求:

  • JDK8
  • ZooKeeper

# 下载解压

进入官方下载地址:http://kafka.apache.org/downloads,选择合适版本。

解压到本地:

> tar -xzf kafka_2.11-1.1.0.tgz
+> cd kafka_2.11-1.1.0
+

现在您已经在您的机器上下载了最新版本的 Kafka。

# 启动服务器

由于 Kafka 依赖于 ZooKeeper,所以运行前需要先启动 ZooKeeper

> bin/zookeeper-server-start.sh config/zookeeper.properties
+[2013-04-22 15:01:37,495] INFO Reading configuration from: config/zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
+...
+

然后,启动 Kafka

> bin/kafka-server-start.sh config/server.properties
+[2013-04-22 15:01:47,028] INFO Verifying properties (kafka.utils.VerifiableProperties)
+[2013-04-22 15:01:47,051] INFO Property socket.send.buffer.bytes is overridden to 1048576 (kafka.utils.VerifiableProperties)
+...
+

# 停止服务器

执行所有操作后,可以使用以下命令停止服务器

$ bin/kafka-server-stop.sh config/server.properties
+

# 创建主题

创建一个名为 test 的 Topic,这个 Topic 只有一个分区以及一个备份:

> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
+

# 生产者生产消息

运行生产者,然后可以在控制台中输入一些消息,这些消息会发送到服务器:

> bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
+This is a message
+This is another message
+

# 消费者消费消息

启动消费者,然后获得服务器中 Topic 下的消息:

> bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
+This is a message
+This is another message
+

# 集群部署

复制配置为多份(Windows 使用 copy 命令代理):

> cp config/server.properties config/server-1.properties
+> cp config/server.properties config/server-2.properties
+

修改配置:

config/server-1.properties:
+    broker.id=1
+    listeners=PLAINTEXT://:9093
+    log.dir=/tmp/kafka-logs-1
+
+config/server-2.properties:
+    broker.id=2
+    listeners=PLAINTEXT://:9094
+    log.dir=/tmp/kafka-logs-2
+

其中,broker.id 这个参数必须是唯一的。

端口故意配置的不一致,是为了可以在一台机器启动多个应用节点。

根据这两份配置启动三个服务器节点:

> bin/kafka-server-start.sh config/server.properties &
+...
+> bin/kafka-server-start.sh config/server-1.properties &
+...
+> bin/kafka-server-start.sh config/server-2.properties &
+...
+

创建一个新的 Topic 使用 三个备份:

> bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic
+

查看主题:

> bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic
+Topic:my-replicated-topic   PartitionCount:1    ReplicationFactor:3 Configs:
+    Topic: my-replicated-topic  Partition: 0    Leader: 1   Replicas: 1,2,0 Isr: 1,2,0
+
  • leader - 负责指定分区的所有读取和写入的节点。每个节点将成为随机选择的分区部分的领导者。
  • replicas - 是复制此分区日志的节点列表,无论它们是否为领导者,或者即使它们当前处于活动状态。
  • isr - 是“同步”复制品的集合。这是副本列表的子集,该列表当前处于活跃状态并且已经被领导者捕获。

# 更多内容

+ + + diff --git a/linux/soft/maven-install.html b/linux/soft/maven-install.html new file mode 100644 index 0000000..a1cc8c6 --- /dev/null +++ b/linux/soft/maven-install.html @@ -0,0 +1,45 @@ + + + + + + Maven 安装 | LINUX-TUTORIAL + + + + + + + + +

# Maven 安装

环境要求:

  • JDK

# 安装方法

安装步骤如下:

(1)下载

进入官网下载地址:https://maven.apache.org/download.cgi ,选择合适的版本下载。

我选择的是最新 Maven3 版本:http://mirrors.hust.edu.cn/apache/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz

(2)解压到本地

我个人喜欢存放在:/opt/maven

(3)设置环境变量

输入 vi /etc/profile ,添加环境变量如下:

# MAVEN 的根路径
+export MAVEN_HOME=/opt/maven/apache-maven-3.5.2
+export PATH=\$MAVEN_HOME/bin:\$PATH
+

执行 source /etc/profile ,立即生效

(4)检验是否安装成功,执行 mvn -v 命令

# 脚本

以上两种安装方式,我都写了脚本去执行:

| 安装脚本 (opens new window) |

+ + + diff --git a/linux/soft/mongodb-ops.html b/linux/soft/mongodb-ops.html new file mode 100644 index 0000000..73ae01c --- /dev/null +++ b/linux/soft/mongodb-ops.html @@ -0,0 +1,51 @@ + + + + + + Mongodb 安装 | LINUX-TUTORIAL + + + + + + + + +

# Mongodb 安装

# 安装

安装步骤如下:

(1)下载并解压到本地

进入官网下载地址:https://www.mongodb.com/download-center#community ,选择合适的版本下载。

我选择的是最新稳定版本 3.6.3:https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz

我个人喜欢存放在:/opt/mongodb

wget -O /opt/mongodb/mongodb-linux-x86_64-3.6.3.tgz https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz
+cd /opt/mongodb
+tar zxvf mongodb-linux-x86_64-3.6.3.tgz
+mv mongodb-linux-x86_64-3.6.3 mongodb-3.6.3
+mkdir -p /data/db
+

# 启动

启动 mongodb 服务

cd /opt/mongodb/mongodb-3.6.3/bin
+./mongod --dbpath=/data/db
+

启动 mongodb 客户端

cd /opt/mongodb/mongodb-3.6.3/bin
+./mongo
+

# 脚本

| 安装脚本 (opens new window) |

+ + + diff --git a/linux/soft/nacos-install.html b/linux/soft/nacos-install.html new file mode 100644 index 0000000..54a98e8 --- /dev/null +++ b/linux/soft/nacos-install.html @@ -0,0 +1,59 @@ + + + + + + Nacos 安装配置 | LINUX-TUTORIAL + + + + + + + + +

# Nacos 安装配置

Nacos (opens new window) 是一款发现、配置和管理微服务的软件。

# 1.预备环境准备

Nacos 依赖 Java (opens new window) 环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置 Maven (opens new window)环境,请确保是在以下版本环境中安装使用:

  1. 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
  2. 64 bit JDK 1.8+;下载 (opens new window) & 配置 (opens new window)
  3. Maven 3.2.x+;下载 (opens new window) & 配置 (opens new window)

# 2.下载源码或者安装包

你可以通过源码和发行包两种方式来获取 Nacos。

# 从 Github 上下载源码方式

git clone https://github.com/alibaba/nacos.git
+cd nacos/
+mvn -Prelease-nacos clean install -U  
+ls -al distribution/target/
+
+// change the $version to your actual path
+cd distribution/target/nacos-server-$version/nacos/bin
+

# 下载编译后压缩包方式

您可以从 最新稳定版本 (opens new window) 下载 nacos-server-$version.zip 包。

  unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
+  cd nacos/bin
+

# 3.启动服务器

# Linux/Unix/Mac

启动命令(standalone代表着单机模式运行,非集群模式):

sh startup.sh -m standalone
+

# Windows

启动命令:

cmd startup.cmd
+

或者双击startup.cmd运行文件。

# 4.服务注册&发现和配置管理

# 服务注册

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
+

# 服务发现

curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=nacos.naming.serviceName'
+

# 发布配置

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
+

# 获取配置

curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
+

# 5.关闭服务器

# Linux/Unix/Mac

sh shutdown.sh
+

# Windows

cmd shutdown.cmd
+

或者双击shutdown.cmd运行文件。

# 参考资料

+ + + diff --git a/linux/soft/nexus-ops.html b/linux/soft/nexus-ops.html new file mode 100644 index 0000000..6902204 --- /dev/null +++ b/linux/soft/nexus-ops.html @@ -0,0 +1,167 @@ + + + + + + Nexus 运维 | LINUX-TUTORIAL + + + + + + + + +

# Nexus 运维

Nexus 是一个强大的 Maven 仓库管理器,可以用来搭建 Maven 私服。

关键词:maven, nexus

部署环境:

  • Nexus 3.13.0
  • JDK 1.8
  • Maven 3.5.4

# 一、Nexus 安装

进入官方下载地址 (opens new window),选择合适版本下载。

img

本人将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。

这里,如果想通过命令方式直接下载(比如用脚本安装),可以在官方历史发布版本页面 (opens new window)中找到合适版本,然后执行以下命令:

# 个人习惯将 nexus 安装在 /opt/maven 目录下
+wget -O /opt/maven/nexus-unix.tar.gz http://download.sonatype.com/nexus/3/nexus-3.13.0-01-unix.tar.gz
+
+
  • 【解压】执行 tar -zxf nexus-unix.tar.gz 命令,会解压出两个目录: +
    • nexus-<version> - 程序目录。包含了 Nexus 运行所需要的文件。是 Nexus 运行必须的。 +
      • nexus-<version>/etc - 配置目录。 +
        • nexus-<version>/etc/nexus.properties - nexus 核心配置文件(默认 etc 目录下有 nexus-default.properties,可以基于此修改)。
    • sonatype-work - 仓库目录。包含了 Nexus 生成的配置文件、日志文件、仓库文件等。当我们需要备份 Nexus 的时候默认备份此目录即可。
  • [修改环境变量】执行 vim /etc/profile,在文件尾部添加以下内容:
NEXUS_HOME=/usr/program/nexus2.11.4
+export NEXUS_HOME
+

刷新环境变量:source /etc/profile

  • 【检查安装是否成功】执行 nexus -version 查看是否安装成功。
  • 【防火墙】 +
    • iptabes +
      • 添加规则:iptables -I INPUT -p tcp -m tcp --dport 8081 -j ACCEPT
      • 载入规则:/etc/rc.d/init.d/iptables save
      • 重启 iptables:service iptables restart
    • firewalld +
      • 添加规则:firewall-cmd --zone=public --add-port=8081/tcp --permanent
      • 载入规则:firewall-cmd --reload

# 二、Nexus 使用

# 启动/停止 Nexus

进入 nexus-3.13.0-01/bin 目录,有一个可执行脚本 nexus。

执行 ./nexus,可以查看允许执行的参数,如下所示,含义可谓一目了然:

$ ./nexus
+Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}
+
  • 启动 nexus - ./nexus start
  • 停止 nexus - ./nexus stop
  • 重启 nexus - ./nexus restart

Nexus 的默认启动端口为 8081,启动成功后,在浏览器中访问 http://<ip>:8081,欢迎页面如下图所示:

img

点击右上角 Sign in 登录,默认用户名/密码为:admin/admin123

# 配置 maven 仓库

Nexus 中的仓库有以下类型:

  • hosted - 宿主仓库。主要用于部署无法从公共仓库获取的构件(如 oracle 的 JDBC 驱动)以及自己或第三方的项目构件;
  • proxy - 代理仓库。代理公共的远程仓库;
  • virtual - 虚拟仓库。用于适配 Maven 1;
  • group - 仓库组。Nexus 通过仓库组的概念统一管理多个仓库,这样我们在项目中直接请求仓库组即可请求到仓库组管理的多个仓库。

img

建议配置如下:

  • hosted 仓库
    • maven-releases - 存储私有仓库的发行版 jar 包
    • maven-snapshots - 存储私有仓库的快照版(调试版本) jar 包
  • proxy 仓库
    • maven-central-maven - 中央库(如果没有配置 mirror,默认就从这里下载 jar 包),从 https://repo1.maven.org/maven2/ 获取资源
    • maven-aliyun - 国内 maven 仓库,提高访问速度。
  • group 仓库
    • maven-public - 私有仓库的公共空间,把上面三个仓库组合在一起对外提供服务,在本地 maven 基础配置 settings.xml 中使用。

img

其中:

maven-centralmaven-publicmaven-releasemaven-snapshot 仓库是默认配置好的 maven 仓库。maven-central 配置的是 https://repo1.maven.org/maven2/ 的代理仓库,即 maven 中央仓库地址。

参考配置如下:

img

推荐配置的代理仓库:

  • OSS SNAPSHOT 仓库:http://oss.jfrog.org/artifactory/oss-snapshot-local/
  • aliyun 仓库(受限于国内网络,可以通过它来加速):http://maven.aliyun.com/nexus/content/groups/public/

# 配置 yum 仓库

img

推荐配置的 yum 代理仓库:

  • aliyun yum 仓库:http://mirrors.aliyun.com/centos

配置本地 yum:

(1)新增 nexus.repo 文件,内容如下:

[base]
+name=Nexus
+baseurl= http://<nexus host>:<nexus port>/repository/yum-aliyun/$releasever/os/$basearch/
+enabled=1
+gpgcheck=0
+priority=1
+

(2)更新 yum 缓存,执行以下命令:

yum clean all
+yum makecache
+

# 定时任务

随着 jar 包越来越多,尤其是 SNAPSHOT 包由于不限制重复上传,尤其容易导致磁盘空间膨胀。所以,需要定期进行清理或修复。

Nexus 内置了多个定时任务,可以执行清理。

【示例】定期清理 SNAPSHOST

img

# 三、开机自启动

作为常用服务,有必要将 Nexus 设为 systemd 服务,以便在断电恢复后自动重启。

配置方法如下:

/lib/systemd/system 目录下创建 nexus.service 文件,内容如下:

[Unit]
+Description=nexus
+After=network.target
+
+[Service]
+Type=forking
+LimitNOFILE=65536 #警告处理
+Environment=RUN_AS_USER=root
+ExecStart=/opt/maven/nexus-3.13.0-01/bin/nexus start
+ExecReload=/opt/maven/nexus-3.13.0-01/bin/nexus restart
+ExecStop=/opt/maven/nexus-3.13.0-01/bin/nexus stop
+Restart=on-failure
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
+

保存后,可以使用以下命令应用 nexus 服务:

  • systemctl enable nexus - 启动 nexus 开机启动
  • systemctl disable nexus - 关闭 nexus 开机启动
  • systemctl start nexus - 启动 nexus 服务
  • systemctl stop nexus - 停止 nexus 服务
  • systemctl restart nexus - 重启 nexus 服务

执行 systemctl enable nexus 后,再执行 reboot 重启,重连后,可以检测是否成功开机自动重启。

# 四、Nexus 和 Maven

Nexus 是 maven 私服。现在,Nexus 服务器已经部署好了,如何配合 maven 使用呢?

# 配置 settings.xml

如果要使用 Nexus,还必须在 settings.xmlpom.xml 中配置认证信息。

一份完整的 settings.xml

<?xml version="1.0" encoding="UTF-8"?>
+
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+  <pluginGroups>
+    <pluginGroup>org.sonatype.plugins</pluginGroup>
+  </pluginGroups>
+
+  <!--设置本地 maven 仓库-->
+  <localRepository>D:\Tools\maven\.m2</localRepository>
+
+  <!--Maven 私服账号信息-->
+  <servers>
+    <server>
+      <id>releases</id>
+      <username>admin</username>
+      <password>admin123</password>
+    </server>
+    <server>
+      <id>snapshots</id>
+      <username>admin</username>
+      <password>admin123</password>
+    </server>
+  </servers>
+
+  <!--Maven 镜像地址-->
+  <mirrors>
+    <mirror>
+      <id>public</id>
+      <mirrorOf>*</mirrorOf>
+      <!--Nexus 服务器地址-->
+      <url>http://10.255.255.224:8081/repository/maven-public/</url>
+    </mirror>
+  </mirrors>
+
+  <profiles>
+    <profile>
+      <id>zp</id>
+      <repositories>
+        <repository>
+          <id>central</id>
+          <url>http://central</url>
+          <releases>
+            <enabled>true</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>central</id>
+          <url>http://central</url>
+          <releases>
+            <enabled>true</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+            <updatePolicy>always</updatePolicy>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+
+  <activeProfiles>
+    <activeProfile>zp</activeProfile>
+  </activeProfiles>
+</settings>
+

# 配置 pom.xml

pom.xml 中添加如下配置,这样就可以执行 mvn deploy,将本地构建的 jar、war 等包发布到私服上。

  <distributionManagement>
+    <repository>
+      <id>releases</id>
+      <name>Releases</name>
+      <url>http://10.255.255.224:8081/repository/maven-releases</url>
+    </repository>
+    <snapshotRepository>
+      <id>snapshots</id>
+      <name>Snapshot</name>
+      <url>http://10.255.255.224:8081/repository/maven-snapshots</url>
+    </snapshotRepository>
+  </distributionManagement>
+

🔔 注意:

  • <repository><snapshotRepository> 的 id 必须和 settings.xml 配置文件中的 <server> 标签中的 id 匹配。
  • <url> 标签的地址需要和 maven 私服的地址匹配。

# 执行 maven 构建

如果要使用 settings.xml 中的私服配置,必须通过指定 -P zp 来激活 profile。

示例:

# 编译并打包 maven 项目
+$ mvn clean package -Dmaven.skip.test=true -P zp
+
+# 编译并上传 maven 交付件(jar 包)
+$ mvn clean deploy -Dmaven.skip.test=true -P zp
+

至此,已经可以正常向 Nexus 上传、下载 jar 包。

# 五、备份和迁移

Nexus 三个重要目录:

名称 目录名 重要配置文件
nexus 主目录 nexus-2.6.4-02 conf/nexus.properties 里面有 sonatype-work 的地址
sonatype-work 目录 sonatype-work nexus/conf/nexus.xml 里面有 storage 的地址
storage 目录 storage 里面主要是各种程序的 jar 包等

# 备份

Nexus 的数据都存储在 sonatype-work 目录,备份 Nexus 数据只需要将其打包即可。

# 迁移

将原 Nexus 服务器中的 sonatype-work 目录迁移到新 Nexus 服务器的 sonatype-work 目录下。

# 六、FAQ

# 配置 INSTALL4J_JAVA_HOME

我在工作中遇到 nexus systemctl 服务无法自启动的问题,通过查看状态,发现以下报错:

Please define INSTALL4J_JAVA_HOME to point to a suitable JVM
+

通过排查,找到原因:即使环境上已安装 JDK,且配置了 JAVA_HOME,但 nexus 仍然无法正确找到 JDK,需要在 /bin/nexus 中指定 INSTALL4J_JAVA_HOME_OVERRIDE=<JDK安装路径>

# 参考资料

+ + + diff --git a/linux/soft/nodejs-install.html b/linux/soft/nodejs-install.html new file mode 100644 index 0000000..9105229 --- /dev/null +++ b/linux/soft/nodejs-install.html @@ -0,0 +1,47 @@ + + + + + + Nodejs 安装 | LINUX-TUTORIAL + + + + + + + + +

# Nodejs 安装

# 安装方法

# 先安装 nvm

推荐安装 nvm(Node Version Manager) ,来管理 node.js 版本。

安装步骤如下:

(1)执行安装脚本

rm -rf ~/.nvm
+curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
+. ~/.nvm/nvm.sh
+

(2)检验是否安装成功

执行 nvm --version 命令。

注意:如果出现 nvm: command not found ,关闭终端,然后再打开终端试试。

# 安装 Nodejs

安装步骤如下:

(1)使用 nvm 安装 nodejs 指定版本

执行以下命令:

nvm install 8.9.4
+nvm use 8.9.4
+

(2)检验是否安装成功

执行 node --version 命令。

注意:如果出现 node: command not found ,关闭终端,然后再打开终端试试。

# 脚本

| 安装脚本 (opens new window) |

# 更多内容

+ + + diff --git a/linux/soft/rocketmq-install.html b/linux/soft/rocketmq-install.html new file mode 100644 index 0000000..cf970e3 --- /dev/null +++ b/linux/soft/rocketmq-install.html @@ -0,0 +1,78 @@ + + + + + + RocketMQ 安装部署 | LINUX-TUTORIAL + + + + + + + + +

# RocketMQ 安装部署

# 环境要求

  • 推荐 64 位操作系统:Linux/Unix/Mac
  • 64bit JDK 1.8+
  • Maven 3.2.x
  • Git

# 下载解压

进入官方下载地址:https://rocketmq.apache.org/dowloading/releases/,选择合适版本

建议选择 binary 版本。

解压到本地:

> unzip rocketmq-all-4.2.0-source-release.zip
+> cd rocketmq-all-4.2.0/
+

# 启动 Name Server

> nohup sh bin/mqnamesrv &
+> tail -f ~/logs/rocketmqlogs/namesrv.log
+The Name Server boot success...
+

# 启动 Broker

> nohup sh bin/mqbroker -n localhost:9876 -c conf/broker.conf &
+> tail -f ~/logs/rocketmqlogs/broker.log
+The broker[%s, 172.30.30.233:10911] boot success...
+

# 收发消息

执行收发消息操作之前,不许告诉客户端命名服务器的位置。在 RocketMQ 中有多种方法来实现这个目的。这里,我们使用最简单的方法——设置环境变量 NAMESRV_ADDR

> export NAMESRV_ADDR=localhost:9876
+> sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
+SendResult [sendStatus=SEND_OK, msgId= ...
+
+> sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
+ConsumeMessageThread_%d Receive New Messages: [MessageExt...
+

# 关闭服务器

> sh bin/mqshutdown broker
+The mqbroker(36695) is running...
+Send shutdown request to mqbroker(36695) OK
+
+> sh bin/mqshutdown namesrv
+The mqnamesrv(36664) is running...
+Send shutdown request to mqnamesrv(36664) OK
+

# FAQ

# connect to <172.17.0.1:10909> failed

启动后,生产者客户端连接 RocketMQ 时报错:

org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <172.17.0.1:10909> failed
+    at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:357)
+    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessageSync(MQClientAPIImpl.java:343)
+    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:327)
+    at org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessage(MQClientAPIImpl.java:290)
+    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendKernelImpl(DefaultMQProducerImpl.java:688)
+    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendSelectImpl(DefaultMQProducerImpl.java:901)
+    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:878)
+    at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:873)
+    at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:369)
+    at com.emrubik.uc.mdm.sync.utils.MdmInit.sendMessage(MdmInit.java:62)
+    at com.emrubik.uc.mdm.sync.utils.MdmInit.main(MdmInit.java:2149)
+

原因:RocketMQ 部署在虚拟机上,内网 ip 为 10.10.30.63,该虚拟机一个 docker0 网卡,ip 为 172.17.0.1。RocketMQ broker 启动时默认使用了 docker0 网卡,生产者客户端无法连接 172.17.0.1,造成以上问题。

解决方案

(1)干掉 docker0 网卡或修改网卡名称

(2)停掉 broker,修改 broker 配置文件,重启 broker。

修改 conf/broker.conf,增加两行来指定启动 broker 的 IP:

namesrvAddr = 10.10.30.63:9876
+brokerIP1 = 10.10.30.63
+

启动时需要指定配置文件

nohup sh bin/mqbroker -n localhost:9876 -c conf/broker.conf &
+

# 更多内容

+ + + diff --git a/linux/soft/svn-ops.html b/linux/soft/svn-ops.html new file mode 100644 index 0000000..94896ba --- /dev/null +++ b/linux/soft/svn-ops.html @@ -0,0 +1,70 @@ + + + + + + Svn 运维 | LINUX-TUTORIAL + + + + + + + + +

# Svn 运维

Svn 是 Subversion 的简称,是一个开放源代码的版本控制系统,它采用了分支管理系统。

本文目的在于记录 svn 的安装、配置、使用。

# 安装

# 安装 svn

$ yum install -y subversion
+

# 创建 svn 仓库

$ mkdir -p /share/svn
+$ svnadmin create /share/svn
+$ ls /share/svn
+conf  db  format  hooks  locks  README.txt
+

在 conf 目录下有三个重要的配置文件

  • authz - 是权限控制文件
  • passwd - 是帐号密码文件
  • svnserve.conf - 是 SVN 服务配置文件

# 配置

# 配置 svnserve.conf

$ vim /share/svn/conf/svnserve.conf
+

打开下面的 5 个注释

anon-access = read      #匿名用户可读
+auth-access = write     #授权用户可写
+password-db = passwd    #使用哪个文件作为账号文件
+authz-db = authz        #使用哪个文件作为权限文件
+realm = /share/svn      # 认证空间名,版本库所在目录
+

# 配置 passwd

$ vim /share/svn/conf/passwd
+

添加新用户的用户名/密码如下:

[users]
+user1 = 123456
+user2 = 123456
+user3 = 123456
+

# 配置 authz

$ vim /share/svn/conf/authz
+

指定用户的访问权限(r 为读权限;w 为写权限):

[/]
+user1 = rw
+user2 = rw
+user3 = rw
+*=
+

# 服务器管理

# 启动关闭 svn

$ svnserve -d -r /share/svn # 启动 svn
+$ killall svnserve # 关闭 svn
+

# 开机自启动 svn 方法

安装好 svn 服务后,默认是没有随系统启动自动启动的,而一般我们有要求 svn 服务稳定持续的提供服务。所以,有必要配置开机自启动 svn 服务。

# Centos7 以前

编辑 /etc/rc.d/rc.local 文件:

$ vi /etc/rc.d/rc.local
+

输入以下内容:

# 开机自动启动 svn,默认端口是 3690
+$ /usr/bin/svnserve -d -r /share/svn --listen-port 3690
+

注意:

我们在用终端操作的时候,可以直接使用以下命令启动 SVN:svnserve -d -r /share/svn,但是在 /etc/rc.d/rc.local 文件中必须写上完整的路径!

如果不知道 svnserve 命令安装在哪儿,可以使用 whereis svnserve 查找。

# Centos7

CentOS 7 中的 /etc/rc.d/rc.local 是没有执行权限的,系统建议创建 systemd service 启动服务。

找到 svn 的 service 配置文件 /etc/sysconfig/svnserve 编辑配置文件

$ vi /etc/sysconfig/svnserve
+

OPTIONS="-r /var/svn" 改为 svn 版本库存放的目录,:wq 保存退出。

执行 systemctl enable svnserve.service

重启服务器后,执行 ps -ef | grep svn 应该可以看到 svn 服务的进程已经启动。

  • 启动一个服务 - systemctl start svnserve.service
  • 关闭一个服务 - systemctl stop svnserve.service
  • 重启一个服务 - systemctl restart svnserve.service
  • 显示一个服务的状态 - systemctl status svnserve.service
  • 在开机时启用一个服务 - systemctl enable svnserve.service
  • 在开机时禁用一个服务 - systemctl disable svnserve.service

# 客户端使用

进入 svn 官方下载地址 (opens new window),选择合适的版本,下载并安装。

新建一个目录,然后打开鼠标右键菜单,选择 SVN Checkout

在新的窗口,输入地址 svn://<你的 IP> 即可,不出意外输入用户名和密码就能连接成功了(这里的用户、密码必须在 passwd 配置文件的清单中)。默认端口 3690,如果你修改了端口,那么要记得加上端口号。如下图所示:

img

# 参考资料

  • https://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html
  • https://blog.csdn.net/testcs_dn/article/details/45395645
  • https://www.cnblogs.com/moxiaoan/p/5683743.html
  • https://blog.csdn.net/realghost/article/details/52396648
+ + + diff --git a/linux/soft/tomcat-install.html b/linux/soft/tomcat-install.html new file mode 100644 index 0000000..8dbf09d --- /dev/null +++ b/linux/soft/tomcat-install.html @@ -0,0 +1,49 @@ + + + + + + Tomcat 安装 | LINUX-TUTORIAL + + + + + + + + +

# Tomcat 安装

# 安装

安装步骤如下:

(1)下载并解压到本地

进入官网下载地址:https://tomcat.apache.org/download-80.cgi ,选择合适的版本下载。

我选择的是最新稳定版本 8.5.28:http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.28/bin/apache-tomcat-8.5.28.tar.gz

我个人喜欢存放在:/opt/tomcat

wget -O /opt/tomcat/apache-tomcat-8.5.28.tar.gz http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.28/bin/apache-tomcat-8.5.28.tar.gz
+cd /opt/tomcat
+tar zxvf apache-tomcat-8.5.28.tar.gz
+

# 启动

启动 tomcat 服务

cd /opt/tomcat/apache-tomcat-8.5.28/bin
+./catalina.sh start
+

停止 tomcat 服务

cd /opt/tomcat/apache-tomcat-8.5.28/bin
+./catalina.sh stop
+

# 脚本

| 安装脚本 (opens new window) |

# 更多内容

+ + + diff --git a/linux/soft/yapi-ops.html b/linux/soft/yapi-ops.html new file mode 100644 index 0000000..7ce7b2e --- /dev/null +++ b/linux/soft/yapi-ops.html @@ -0,0 +1,79 @@ + + + + + + YApi 运维 | LINUX-TUTORIAL + + + + + + + + +

# YApi 运维

YApi (opens new window) 是一个可本地部署的、打通前后端及 QA 的、可视化的接口管理平台。

本文目的在于记录 svn 的安装、配置、使用。

img

# 1. 普通部署

# 1.1. 环境要求

  • nodejs(7.6+)
  • mongodb(2.6+)
  • git

# 1.2. 部署

# 方式一. 可视化部署[推荐]

执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定 url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。

$ npm install -g yapi-cli --registry https://registry.npm.taobao.org
+$ yapi server
+

# 方式二. 命令行部署

如果 github 压缩文件无法下载,或需要部署到一些特殊的服务器,可尝试此方法

mkdir yapi
+cd yapi
+git clone https://github.com/YMFE/yapi.git vendors //或者下载 zip 包解压到 vendors 目录(clone 整个仓库大概 140+ M,可以通过 `git clone --depth=1 https://github.com/YMFE/yapi.git vendors` 命令减少,大概 10+ M)
+cp vendors/config_example.json ./config.json //复制完成后请修改相关配置
+cd vendors
+npm install --production --registry https://registry.npm.taobao.org
+npm run install-server //安装程序会初始化数据库索引和管理员账号,管理员账号名可在 config.json 配置
+node server/app.js //启动服务器后,请访问 127.0.0.1:{config.json配置的端口},初次运行会有个编译的过程,请耐心等候
+

安装后的目录结构如下:

|-- config.json
+|-- init.lock
+|-- log
+`-- vendors
+    |-- CHANGELOG.md
+    |-- LICENSE
+    |-- README.md
+    |-- client
+    |-- common
+    |-- config_example.json
+    |-- doc
+    |-- exts
+    |-- nodemon.json
+    |-- npm-debug.log
+    |-- package.json
+    |-- plugin.json
+    |-- server
+    |-- static
+    |-- test
+    |-- webpack.alias.js
+    |-- yapi-base-flow.jpg
+    |-- ydocfile.js
+    `-- ykit.config.js
+

# 1.3. 升级

升级项目版本是非常容易的,并且不会影响已有的项目数据,只会同步 vendors 目录下的源码文件。

cd  {项目目录}
+yapi ls //查看版本号列表
+yapi update //升级到最新版本
+yapi update -v v1.1.0 //升级到指定版本
+

# 2. Docker 部署

# 2.1. 环境要求

  • 系统:CentOS 7.4
  • 硬件要求:1 GB RAM minimum
  • ip:http://192.168.1.121
  • docker version:17.12.1-ce, build 7390fc6
  • docker-compose version:1.18.0, build 8dd22a9

建议部署成 http 站点,因 chrome 浏览器安全限制,部署成 https 会导致测试功能在请求 http 站点时文件上传功能异常。--来源 (opens new window)

# 2.2. 部署

  • 一个好心人的维护:https://github.com/branchzero/yapi-docker (opens new window)
  • 使用方法: - work path:mkdir -p /opt/git-data - clone:cd /opt/git-data && git clone https://github.com/branchzero/yapi-docker.git - permission:chmod -R 777 /opt/git-data - run command:cd /opt/git-data/yapi-docker && docker-compose up -d - open chrome:http://192.168.1.121:3000
  • 初始化管理员账号名:admin@admin.com,密码:ymfe.org

# 3. 参考资料

+ + + diff --git a/mac/soft/ruby-install.html b/mac/soft/ruby-install.html new file mode 100644 index 0000000..08472ed --- /dev/null +++ b/mac/soft/ruby-install.html @@ -0,0 +1,80 @@ + + + + + + 安装 Ruby | LINUX-TUTORIAL + + + + + + + + +

# 安装 Ruby

# 安装 rvm

# 下载安装 rvm

:~ admin$ curl -sSL https://get.rvm.io | bash -s stable
+Downloading https://github.com/rvm/rvm/archive/1.29.1.tar.gz
+Downloading https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc
+Found PGP signature at: 'https://github.com/rvm/rvm/releases/download/1.29.1/1.29.1.tar.gz.asc',
+but no GPG software exists to validate it, skipping.
+
+Installing RVM to /Users/admin/.rvm/
+    Adding rvm PATH line to /Users/admin/.profile /Users/admin/.mkshrc /Users/admin/.bashrc /Users/admin/.zshrc.
+    Adding rvm loading line to /Users/admin/.profile /Users/admin/.bash_profile /Users/admin/.zlogin.
+Installation of RVM in /Users/admin/.rvm/ is almost complete:
+
+  * To start using RVM you need to run `source /Users/admin/.rvm/scripts/rvm`
+    in all your open shell windows, in rare cases you need to reopen all shell windows.
+
+# admin,
+#
+#   Thank you for using RVM!
+#   We sincerely hope that RVM helps to make your life easier and more enjoyable!!!
+#
+# ~Wayne, Michal & team.
+
+In case of problems: https://rvm.io/help and https://twitter.com/rvm_io
+

等待一两分钟,成功安装好 RVM。

# 设置环境变量

# 1.2 然后,载入 RVM 环境:
+$ source /etc/profile.d/rvm.sh
+$ sudo chmod -R 777 /usr/local/rvm/archives
+
+# 1.3 修改 RVM 下载 Ruby 的源,到 Ruby China 的镜像
+$ echo "ruby_url=https://cache.ruby-china.com/pub/ruby" > /usr/local/rvm/user/db
+$ rvm install 2.7.0 --disable-binary
+
+// 如下所示:
+AdmindeiMac-4:~ admin$ source ~/.rvm/scripts/rvm
+AdmindeiMac-4:~ admin$ echo "ruby_url=https://cache.ruby-china.org/pub/ruby" > ~/.rvm/user/db
+AdmindeiMac-4:~ admin$ rvm -v
+rvm 1.29.9 (latest) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io/]
+如果能显示版本号,则安装成功。
+

# 参考资料

+ + + diff --git a/service-worker.js b/service-worker.js new file mode 100644 index 0000000..0111547 --- /dev/null +++ b/service-worker.js @@ -0,0 +1,589 @@ +/** + * Welcome to your Workbox-powered service worker! + * + * You'll need to register this file in your web app and you should + * disable HTTP caching for this file too. + * See https://goo.gl/nhQhGp + * + * The rest of the code is auto-generated. Please don't update this file + * directly; instead, make changes to your Workbox build configuration + * and re-run your build process. + * See https://goo.gl/2aRDsh + */ + +importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); + +self.addEventListener('message', (event) => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } +}); + +/** + * The workboxSW.precacheAndRoute() method efficiently caches and responds to + * requests for URLs in the manifest. + * See https://goo.gl/S9QRab + */ +self.__precacheManifest = [ + { + "url": "404.html", + "revision": "f2acd29de3de8d07dad7112bb651d6d9" + }, + { + "url": "assets/css/0.styles.45d9d031.css", + "revision": "bf64f505dbe001ee40e057b594429415" + }, + { + "url": "assets/img/search.83621669.svg", + "revision": "83621669651b9a3d4bf64d1a670ad856" + }, + { + "url": "assets/js/10.7933187b.js", + "revision": "fab860e70f51e33f0726a4e6501b3047" + }, + { + "url": "assets/js/11.b9b41530.js", + "revision": "3fce4b9a626f31fea7dad62fcd964da3" + }, + { + "url": "assets/js/12.70a5dba8.js", + "revision": "d9ebb0dd71bd7ee7b0ab6a1e07c30d08" + }, + { + "url": "assets/js/13.857dcc43.js", + "revision": "91cdbd449855743da97724e21889675d" + }, + { + "url": "assets/js/14.5a603a55.js", + "revision": "18c36975550cb3a7bc0f8f01c744a5e9" + }, + { + "url": "assets/js/15.d217acb7.js", + "revision": "a3f6be5397a4605db21f193bc59fa93f" + }, + { + "url": "assets/js/16.ad565eae.js", + "revision": "9eab2964d75a016ede44bbee4a523c91" + }, + { + "url": "assets/js/17.d43e9f56.js", + "revision": "8f2f31758bbacb1b5e4cda986bb626a2" + }, + { + "url": "assets/js/18.aa00ff43.js", + "revision": "21263eda3d96c3d8878ac52386b11cfe" + }, + { + "url": "assets/js/19.43ce44b3.js", + "revision": "7d0435ac691561a60da20979b289e41e" + }, + { + "url": "assets/js/20.5618e1ff.js", + "revision": "ed44faead694b36e7edce0d71660dbb9" + }, + { + "url": "assets/js/21.1c5a41d7.js", + "revision": "2abe9e71d62ecb9442ebc7056171f5fd" + }, + { + "url": "assets/js/22.fbe9fdf1.js", + "revision": "1d7bd922a0b7745ae04ef11511f034b8" + }, + { + "url": "assets/js/23.a4fb0e74.js", + "revision": "3da75f0c11bcc3cdd1295ab45be3c19e" + }, + { + "url": "assets/js/24.e3a23b69.js", + "revision": "ca4157a4970d639456504d71c06d391c" + }, + { + "url": "assets/js/25.9896afe9.js", + "revision": "4d0dafcb181b2345dcb9ffe786c87b7c" + }, + { + "url": "assets/js/26.96164082.js", + "revision": "7bd6798a63a2eced549d9283974a993f" + }, + { + "url": "assets/js/27.391033bb.js", + "revision": "35b368678d39ea808ea889c65d1d1c9f" + }, + { + "url": "assets/js/28.703f74c2.js", + "revision": "6a2dc76deefe158524ba70bb7b3b7a86" + }, + { + "url": "assets/js/29.02a952cb.js", + "revision": "b9eb4e4cace4b6a2e0571aac80d85e78" + }, + { + "url": "assets/js/30.7e13628f.js", + "revision": "e9cea490d3bcd50fcbd6cefbe78e1251" + }, + { + "url": "assets/js/31.c4652f75.js", + "revision": "d1947fdeee8399b7f90be2b83f44ad90" + }, + { + "url": "assets/js/32.05d2cbec.js", + "revision": "ff4c952bdec9f389a7402292369b8a95" + }, + { + "url": "assets/js/33.3b265df8.js", + "revision": "3e74c8c3c8cf64da0eae7e2a64cb313a" + }, + { + "url": "assets/js/34.26330a03.js", + "revision": "808c2b3dc8f7518d34539a7b5bf6663b" + }, + { + "url": "assets/js/35.417d706d.js", + "revision": "660a8b4be8a2f98c254c1d7aad48c7d3" + }, + { + "url": "assets/js/36.0ed775e0.js", + "revision": "d247ea67f5b568d0395c1c00f8faeed5" + }, + { + "url": "assets/js/37.34430c74.js", + "revision": "452f7584c50ec55f4e76d4e584888e3a" + }, + { + "url": "assets/js/38.87d5e0ff.js", + "revision": "491039efe8d3619fbb604730320c991d" + }, + { + "url": "assets/js/39.7b648b3e.js", + "revision": "8926c0bff137f9a10b979ea73e8c393c" + }, + { + "url": "assets/js/4.fb6e0f89.js", + "revision": "304b142424b320b51babb9b6fa01ff9d" + }, + { + "url": "assets/js/40.3b7a219e.js", + "revision": "37bbca6df31832d526f27dd6459822e7" + }, + { + "url": "assets/js/41.e727eee9.js", + "revision": "018161029bc51f06cab9411df6a14d9a" + }, + { + "url": "assets/js/42.0134c187.js", + "revision": "d2c0f02508f2acaa5272dfce37b163d8" + }, + { + "url": "assets/js/43.175e982f.js", + "revision": "94a27269b2731044b356fe249ad1ea04" + }, + { + "url": "assets/js/44.72d90888.js", + "revision": "874423eb477d902e644647f5592831e5" + }, + { + "url": "assets/js/45.d49955bd.js", + "revision": "4a8411b023b4dfae6206568337433fd5" + }, + { + "url": "assets/js/46.a9c290ec.js", + "revision": "dc0db6a6f96ed8225e960988a0b25535" + }, + { + "url": "assets/js/47.cc639f04.js", + "revision": "ea5c824af05e1ce131feabb8bbb422fc" + }, + { + "url": "assets/js/48.98c78321.js", + "revision": "c32b16dd3334eda1920e6e2b53e39838" + }, + { + "url": "assets/js/49.a7c3afed.js", + "revision": "fd493ff5c85b6e5384d02d3c7df19d31" + }, + { + "url": "assets/js/5.cb43ecfb.js", + "revision": "ba47a8e18abdc4e6846087076e5abaef" + }, + { + "url": "assets/js/50.22d8c542.js", + "revision": "26730dfd030c129faab5773d212977c9" + }, + { + "url": "assets/js/51.28055fcd.js", + "revision": "953c6329d2e601430783772b78caaa7c" + }, + { + "url": "assets/js/52.f8103df5.js", + "revision": "3e0294fb79645f2ce393504c0bfa4413" + }, + { + "url": "assets/js/53.76541550.js", + "revision": "5e299bf02a853c836960d4f729d4d4e9" + }, + { + "url": "assets/js/54.e78d2776.js", + "revision": "6cc7541015066ce95c1f344c3bb2b0ee" + }, + { + "url": "assets/js/55.3ce3079c.js", + "revision": "6c9daed77664bceee7a8757433853c50" + }, + { + "url": "assets/js/56.832958c9.js", + "revision": "ab03a37736c5cd8ec6701ee6629aa190" + }, + { + "url": "assets/js/57.961ce896.js", + "revision": "b5ff411736227a1f2b82a4b05e36f62b" + }, + { + "url": "assets/js/58.6d6fbc82.js", + "revision": "ed961d531fbd5a4551e472df9e8ed13a" + }, + { + "url": "assets/js/59.d5e48112.js", + "revision": "2c5594406db9f1e5e5e966c2780afbc9" + }, + { + "url": "assets/js/6.c8f4721c.js", + "revision": "d46e38a83b53accfb9577ceab12eb833" + }, + { + "url": "assets/js/60.7927b23b.js", + "revision": "f1503d4da8705cd41d615e3985ee6d10" + }, + { + "url": "assets/js/61.ee233f24.js", + "revision": "8b4b6caf4da37b87f5aba3137fb92d75" + }, + { + "url": "assets/js/62.6ba50cc7.js", + "revision": "c50df68b7eba04ea5bd05f444a4508ed" + }, + { + "url": "assets/js/63.9cbf9f2b.js", + "revision": "94d9fa34f8a65a37d9bf47e2622c2100" + }, + { + "url": "assets/js/64.0be148a4.js", + "revision": "fb9059d2721bb56e05bd5560d0909900" + }, + { + "url": "assets/js/65.c520257e.js", + "revision": "0d700e59cf55e5e82e87bd2efaf7e2a0" + }, + { + "url": "assets/js/66.f2335390.js", + "revision": "cfb1932d6cad3fe51c63806e629d1c16" + }, + { + "url": "assets/js/67.e5737218.js", + "revision": "669664b5207606926112e4c9727cd4b8" + }, + { + "url": "assets/js/68.46427a01.js", + "revision": "33edccfde47d58e73a26859b88783d7e" + }, + { + "url": "assets/js/69.450417bb.js", + "revision": "e1efd284c6a5b70e7fb0919691f05c30" + }, + { + "url": "assets/js/7.046e5a1b.js", + "revision": "a1a4eabe5f9f709c8fdb0f59c535f7e3" + }, + { + "url": "assets/js/70.072034d2.js", + "revision": "17e6fcb32ef68fd810fd318bf21a3aa9" + }, + { + "url": "assets/js/8.77fb8967.js", + "revision": "fe3132e4d77b75cf16882c0fcf84463c" + }, + { + "url": "assets/js/9.ebfa537e.js", + "revision": "f8c46e4421227a74a3111727b37c7e7a" + }, + { + "url": "assets/js/app.79a38eea.js", + "revision": "47193fce47767e950d4619c99675cc1e" + }, + { + "url": "assets/js/vendors~flowchart.20a64d45.js", + "revision": "716c82a5a8d7e7248817c9c543fbb778" + }, + { + "url": "assets/js/vendors~notification.ea176280.js", + "revision": "4638db80765160e1766d4bf574a4457c" + }, + { + "url": "docker/docker-cheat-sheet.html", + "revision": "14e8c5a89aacd3ef7245db222c7026f1" + }, + { + "url": "docker/docker-compose.html", + "revision": "0b6c393bf27187f0953bdc4c901ee027" + }, + { + "url": "docker/docker-dockerfile.html", + "revision": "9d43d29855174d5fba38cf34e95291f4" + }, + { + "url": "docker/docker-quickstart.html", + "revision": "65a0262fed5b06d931b4e60fad686e35" + }, + { + "url": "docker/index.html", + "revision": "758d096beab5a4a69bbe678eca0c141e" + }, + { + "url": "docker/kubernetes.html", + "revision": "f9fff0f9beff5275891da35c3db9618e" + }, + { + "url": "docker/service/docker-install-mysql.html", + "revision": "ebdfba0bd4349b4ef2c224232fe3a0c0" + }, + { + "url": "docker/service/docker-install-nginx.html", + "revision": "153abc46bd66f70c7e206141525f65a1" + }, + { + "url": "images/dunwu-logo-100.png", + "revision": "724d2445b33014d7c1ad9401d24a7571" + }, + { + "url": "images/dunwu-logo-200.png", + "revision": "0a7effb33a04226ed0b9b6e68cbf694d" + }, + { + "url": "images/dunwu-logo-50.png", + "revision": "9ada5bdcd34ac9c06dcd682b70a9016b" + }, + { + "url": "images/dunwu-logo.png", + "revision": "f85f8cd2ab66992bc87b0bb314fdcf59" + }, + { + "url": "index.html", + "revision": "f5de0bed3943fd98e9de09f0313c60e4" + }, + { + "url": "linux/cli/free.html", + "revision": "a06054519dd4a451488c56acb5c8a722" + }, + { + "url": "linux/cli/grep.html", + "revision": "6e2f659494c462616130e5c73c885cfc" + }, + { + "url": "linux/cli/index.html", + "revision": "afc9519072639b200f01272a7593267c" + }, + { + "url": "linux/cli/iostat.html", + "revision": "948f9402cc39ed45d278e079cbb2122d" + }, + { + "url": "linux/cli/iotop.html", + "revision": "0107de05d4f432476f93d0461ac7e409" + }, + { + "url": "linux/cli/linux-cli-dir.html", + "revision": "ce83d21da017254d07217128729f1628" + }, + { + "url": "linux/cli/linux-cli-file-compress.html", + "revision": "7024dd0f89674eb1f949df5dedcd900d" + }, + { + "url": "linux/cli/linux-cli-file.html", + "revision": "dac9a6beccbb544e4a31996f3d21265c" + }, + { + "url": "linux/cli/linux-cli-hardware.html", + "revision": "38b6ff4cefc0743398e7bf6ac86ea400" + }, + { + "url": "linux/cli/linux-cli-help.html", + "revision": "378005b3c0ad4bdf5edeb8dedbad67d5" + }, + { + "url": "linux/cli/linux-cli-net.html", + "revision": "4abc4f14c5acdc9767dbe01b05348105" + }, + { + "url": "linux/cli/linux-cli-software.html", + "revision": "5cf5be31d7ef73b5949f65e1883f32c8" + }, + { + "url": "linux/cli/linux-cli-system.html", + "revision": "8328251e4644ea7e2c53825b26bf133a" + }, + { + "url": "linux/cli/linux-cli-user.html", + "revision": "b2d852e36018bad6d5e1a4406145fd47" + }, + { + "url": "linux/cli/scp.html", + "revision": "4b155e5b535d491ef1ef740781b74ed0" + }, + { + "url": "linux/cli/top.html", + "revision": "909a635b773df1c1266ce6f0d2718da9" + }, + { + "url": "linux/cli/vmstat.html", + "revision": "2c8686f737883869e6470b151d0331c3" + }, + { + "url": "linux/cli/命令行的艺术.html", + "revision": "c0bf9391a873bb0545430bec608cc94d" + }, + { + "url": "linux/expect.html", + "revision": "c265fb96a5987e62b073a9ceb2557298" + }, + { + "url": "linux/ops/crontab.html", + "revision": "342fcf6eaede130a1e6e5593f163f3c5" + }, + { + "url": "linux/ops/firewalld.html", + "revision": "6475d7ea2c68e60a1a7e575da29525ad" + }, + { + "url": "linux/ops/index.html", + "revision": "68b6ce8033734f8a3e779378c9a6eafe" + }, + { + "url": "linux/ops/iptables.html", + "revision": "848665ff1d2cce8e5f3bfbce1d3d5cb4" + }, + { + "url": "linux/ops/network-ops.html", + "revision": "a22a3d25b2f75d2e0ef63ced721d98ca" + }, + { + "url": "linux/ops/ntp.html", + "revision": "6f0c4e89ad5e02f6b2ec35b9a6795fab" + }, + { + "url": "linux/ops/samba.html", + "revision": "105fd41745834938a1ea408273a6b44d" + }, + { + "url": "linux/ops/systemd.html", + "revision": "90c4a94360d1c4ae13a096afba1a082f" + }, + { + "url": "linux/ops/vim.html", + "revision": "2fbc6777e339aac919a6e57624f411b8" + }, + { + "url": "linux/ops/zsh.html", + "revision": "488b64b7706a4e316a166aebc63fd978" + }, + { + "url": "linux/soft/apollo/index.html", + "revision": "02fd3f70202cc84c5f6293252c222c19" + }, + { + "url": "linux/soft/elastic/elastic-beats.html", + "revision": "7df9a03908478a0421131cd59fed12f4" + }, + { + "url": "linux/soft/elastic/elastic-kibana.html", + "revision": "cd910a3908d908aa75cf8c7653aa9a5d" + }, + { + "url": "linux/soft/elastic/elastic-logstash.html", + "revision": "73a495388bf716f0d7440350c0da39d6" + }, + { + "url": "linux/soft/elastic/elastic-quickstart.html", + "revision": "5ed7dac5fe4b49b7c9d304fae18a3961" + }, + { + "url": "linux/soft/elastic/index.html", + "revision": "953cb573bb840a18ea8046529ebeee5d" + }, + { + "url": "linux/soft/fastdfs.html", + "revision": "14d991987ad3a061760013deb23aeea2" + }, + { + "url": "linux/soft/gitlab-ops.html", + "revision": "49c5eab37855942ea8d72e2a7b41a715" + }, + { + "url": "linux/soft/index.html", + "revision": "dac468e8de4fdfd54dd2829ba58b48cb" + }, + { + "url": "linux/soft/jdk-install.html", + "revision": "e3a80173c9fb3f3644ade38d9b66c2aa" + }, + { + "url": "linux/soft/jenkins-ops.html", + "revision": "6d3c9890f2ceeeac403452a6ad527967" + }, + { + "url": "linux/soft/kafka-install.html", + "revision": "305025d9fd695b36ac3b4654a1843e9f" + }, + { + "url": "linux/soft/maven-install.html", + "revision": "12bf7e75aef1577358e3b5cd9ffedf1e" + }, + { + "url": "linux/soft/mongodb-ops.html", + "revision": "5acb08a7cda76d8f3be76f1c7d7b5cc5" + }, + { + "url": "linux/soft/nacos-install.html", + "revision": "44dd724bcb837e9499c9ae18525f55f9" + }, + { + "url": "linux/soft/nexus-ops.html", + "revision": "4d4deb4ac304347d4bcaba40e1e77f21" + }, + { + "url": "linux/soft/nodejs-install.html", + "revision": "5be5a2da0efb80ac53681b32c9b3b540" + }, + { + "url": "linux/soft/rocketmq-install.html", + "revision": "45491a526e16ba358363bd900b57fad3" + }, + { + "url": "linux/soft/svn-ops.html", + "revision": "6c7f7741c1409cd21f0d08debbbd65c9" + }, + { + "url": "linux/soft/tomcat-install.html", + "revision": "527af5e7a0979414251b62f7e3444a9b" + }, + { + "url": "linux/soft/yapi-ops.html", + "revision": "d12e4348627a3f735f754732be107ed6" + }, + { + "url": "mac/soft/ruby-install.html", + "revision": "5664b9736b30f71516ba5db30fca5ccc" + } +].concat(self.__precacheManifest || []); +workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); +addEventListener('message', event => { + const replyPort = event.ports[0] + const message = event.data + if (replyPort && message && message.type === 'skip-waiting') { + event.waitUntil( + self.skipWaiting().then( + () => replyPort.postMessage({ error: null }), + error => replyPort.postMessage({ error }) + ) + ) + } +})