Repository: wsargent/docker-cheat-sheet Branch: master Commit: 5b1b6d7738d7 Files: 8 Total size: 217.4 KB Directory structure: gitextract_upaged8i/ ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── es-es/ │ └── README.md ├── pt-br/ │ └── README.md ├── ru/ │ └── README.md └── zh-cn/ └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .idea ================================================ FILE: .travis.yml ================================================ language: ruby rvm: 2.2 before_script: gem install awesome_bot script: awesome_bot README.md --allow-redirect --allow-dupe -w vagrantup.com ================================================ FILE: LICENSE ================================================ Attribution 4.0 International ======================================================================= Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an "as-is" basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC- licensed material, or material used under an exception or limitation to copyright. More considerations for licensors: wiki.creativecommons.org/Considerations_for_licensors Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor's permission is not necessary for any reason--for example, because of any applicable exception or limitation to copyright--then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public: wiki.creativecommons.org/Considerations_for_licensees ======================================================================= Creative Commons Attribution 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part; and b. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. ======================================================================= Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. ================================================ FILE: README.md ================================================ # Docker Cheat Sheet **Want to improve this cheat sheet? See the [Contributing](#contributing) section!** ## Table of Contents * [Why Docker](#why-docker) * [Prerequisites](#prerequisites) * [Installation](#installation) * [Containers](#containers) * [Images](#images) * [Networks](#networks) * [Registry and Repository](#registry--repository) * [Dockerfile](#dockerfile) * [Layers](#layers) * [Links](#links) * [Volumes](#volumes) * [Exposing Ports](#exposing-ports) * [Best Practices](#best-practices) * [Docker-Compose](#docker-compose) * [Security](#security) * [Tips](#tips) * [Contributing](#contributing) ## Why Docker "With Docker, developers can build any app in any language using any toolchain. “Dockerized” apps are completely portable and can run anywhere - colleagues’ OS X and Windows laptops, QA servers running Ubuntu in the cloud, and production data center VMs running Red Hat. Developers can get going quickly by starting with one of the 13,000+ apps available on Docker Hub. Docker manages and tracks changes and dependencies, making it easier for sysadmins to understand how the apps that developers build work. And with Docker Hub, developers can automate their build pipeline and share artifacts with collaborators through public or private repositories. Docker helps developers build and ship higher-quality applications, faster." -- [What is Docker](https://www.docker.com/what-docker#copy1) ## Prerequisites I use [Oh My Zsh](https://github.com/ohmyzsh/oh-my-zsh) with the [Docker plugin](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#docker) for autocompletion of docker commands. YMMV. ### Linux The 3.10.x kernel is [the minimum requirement](https://docs.docker.com/engine/installation/binaries/#check-kernel-dependencies) for Docker. ### MacOS 10.8 “Mountain Lion” or newer is required. ### Windows 10 Hyper-V must be enabled in BIOS VT-D must also be enabled if available (Intel Processors). ### Windows Server Windows Server 2016 is the minimum version required to install docker and docker-compose. Limitations exist on this version, such as multiple virtual networks and Linux containers. Windows Server 2019 and later are recommended. ## Installation ### Linux Run this quick and easy install script provided by Docker: ```sh curl -sSL https://get.docker.com/ | sh ``` If you're not willing to run a random shell script, please see the [installation](https://docs.docker.com/engine/installation/linux/) instructions for your distribution. If you are a complete Docker newbie, you should follow the [series of tutorials](https://docs.docker.com/engine/getstarted/) now. ### macOS Download and install [Docker Community Edition](https://www.docker.com/community-edition). if you have Homebrew-Cask, just type `brew install --cask docker`. Or Download and install [Docker Toolbox](https://docs.docker.com/toolbox/overview/). [Docker For Mac](https://docs.docker.com/docker-for-mac/) is nice, but it's not quite as finished as the VirtualBox install. [See the comparison](https://docs.docker.com/docker-for-mac/docker-toolbox/). > **NOTE** Docker Toolbox is legacy. You should to use Docker Community Edition, See [Docker Toolbox](https://docs.docker.com/toolbox/overview/). Once you've installed Docker Community Edition, click the docker icon in Launchpad. Then start up a container: ```sh docker run hello-world ``` That's it, you have a running Docker container. If you are a complete Docker newbie, you should probably follow the [series of tutorials](https://docs.docker.com/engine/getstarted/) now. ### Windows 10 Instructions to install Docker Desktop for Windows can be found [here](https://docs.docker.com/desktop/windows/install/) Once installed, open powershell as administrator and run: ```powershell # Display the version of docker installed: docker version # Pull, create, and run 'hello-world': docker run hello-world ``` To continue with this cheat sheet, right click the Docker icon in the system tray, and go to settings. In order to mount volumes, the C:/ drive will need to be enabled in the settings to that information can be passed into the containers (later described in this article). To switch between Windows containers and Linux containers, right click the icon in the system tray and click the button to switch container operating system Doing this will stop the current containers that are running, and make them unaccessible until the container OS is switched back. Additionally, if you have WSL or WSL2 installed on your desktop, you might want to install the Linux Kernel for Windows. Instructions can be found [here](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/using-wsl2-in-a-docker-linux-container-on-windows-to-run-a/ba-p/1482133). This requires the Windows Subsystem for Linux feature. This will allow for containers to be accessed by WSL operating systems, as well as the efficiency gain from running WSL operating systems in docker. It is also preferred to use [Windows terminal](https://docs.microsoft.com/en-us/windows/terminal/get-started) for this. ### Windows Server 2016 / 2019 Follow Microsoft's instructions that can be found [here](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/deploy-containers-on-server#install-docker) If using the latest edge version of 2019, be prepared to only work in powershell, as it is only a servercore image (no desktop interface). When starting this machine, it will login and go straight to a powershell window. It is recommended to install text editors and other tools using [Chocolatey](https://chocolatey.org/install). After installing, these commands will work: ```powershell # Display the version of docker installed: docker version # Pull, create, and run 'hello-world': docker run hello-world ``` Windows Server 2016 is not able to run Linux images. Windows Server Build 2004 is capable of running both linux and windows containers simultaneously through Hyper-V isolation. When running containers, use the ```--isolation=hyperv``` command, which will isolate the container using a separate kernel instance. ### Check Version It is very important that you always know the current version of Docker you are currently running on at any point in time. This is very helpful because you get to know what features are compatible with what you have running. This is also important because you know what containers to run from the docker store when you are trying to get template containers. That said let see how to know which version of docker we have running currently. * [`docker version`](https://docs.docker.com/engine/reference/commandline/version/) shows which version of docker you have running. Get the server version: ```console $ docker version --format '{{.Server.Version}}' 1.8.0 ``` You can also dump raw JSON data: ```console $ docker version --format '{{json .}}' {"Client":{"Version":"1.8.0","ApiVersion":"1.20","GitCommit":"f5bae0a","GoVersion":"go1.4.2","Os":"linux","Arch":"am"} ``` ## Containers [Your basic isolated Docker process](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/). Containers are to Virtual Machines as threads are to processes. Or you can think of them as chroots on steroids. ### Lifecycle * [`docker create`](https://docs.docker.com/engine/reference/commandline/create) creates a container but does not start it. * [`docker rename`](https://docs.docker.com/engine/reference/commandline/rename/) allows the container to be renamed. * [`docker run`](https://docs.docker.com/engine/reference/commandline/run) creates and starts a container in one operation. * [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) deletes a container. * [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) updates a container's resource limits. Normally if you run a container without options it will start and stop immediately, if you want keep it running you can use the command, `docker run -td container_id` this will use the option `-t` that will allocate a pseudo-TTY session and `-d` that will detach automatically the container (run container in background and print container ID). If you want a transient container, `docker run --rm` will remove the container after it stops. If you want to map a directory on the host to a docker container, `docker run -v $HOSTDIR:$DOCKERDIR`. Also see [Volumes](https://github.com/wsargent/docker-cheat-sheet/#volumes). If you want to remove also the volumes associated with the container, the deletion of the container must include the `-v` switch like in `docker rm -v`. There's also a [logging driver](https://docs.docker.com/engine/admin/logging/overview/) available for individual containers in docker 1.10. To run docker with a custom log driver (i.e., to syslog), use `docker run --log-driver=syslog`. Another useful option is `docker run --name yourname docker_image` because when you specify the `--name` inside the run command this will allow you to start and stop a container by calling it with the name the you specified when you created it. ### Starting and Stopping * [`docker start`](https://docs.docker.com/engine/reference/commandline/start) starts a container so it is running. * [`docker stop`](https://docs.docker.com/engine/reference/commandline/stop) stops a running container. * [`docker restart`](https://docs.docker.com/engine/reference/commandline/restart) stops and starts a container. * [`docker pause`](https://docs.docker.com/engine/reference/commandline/pause/) pauses a running container, "freezing" it in place. * [`docker unpause`](https://docs.docker.com/engine/reference/commandline/unpause/) will unpause a running container. * [`docker wait`](https://docs.docker.com/engine/reference/commandline/wait) blocks until running container stops. * [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) sends a SIGKILL to a running container. * [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) will connect to a running container. If you want to detach from a running container, use `Ctrl + p, Ctrl + q`. If you want to integrate a container with a [host process manager](https://docs.docker.com/engine/admin/host_integration/), start the daemon with `-r=false` then use `docker start -a`. If you want to expose container ports through the host, see the [exposing ports](#exposing-ports) section. Restart policies on crashed docker instances are [covered here](http://container42.com/2014/09/30/docker-restart-policies/). #### CPU Constraints You can limit CPU, either using a percentage of all CPUs, or by using specific cores. For example, you can tell the [`cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint) setting. The setting is a bit strange -- 1024 means 100% of the CPU, so if you want the container to take 50% of all CPU cores, you should specify 512. See for more: ```sh docker run -it -c 512 agileek/cpuset-test ``` You can also only use some CPU cores using [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint). See for details and some nice videos: ```sh docker run -it --cpuset-cpus=0,4,6 agileek/cpuset-test ``` Note that Docker can still **see** all of the CPUs inside the container -- it just isn't using all of them. See for more details. #### Memory Constraints You can also set [memory constraints](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) on Docker: ```sh docker run -it -m 300M ubuntu:14.04 /bin/bash ``` #### Capabilities Linux capabilities can be set by using `cap-add` and `cap-drop`. See for details. This should be used for greater security. To mount a FUSE based filesystem, you need to combine both --cap-add and --device: ```sh docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs ``` Give access to a single device: ```sh docker run -it --device=/dev/ttyUSB0 debian bash ``` Give access to all devices: ```sh docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash ``` More info about privileged containers [here]( https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities). ### Info * [`docker ps`](https://docs.docker.com/engine/reference/commandline/ps) shows running containers. * [`docker logs`](https://docs.docker.com/engine/reference/commandline/logs) gets logs from container. (You can use a custom log driver, but logs is only available for `json-file` and `journald` in 1.10). * [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) looks at all the info on a container (including IP address). * [`docker events`](https://docs.docker.com/engine/reference/commandline/events) gets events from container. * [`docker port`](https://docs.docker.com/engine/reference/commandline/port) shows public facing port of container. * [`docker top`](https://docs.docker.com/engine/reference/commandline/top) shows running processes in container. * [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats) shows containers' resource usage statistics. * [`docker diff`](https://docs.docker.com/engine/reference/commandline/diff) shows changed files in the container's FS. `docker ps -a` shows running and stopped containers. `docker stats --all` shows a list of all containers, default shows just running. ### Import / Export * [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp) copies files or folders between a container and the local filesystem. * [`docker export`](https://docs.docker.com/engine/reference/commandline/export) turns container filesystem into tarball archive stream to STDOUT. ### Executing Commands * [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) to execute a command in container. To enter a running container, attach a new shell process to a running container called foo, use: `docker exec -it foo /bin/bash`. ## Images Images are just [templates for docker containers](https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work). ### Lifecycle * [`docker images`](https://docs.docker.com/engine/reference/commandline/images) shows all images. * [`docker import`](https://docs.docker.com/engine/reference/commandline/import) creates an image from a tarball. * [`docker build`](https://docs.docker.com/engine/reference/commandline/build) creates image from Dockerfile. * [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit) creates image from a container, pausing it temporarily if it is running. * [`docker rmi`](https://docs.docker.com/engine/reference/commandline/rmi) removes an image. * [`docker load`](https://docs.docker.com/engine/reference/commandline/load) loads an image from a tar archive as STDIN, including images and tags (as of 0.7). * [`docker save`](https://docs.docker.com/engine/reference/commandline/save) saves an image to a tar archive stream to STDOUT with all parent layers, tags & versions (as of 0.7). ### Info * [`docker history`](https://docs.docker.com/engine/reference/commandline/history) shows history of image. * [`docker tag`](https://docs.docker.com/engine/reference/commandline/tag) tags an image to a name (local or registry). ### Cleaning up While you can use the `docker rmi` command to remove specific images, there's a tool called [docker-gc](https://github.com/spotify/docker-gc) that will safely clean up images that are no longer used by any containers. As of docker 1.13, `docker image prune` is also available for removing unused images. See [Prune](#prune). ### Load/Save image Load an image from file: ```sh docker load < my_image.tar.gz ``` Save an existing image: ```sh docker save my_image:my_tag | gzip > my_image.tar.gz ``` ### Import/Export container Import a container as an image from file: ```sh cat my_container.tar.gz | docker import - my_image:my_tag ``` Export an existing container: ```sh docker export my_container | gzip > my_container.tar.gz ``` ### Difference between loading a saved image and importing an exported container as an image Loading an image using the `load` command creates a new image including its history. Importing a container as an image using the `import` command creates a new image excluding the history which results in a smaller image size compared to loading an image. ## Networks Docker has a [networks](https://docs.docker.com/engine/userguide/networking/) feature. Docker automatically creates 3 network interfaces when you install it (bridge, host none). A new container is launched into the bridge network by default. To enable communication between multiple containers, you can create a new network and launch containers in it. This enables containers to communicate to each other while being isolated from containers that are not connected to the network. Furthermore, it allows to map container names to their IP addresses. See [working with networks](https://docs.docker.com/engine/userguide/networking/work-with-networks/) for more details. ### Lifecycle * [`docker network create`](https://docs.docker.com/engine/reference/commandline/network_create/) NAME Create a new network (default type: bridge). * [`docker network rm`](https://docs.docker.com/engine/reference/commandline/network_rm/) NAME Remove one or more networks by name or identifier. No containers can be connected to the network when deleting it. ### Info * [`docker network ls`](https://docs.docker.com/engine/reference/commandline/network_ls/) List networks * [`docker network inspect`](https://docs.docker.com/engine/reference/commandline/network_inspect/) NAME Display detailed information on one or more networks. ### Connection * [`docker network connect`](https://docs.docker.com/engine/reference/commandline/network_connect/) NETWORK CONTAINER Connect a container to a network * [`docker network disconnect`](https://docs.docker.com/engine/reference/commandline/network_disconnect/) NETWORK CONTAINER Disconnect a container from a network You can specify a [specific IP address for a container](https://blog.jessfraz.com/post/ips-for-all-the-things/): ```sh # create a new bridge network with your subnet and gateway for your ip block docker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic # run a nginx container with a specific ip in that block $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx # curl the ip from any other place (assuming this is a public ip block duh) $ curl 203.0.113.2 ``` ## Registry & Repository A repository is a *hosted* collection of tagged images that together create the file system for a container. A registry is a *host* -- a server that stores repositories and provides an HTTP API for [managing the uploading and downloading of repositories](https://docs.docker.com/engine/tutorials/dockerrepos/). Docker.com hosts its own [index](https://hub.docker.com/) to a central registry which contains a large number of repositories. Having said that, the central docker registry [does not do a good job of verifying images](https://titanous.com/posts/docker-insecurity) and should be avoided if you're worried about security. * [`docker login`](https://docs.docker.com/engine/reference/commandline/login) to login to a registry. * [`docker logout`](https://docs.docker.com/engine/reference/commandline/logout) to logout from a registry. * [`docker search`](https://docs.docker.com/engine/reference/commandline/search) searches registry for image. * [`docker pull`](https://docs.docker.com/engine/reference/commandline/pull) pulls an image from registry to local machine. * [`docker push`](https://docs.docker.com/engine/reference/commandline/push) pushes an image to the registry from local machine. ### Run local registry You can run a local registry by using the [docker distribution](https://github.com/docker/distribution) project and looking at the [local deploy](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md) instructions. Also see the [mailing list](https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution). ## Dockerfile [The configuration file](https://docs.docker.com/engine/reference/builder/). Sets up a Docker container when you run `docker build` on it. Vastly preferable to `docker commit`. Here are some common text editors and their syntax highlighting modules you could use to create Dockerfiles: * If you use [jEdit](http://jedit.org), I've put up a syntax highlighting module for [Dockerfile](https://github.com/wsargent/jedit-docker-mode) you can use. * [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting) * [Atom](https://atom.io/packages/language-docker) * [Vim](https://github.com/ekalinin/Dockerfile.vim) * [Emacs](https://github.com/spotify/dockerfile-mode) * [TextMate](https://github.com/docker/docker/tree/master/contrib/syntax/textmate) * [VS Code](https://github.com/Microsoft/vscode-docker) * Also see [Docker meets the IDE](https://domeide.github.io/) ### Instructions * [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * [FROM](https://docs.docker.com/engine/reference/builder/#from) Sets the Base Image for subsequent instructions. * [MAINTAINER (deprecated - use LABEL instead)](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) Set the Author field of the generated images. * [RUN](https://docs.docker.com/engine/reference/builder/#run) execute any commands in a new layer on top of the current image and commit the results. * [CMD](https://docs.docker.com/engine/reference/builder/#cmd) provide defaults for an executing container. * [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) informs Docker that the container listens on the specified network ports at runtime. NOTE: does not actually make ports accessible. * [ENV](https://docs.docker.com/engine/reference/builder/#env) sets environment variable. * [ADD](https://docs.docker.com/engine/reference/builder/#add) copies new files, directories or remote file to container. Invalidates caches. Avoid `ADD` and use `COPY` instead. * [COPY](https://docs.docker.com/engine/reference/builder/#copy) copies new files or directories to container. By default this copies as root regardless of the USER/WORKDIR settings. Use `--chown=:` to give ownership to another user/group. (Same for `ADD`.) * [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) configures a container that will run as an executable. * [VOLUME](https://docs.docker.com/engine/reference/builder/#volume) creates a mount point for externally mounted volumes or other containers. * [USER](https://docs.docker.com/engine/reference/builder/#user) sets the user name for following RUN / CMD / ENTRYPOINT commands. * [WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir) sets the working directory. * [ARG](https://docs.docker.com/engine/reference/builder/#arg) defines a build-time variable. * [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) adds a trigger instruction when the image is used as the base for another build. * [STOPSIGNAL](https://docs.docker.com/engine/reference/builder/#stopsignal) sets the system call signal that will be sent to the container to exit. * [LABEL](https://docs.docker.com/config/labels-custom-metadata/) apply key/value metadata to your images, containers, or daemons. * [SHELL](https://docs.docker.com/engine/reference/builder/#shell) override default shell is used by docker to run commands. * [HEALTHCHECK](https://docs.docker.com/engine/reference/builder/#healthcheck) tells docker how to test a container to check that it is still working. ### Tutorial * [Flux7's Dockerfile Tutorial](https://www.flux7.com/tutorial/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/) ### Examples * [Examples](https://docs.docker.com/engine/reference/builder/#dockerfile-examples) * [Best practices for writing Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) * [Michael Crosby](http://crosbymichael.com/) has some more [Dockerfiles best practices](http://crosbymichael.com/dockerfile-best-practices.html) / [take 2](http://crosbymichael.com/dockerfile-best-practices-take-2.html). * [Building Good Docker Images](http://jonathan.bergknoff.com/journal/building-good-docker-images) / [Building Better Docker Images](http://jonathan.bergknoff.com/journal/building-better-docker-images) * [Managing Container Configuration with Metadata](https://speakerdeck.com/garethr/managing-container-configuration-with-metadata) * [How to write excellent Dockerfiles](https://rock-it.pl/how-to-write-excellent-dockerfiles/) ## Layers The versioned filesystem in Docker is based on layers. They're like [git commits or changesets for filesystems](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/). ## Links Links are how Docker containers talk to each other [through TCP/IP ports](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). [Atlassian](https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/) show worked examples. You can also resolve [links by hostname](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file). This has been deprecated to some extent by [user-defined networks](https://docs.docker.com/network/). NOTE: If you want containers to ONLY communicate with each other through links, start the docker daemon with `-icc=false` to disable inter process communication. If you have a container with the name CONTAINER (specified by `docker run --name CONTAINER`) and in the Dockerfile, it has an exposed port: ``` EXPOSE 1337 ``` Then if we create another container called LINKED like so: ```sh docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress ``` Then the exposed ports and aliases of CONTAINER will show up in LINKED with the following environment variables: ```sh $ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR ``` And you can connect to it that way. To delete links, use `docker rm --link`. Generally, linking between docker services is a subset of "service discovery", a big problem if you're planning to use Docker at scale in production. Please read [The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) for more info. ## Volumes Docker volumes are [free-floating filesystems](https://docs.docker.com/engine/tutorials/dockervolumes/). They don't have to be connected to a particular container. You can use volumes mounted from [data-only containers](https://medium.com/@ramangupta/why-docker-data-containers-are-good-589b3c6c749e) for portability. As of Docker 1.9.0, Docker has named volumes which replace data-only containers. Consider using named volumes to implement it rather than data containers. ### Lifecycle * [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) * [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) ### Info * [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) * [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) Volumes are useful in situations where you can't use links (which are TCP/IP only). For instance, if you need to have two docker instances communicate by leaving stuff on the filesystem. You can mount them in several docker containers at once, using `docker run --volumes-from`. Because volumes are isolated filesystems, they are often used to store state from computations between transient containers. That is, you can have a stateless and transient container run from a recipe, blow it away, and then have a second instance of the transient container pick up from where the last one left off. See [advanced volumes](http://crosbymichael.com/advanced-docker-volumes.html) for more details. [Container42](http://container42.com/2014/11/03/docker-indepth-volumes/) is also helpful. You can [map MacOS host directories as docker volumes](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume): ```sh docker run -v /Users/wsargent/myapp/src:/src ``` You can use remote NFS volumes if you're [feeling brave](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume). You may also consider running data-only containers as described [here](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) to provide some data portability. Be aware that you can [mount files as volumes](#volumes-can-be-files). ## Exposing ports Exposing incoming ports through the host container is [fiddly but doable](https://docs.docker.com/engine/reference/run/#expose-incoming-ports). This is done by mapping the container port to the host port (only using localhost interface) using `-p`: ```sh docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT \ --name CONTAINER \ -t someimage ``` You can tell Docker that the container listens on the specified network ports at runtime by using [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose): ```Dockerfile EXPOSE ``` Note that `EXPOSE` does not expose the port itself - only `-p` will do that. To expose the container's port on your localhost's port, run: ```sh iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination : ``` If you're running Docker in Virtualbox, you then need to forward the port there as well, using [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html). Define a range of ports in your Vagrantfile like this so you can dynamically map them: ``` Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end ``` If you forget what you mapped the port to on the host container, use `docker port` to show it: ```sh docker port CONTAINER $CONTAINERPORT ``` ## Best Practices This is where general Docker best practices and war stories go: * [The Rabbit Hole of Using Docker in Automated Tests](http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/) * [Bridget Kromhout](https://twitter.com/bridgetkromhout) has a useful blog post on [running Docker in production](http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html) at Dramafever. * There's also a best practices [blog post](http://developers.lyst.com/devops/2014/12/08/docker/) from Lyst. * [Building a Development Environment With Docker](https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/) * [Discourse in a Docker Container](https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container) ## Docker-Compose Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the [list of features](https://docs.docker.com/compose/overview/#features). By using the following command you can start up your application: ```sh docker-compose -f up ``` You can also run docker-compose in detached mode using -d flag, then you can stop it whenever needed by the following command: ```sh docker-compose stop ``` You can bring everything down, removing the containers entirely, with the down command. Pass `--volumes` to also remove the data volume. ## Security This is where security tips about Docker go. The Docker [security](https://docs.docker.com/engine/security/security/) page goes into more detail. First things first: Docker runs as root. If you are in the `docker` group, you effectively [have root access](https://web.archive.org/web/20161226211755/http://reventlov.com/advisories/using-the-docker-command-to-root-the-host). If you expose the docker unix socket to a container, you are giving the container [root access to the host](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/). Docker should not be your only defense. You should secure and harden it. For an understanding of what containers leave exposed, you should read [Understanding and Hardening Linux Containers](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf) by [Aaron Grattafiori](https://twitter.com/dyn___). This is a complete and comprehensive guide to the issues involved with containers, with a plethora of links and footnotes leading on to yet more useful content. The security tips following are useful if you've already hardened containers in the past, but are not a substitute for understanding. ### Security Tips For greatest security, you want to run Docker inside a virtual machine. This is straight from the Docker Security Team Lead -- [slides](http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security) / [notes](http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/). Then, run with AppArmor / seccomp / SELinux / grsec etc to [limit the container permissions](http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/). See the [Docker 1.10 security features](https://blog.docker.com/2016/02/docker-engine-1-10-security/) for more details. Docker image ids are [sensitive information](https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4) and should not be exposed to the outside world. Treat them like passwords. See the [Docker Security Cheat Sheet](https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc) by [Thomas Sjögren](https://github.com/konstruktoid): some good stuff about container hardening in there. Check out the [docker bench security script](https://github.com/docker/docker-bench-security), download the [white papers](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/). Snyk's [10 Docker Image Security Best Practices cheat sheet](https://snyk.io/blog/10-docker-image-security-best-practices/) You should start off by using a kernel with unstable patches for grsecurity / pax compiled in, such as [Alpine Linux](https://en.wikipedia.org/wiki/Alpine_Linux). If you are using grsecurity in production, you should spring for [commercial support](https://grsecurity.net/business_support.php) for the [stable patches](https://grsecurity.net/announce.php), same as you would do for RedHat. It's $200 a month, which is nothing to your devops budget. Since docker 1.11 you can easily limit the number of active processes running inside a container to prevent fork bombs. This requires a linux kernel >= 4.3 with CGROUP_PIDS=y to be in the kernel configuration. ```sb docker run --pids-limit=64 ``` Also available since docker 1.11 is the ability to prevent processes from gaining new privileges. This feature have been in the linux kernel since version 3.5. You can read more about it in [this](http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/) blog post. ```sh docker run --security-opt=no-new-privileges ``` From the [Docker Security Cheat Sheet](http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf) (it's in PDF which makes it hard to use, so copying below) by [Container Solutions](http://container-solutions.com/is-docker-safe-for-production/): Turn off interprocess communication with: ```sh docker -d --icc=false --iptables ``` Set the container to be read-only: ```sh docker run --read-only ``` Verify images with a hashsum: ```sh docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be ``` Set volumes to be read only: ```sh docker run -v $(pwd)/secrets:/secrets:ro debian ``` Define and run a user in your Dockerfile so you don't run as root inside the container: ```Dockerfile RUN groupadd -r user && useradd -r -g user user USER user ``` ### User Namespaces There's also work on [user namespaces](https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/) -- it is in 1.10 but is not enabled by default. To enable user namespaces ("remap the userns") in Ubuntu 15.10, [follow the blog example](https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/). ### Security Videos * [Using Docker Safely](https://youtu.be/04LOuMgNj9U) * [Securing your applications using Docker](https://youtu.be/KmxOXmPhZbk) * [Container security: Do containers actually contain?](https://youtu.be/a9lE9Urr6AQ) * [Linux Containers: Future or Fantasy?](https://www.youtube.com/watch?v=iN6QbszB1R8) ### Security Roadmap The Docker roadmap talks about [seccomp support](https://github.com/docker/docker/blob/master/ROADMAP.md#11-security). There is an AppArmor policy generator called [bane](https://github.com/jfrazelle/bane), and they're working on [security profiles](https://github.com/docker/docker/issues/17142). ## Tips Sources: * [15 Docker Tips in 5 minutes](http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes) * [CodeFresh Everyday Hacks Docker](https://codefresh.io/blog/everyday-hacks-docker/) ### Prune The new [Data Management Commands](https://github.com/docker/docker/pull/26108) have landed as of Docker 1.13: * `docker system prune` * `docker volume prune` * `docker network prune` * `docker container prune` * `docker image prune` ### df `docker system df` presents a summary of the space currently used by different docker objects. ### Heredoc Docker Container ```sh docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF ``` ### Last IDs ```sh alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld ``` ### Commit with command (needs Dockerfile) ```sh docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres ``` ### Get IP address ```sh docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4 ``` Or with [jq](https://stedolan.github.io/jq/) installed: ```sh docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress' ``` Or using a [go template](https://docs.docker.com/engine/reference/commandline/inspect): ```sh docker inspect -f '{{ .NetworkSettings.IPAddress }}' ``` Or when building an image from Dockerfile, when you want to pass in a build argument: ```sh 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` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/ ``` ### Get port mapping ```sh docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' ``` ### Find containers by regular expression ```sh for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done ``` ### Get Environment Settings ```sh docker run --rm ubuntu env ``` ### Kill running containers ```sh if [ "$(docker ps -q)" ]; then docker kill $(docker ps -q); else echo "No running containers."; fi ``` ### Delete all containers (force!! running or stopped containers) ```sh if [ "$(docker ps -qa)" ]; then docker rm -f $(docker ps -qa); else echo "No containers to delete."; fi ``` ### Delete old containers ```sh docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm ``` ### Delete stopped containers ```sh docker rm -v $(docker ps -a -q -f status=exited) ``` ### Delete containers after stopping ```sh docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq) ``` ### Delete dangling images ```sh docker rmi $(docker images -q -f dangling=true) ``` ### Delete all images ```sh docker rmi $(docker images -q) ``` ### Delete dangling volumes As of Docker 1.9: ```sh docker volume rm $(docker volume ls -q -f dangling=true) ``` In 1.9.0, the filter `dangling=false` does _not_ work - it is ignored and will list all volumes. ### Show image dependencies ```sh docker images -viz | dot -Tpng -o docker.png ``` ### Slimming down Docker containers - Cleaning APT in a `RUN` layer - This should be done in the same layer as other `apt` commands. Otherwise, the previous layers still persist the original information and your images will still be fat. ```Dockerfile RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ``` - Flatten an image ```sh ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name ``` - For backup ```sh ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name ``` ### Monitor system resource utilization for running containers To check the CPU, memory, and network I/O usage of a single container, you can use: ```sh docker stats ``` For all containers listed by ID: ```sh docker stats $(docker ps -q) ``` For all containers listed by name: ```sh docker stats $(docker ps --format '{{.Names}}') ``` For all containers listed by image: ```sh docker ps -a -f ancestor=ubuntu ``` Remove all untagged images: ```sh docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}') ``` Remove container by a regular expression: ```sh docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f ``` Remove all exited containers: ```sh docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }') ``` ### Volumes can be files Be aware that you can mount files as volumes. For example you can inject a configuration file like this: ```sh # copy file from container docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # edit file vim httpd.conf # start container with modified configuration docker run --rm -it -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd ``` ## Contributing Here's how to contribute to this cheat sheet. ### Open README.md Click [README.md](https://github.com/wsargent/docker-cheat-sheet/blob/master/README.md) <-- this link ![Click This](images/click.png) ### Edit Page ![Edit This](images/edit.png) ### Make Changes and Commit ![Change This](images/change.png) ![Commit](images/commit.png) ================================================ FILE: es-es/README.md ================================================ # Docker Cheat Sheet **¿Quieres colaborar en este *cheat sheet*? ¡Revisa la sección de [Contribución](#contributing)!** ## Tabla de Contenidos * [Por qué Docker](#por-qué-Docker) * [Prerrequisitos](#prerrequisitos) * [Instalación](#instalación) * [Contenedores](#contenedores) * [Imágenes](#imágenes) * [Redes](#redes) * [Registry y Repositorios](#Registry-y-Repositorios) * [Dockerfile](#dockerfile) * [Capas](#capas) * [Enlaces](#enlaces) * [Volúmenes](#volúmenes) * [Exponiendo Puertos](#Exponiendo-Puertos) * [Buenas prácticas](#buenas-prácticas) * [Docker-Compose](#docker-compose) * [Seguridad](#seguridad) * [Consejos](#consejos) * [Contribución](#contribución) ## Por qué Docker "Con Docker, los desarrolladores (y desarrolladoras) pueden construir cualquier aplicación en cualquier lenguaje usando cualquier herramienta. Las aplicaciones "Dockerizadas" son totalmente portables y pueden funcionar en cualquier lugar: En portátiles con OS X y Windows de compañeros; servidores de QA con Ubuntu en el cloud; y VMs de los datacenters de producción que funcionan con Red Hat. Los desarrolladores pueden empezar a trabajar rápidamente a partir de cualquiera de las más de 13.000 aplicaciones disponibles en Docker Hub. Docker gestiona y guarda los cambios y dependencias, facilitando el trabajo a los Administradores de Sistemas a la hora de entender cómo funcionan las aplicaciones hechas por los desarrolladores. Y, con Docker Hub, los desarrolladores puedes automatizar el despliegue y compartir el trabajo con colaboradores a través de repositorios públicos o privados. Docker ayuda a los desarrolladores a trabajar y conseguir aplicaciones de mejor calidad de forma más rápida." -- [Qué es docker](https://www.docker.com/what-docker#copy1) ## Prerrequisitos De forma opcional, se puede hacer utilizar [Oh My Zsh](https://github.com/ohmyzsh/oh-my-zsh) con el [plugin de Docker](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#docker) para autocompletar los comandos de Docker. ### Linux [El requisito mínimo](https://docs.docker.com/engine/installation/binaries/#check-kernel-dependencies) para Docker es utilizar una versión de Kernel (núcleo) posterior a la 3.10.x. ### MacOS Se requiere de la versión 10.8 “Mountain Lion” o posterior. ### Windows 10 Se debe activar Hyper-V en la BIOS. En caso de estar disponible, también se debe activar VT-D (Procesadores Intel). ### Windows Server Como mínimo se requiere la versiín de Windows Server 2016 para instalar Docker y Docker Compose. No obstante, existen limitaciones en esta versión, como a la hora de utilizar redes virtualizadas y contenedores Linux. Se recomienda utilizar Windows Server 2019 o posteriores. ## Instalación ### Linux Ejecuta este comando rápido y sencillo proporcionado por Docker: ```sh curl -sSL https://get.docker.com/ | sh ``` Si no estás dispuesto a ejecutar un shell script que no sabes lo que trae, por favor: revisa las instrucciones de [instalación](https://docs.docker.com/engine/installation/linux/) de tu distribución. Si eres totalmente nuevo en Docker, te recomendamos seguir esta [serie de tutoriales](https://docs.docker.com/engine/getstarted/). ### macOS Descarga e instala [Docker Community Edition](https://www.docker.com/community-edition). Si tienes Homebrew-Cask, simplemente escribe `brew install --cask docker`. O descarga e instala [Docker Toolbox](https://docs.docker.com/toolbox/overview/). [Docker For Mac](https://docs.docker.com/docker-for-mac/) está bien, pero no está tan pulido como como la instalación de VirtualBox. [Revisa la comparación aquí](https://docs.docker.com/docker-for-mac/docker-toolbox/). > **NOTA:** Docker Toolbox está deprecado. Deberías utilizar Docker Community Edition, revisa [Docker Toolbox](https://docs.docker.com/toolbox/overview/). Una vez hayas instalado Docker Community Edition, haz click en el icono de docker en el Launchpad. Entonces inicia un contenedor: ```sh docker run hello-world ``` ¡Y ya estaría! Ya tienes un contenedor de docker funcionando. Si eres totalmente nuevo en Docker, te recomendamos seguir esta [serie de tutoriales](https://docs.docker.com/engine/getstarted/). ### Windows 10 Las instrucciones para instalar Docker Desktop para Windows se encuentran [aquí](https://docs.docker.com/desktop/windows/install/) Una vez instalado, abre Powershell como administrador y ejecuta: ```powershell # Muestra la versión de docker instalada: docker version # Descarga, crea, y ejecuta 'hello-world': docker run hello-world ``` Para continuar con esta chuleta, haz click derecho sobre el icono de Docker en la sección de notificaciones (abajo a la derecha), y ves a ajustes. Para montar volúmenes, el disco C:/ debe ser habilitado en ajustes para poder pasar la información a los contenedores (se detalla más adelante en este artículo). Para alternar entre contenedores Windows y Linux, haz botón derecho en el icono de Docker en la sección de notificaciones y haz click en el botón de cambiar el sistema operativo del contenedor. Hacer esto parará los contenedores que estén funcionando y serán inaccesibles hasta que el SO del contenedor vuelva a cambiar. Adicionalmente, si tienes WSL (Subsitema de Windows para Linux) o WSL2 instalado en tu equipo, quizás también quieras instalar el Kernel de Linux para Windows. Las instrucciones para ello pueden encontrarse [aquí](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/using-wsl2-in-a-docker-linux-container-on-windows-to-run-a/ba-p/1482133). Esto requiere la característica de Subsistema de Windows para Linux. Esto permitirá que los contenedores sean accesibles desde los sistemas operativos WSL, así como mejorar la eficiencia ejecutando sistemas operaviso WSL en docker. También es preferible utilizar la [terminal de Windows](https://docs.microsoft.com/en-us/windows/terminal/get-started) para esto. ### Windows Server 2016 / 2019 Sigue las instrucciones de Microsoft que puedes encontrar [aquí](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/deploy-containers-on-server#install-docker) Si haces uso de la última versión de 2019, prepárate para trabajar solo con powershell, dado que es solo una imágen del núcleo del servidor (sin interfaz de escritorio). Cuando inicies esta máquina, se logueará y mostrará una ventana de powerhell. Se recomienda instalar editores de texto y otras herramientas utilizando [Chocolatey](https://chocolatey.org/install) Tras instalarlo, funcionarán los siguientes comandos: ```powershell # Muestra la versión de docker instalada: docker version # Descarga, crea, y ejecuta 'hello-world': docker run hello-world ``` Windows Server 2016 no puede ejecutar imágenes de Linux. Windows Server Build 2004 es capaz de ejecutar contenedores de Linux y Windows simultáneamente a través del aislamiento de Hyper-V. Cuando se ejecuten los contenedores, utiliza el comando ```isolation=hyperv```, el cual lo aislará utilizando distintas instancias de kernel para cada contenedor. ### Revisar la versión Es muy importante que siempre conozcas la versión de Docker que estás utilizando en cualquier momento. Es muy útil dado que permite saber las características compatibles con lo que estés ejecutando. Esto también es importante para conocer que contenedores puedes ejecutar de la docker store cuando estés intentando utilizar un contenedor como plantilla. Dicho esto, veamos como recuperar la versión de Docker que está ejecutándose actualmente. * [`docker version`](https://docs.docker.com/engine/reference/commandline/version/) muestra que versión de docker está ejecutándose. Recuperar la versión del servidor: ```console $ docker version --format '{{.Server.Version}}' 1.8.0 ``` Puedes volcar la información en un JSON: ```console $ docker version --format '{{json .}}' {"Client":{"Version":"1.8.0","ApiVersion":"1.20","GitCommit":"f5bae0a","GoVersion":"go1.4.2","Os":"linux","Arch":"am"} ``` ## Contenedores [Proceso básico del aislamiento en Docker](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/). Los contenedores son a las máquinas virtuales lo que los threads son a los procesos. O puedes verlo como un *chroot* dopado. ### Ciclo de vida * [`docker create`](https://docs.docker.com/engine/reference/commandline/create) crea un contenedor pero no lo inicia. * [`docker rename`](https://docs.docker.com/engine/reference/commandline/rename/) permite renombrar el nombre de un contenedor. * [`docker run`](https://docs.docker.com/engine/reference/commandline/run) crea e inicia un contenedor. * [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) elimina un contenedor. * [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) actualiza los recursos máximos de un contenedor. Si ejecutas un contenedor sin opciones este se iniciará y detendrá automáticamente, si quieres mantenerlo funcionando puedes utilizar el comando `docker run -td container_id`, esto utilizará la opción `-t`, que habilitará una pseudo-sesión de TTY, y `-d`, que separará el contenedor automáticamente (lo ejecutará en segundo plano y mostrará la ID del contenedor) Si quieres un contenedor efímero, `docker run --rm` eliminará el contenedor en cuanto se detenga. Si quieres mapear un directorio del host al contenedor de docker, `docker run -v $HOSTDIR:$DOCKERDIR`. Revisa [Volúmenes](https://github.com/wsargent/docker-cheat-sheet/#volumes). Si al eliminar el contenedor también quieres borrar los volúmenes asociados, el borrado deberá contener `-v`, por ejemplo: `docker rm -v`. También existe un [driver de logs](https://docs.docker.com/engine/admin/logging/overview/) disponible para contenedores individuales en Docker 1.10. Para ejecutar docker con un driver de logs personalizado, ejecuta `docker run --log-driver=syslog`. Otra opciónútil es `docker run --name yourname docker_image` donde especificando la opción `--name` dentro del comando *run*, esto te permitirá iniciar y detener el contenedor utilizando el nombre especificado al crearlo. ### Ejecutando y deteniendo * [`docker start`](https://docs.docker.com/engine/reference/commandline/start) inicia un contenedor. * [`docker stop`](https://docs.docker.com/engine/reference/commandline/stop) detiene un contenedor que esté iniciado. * [`docker restart`](https://docs.docker.com/engine/reference/commandline/restart) detiene y ejecuta un contenedor. * [`docker pause`](https://docs.docker.com/engine/reference/commandline/pause/) pausa un contenedor que se está ejecutando, congelándolo. * [`docker unpause`](https://docs.docker.com/engine/reference/commandline/unpause/) reactiva un contenedor. * [`docker wait`](https://docs.docker.com/engine/reference/commandline/wait) se bloquea hasta que el contenedor se detiene. * [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) envía una SIGKILL a un contenedor. * [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) se conecta a un contenedor. Si quieres despegarte de un contenedor, utiliza `Ctrl + p, Ctrl + q`. Si quieres integrar un contenedor con un [gestor de procesos](https://docs.docker.com/engine/admin/host_integration/), inicia el daemon con `-r=false`, después utiliza `docker start -a`. Si quieres exponer un puerto del contenedor a través del host, revisa la sección [exponiendo puertos](#exposing-ports). Las políticas de reinicio en una instancia bloqueada se [explica aquí](http://container42.com/2014/09/30/docker-restart-policies/). #### Restricciones de CPU Puedes limitar la CPU, ya sea especificando el porcentáge global de las CPU o definiendo el número de núcleos. Por ejemplo, puedes especificar la configuración de [`cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint). Este parámetro es un poco raro -- 1024 significa el 100% de la CPU, por lo que si quieres que el contenedor utilice el 50% de todas las CPU, deberás especificar 512. Revisa para más información. ```sh docker run -it -c 512 agileek/cpuset-test ``` Tambiés puedes utilizar únicamente algunos núcleos de la CPU utilizando [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint). Revisa para más detalles y algunos vídeos guays: ```sh docker run -it --cpuset-cpus=0,4,6 agileek/cpuset-test ``` Fíjate que Docker puede seguir **viendo** todas las CPU dentro del contenedor -- simplemente no la utiliza entera. Revisa para más información. #### Restricciones de memoria También puedes especificar [restricciones de memoria](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) en Docker ```sh docker run -it -m 300M ubuntu:14.04 /bin/bash ``` #### Capacidades Las capacidades de linux se pueden establecer utilizando `cap-add` y `cap-drop`. Revisa para más detalles. Debe usarse para una mejor seguridad. Para montar un sistema de ficheros basado en FUSE, debes combinar --cap-add con --device: ```sh docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs ``` Para dar acceso a un único dispositivo: ```sh docker run -it --device=/dev/ttyUSB0 debian bash ``` Para dar acceso a todos los dispositivos: ```sh docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash ``` Más información sobre contenedores con privilegios [aquí]( https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities) ### Información * [`docker ps`](https://docs.docker.com/engine/reference/commandline/ps) muestra los contenedores funcionando. * [`docker logs`](https://docs.docker.com/engine/reference/commandline/logs) recupera los logs del contenedor. (Puedes utilizar un driver personalizado para los logs, pero los logs solo están disponibles para `json-file` y `journald` en la versión 1.10). * [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) revisa toda la información del contenedor (incluyendo la dirección IP). * [`docker events`](https://docs.docker.com/engine/reference/commandline/events) recupera los eventos del contenedor. * [`docker port`](https://docs.docker.com/engine/reference/commandline/port) muestra los puertos abiertos al exterior del contenedor. * [`docker top`](https://docs.docker.com/engine/reference/commandline/top) muestra los procesos que se están ejecutando en el contenedor, * [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats) Muestra las estadísticas del uso de recursos del contenedor. * [`docker diff`](https://docs.docker.com/engine/reference/commandline/diff) Muestra los archivos que han cambiado en el sistema de ficheros del contenedor. `docker ps -a` muestra todos los contenedores: que están funcionados o parados. `docker stats --all` lista todos los contenedores, por defecto solo los que están funcionando. ### Import / Export * [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp) copia los ficheros y carpetas de un contenedor al sistema de ficheros local. * [`docker export`](https://docs.docker.com/engine/reference/commandline/export) vuelca el sistema de ficheros de un contenedor como fichero .tar en el STDOUT. ### Ejecuntando comandos * [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) ejecuta un comando en el contenedor. Para entrar a un contenedor que está funcionando, acopla un nuevo proceso de terminal al contenedor usando: `docker exec -it /bin/bash`. ## Imágenes Las imágenes simplemente son [plantillas para contenedores de docker](https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work). ### Ciclo de vida * [`docker images`](https://docs.docker.com/engine/reference/commandline/images) muestra todas las imágenes. * [`docker import`](https://docs.docker.com/engine/reference/commandline/import) crea una imágen a partir de un fichero .tar. * [`docker build`](https://docs.docker.com/engine/reference/commandline/build) crea una imágen a partir de un Dockerfile. * [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit) crea una imágen a partir de un contenedor, deteniéndolo temporalmente si está funcionando. * [`docker rmi`](https://docs.docker.com/engine/reference/commandline/rmi) elimina una imágen. * [`docker load`](https://docs.docker.com/engine/reference/commandline/load) carga una imágen a partir de un fichero .tar pasado como STDIN, incluyendo imágenes y etiquetas. * [`docker save`](https://docs.docker.com/engine/reference/commandline/save) guarda una imágen en un fichero .tar pasado como STDOUT con todas las capas superiores, etiquetas y versiones. ### Información * [`docker history`](https://docs.docker.com/engine/reference/commandline/history) muestra el historial de una imágen. * [`docker tag`](https://docs.docker.com/engine/reference/commandline/tag) etiqueta una imágen (local o *registry*). ### Limpiar Puedes utilizar el comando `docker rmi` para eliminar una imágen específica, pero también existe una herramienta alternativa llamada [docker-gc](https://github.com/spotify/docker-gc) que elimina de forma segura las imágenes que ya no están siendo utilizadas por ningún contenedor. En la versión 1.13 de docker, también existe el comando `docker image prine`, el cual elimina las imágenes que no están siendo utilizadas. Revisa [Prune](#prune) ### Cargar/Guardar una imágen Carga una imágen a partir de un fichero: ```sh docker load < my_image.tar.gz ``` Guarda una imágen existente: ```sh docker save my_image:my_tag | gzip > my_image.tar.gz ``` ### Importar/Exportar un contenedor Importa un contenedor como imágen a partir de un fichero: ```sh cat my_container.tar.gz | docker import - my_image:my_tag ``` Exporta un contenedor existente: ```sh docker export my_container | gzip > my_container.tar.gz ``` ### Diferencia entre cargar y guardar una imágen e importar y exportar un contenedor como imágen Cargar una imágen utilizando el comando `load` crea una nueva imágen incluyeno su historial. Importar un contenedor como imágen utilizando el comando `import` crea una nueva imágen excluyendo el historial, lo que se traduce en una imágen más ligera comparada con cargarla. ## Redes Docker tiene la característica de [Redes](https://docs.docker.com/engine/userguide/networking/). Docker automáticamente crea tres interficies de red al instalarlo (puente, host, nula). Por defecto, cuando se lanza un nuevo contenedor es añadido la red puente. Para habilitar la comunicación entre varios contenedores puedes crear una nueva red y lanzar los contenedores en ella. Esto permite a los contenedores comunicarse entre ellos y aislarese de los contenedores que no están conectados a su misma red. Además, esto permite mapear nombres de contenedores a sus direcciones IP. Revisa *[working with networks](https://docs.docker.com/engine/userguide/networking/work-with-networks/)* para más información. ### Ciclo de vida * [`docker network create`](https://docs.docker.com/engine/reference/commandline/network_create/) NAME Crea una nueva red (por defecto de tipo puente). * [`docker network rm`](https://docs.docker.com/engine/reference/commandline/network_rm/) NAME Elimina una o más redes indicando el nombre o el identificador. No pueden haber contenedores conectados a la red al eliminarla. ### Info * [`docker network ls`](https://docs.docker.com/engine/reference/commandline/network_ls/) Lista las redes creadas. * [`docker network inspect`](https://docs.docker.com/engine/reference/commandline/network_inspect/) NAME Muestra información detallada de una o más redes. ### Connection * [`docker network connect`](https://docs.docker.com/engine/reference/commandline/network_connect/) NETWORK CONTAINER Conecta un contenedor a una red. * [`docker network disconnect`](https://docs.docker.com/engine/reference/commandline/network_disconnect/) NETWORK CONTAINER Desconecta un contenedor de una red. Puedes especificar una [ip específica a un contenedor](https://blog.jessfraz.com/post/ips-for-all-the-things/): ```sh # crea una nueva red puente con la subnet y puerta de enlace específicada docker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic # ejecuta un contenedor de nginx con al ip especificada en la red iptastic $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx # curl hacia la ip desde cualquier otro lugar (dando por hecho que es una ip pública hehe) $ curl 203.0.113.2 ``` ## Registry y Repositorios (Nota de traducción: Registry sería traducido como Regitro, pero nadie le llama así en el mundo real, así que...) Un repositorio es una colección *alojada* de imágenes enlazadas que unidas crean el sistema de ficheros para un contenedor. Un Registry es un *alojamiento* -- un servidor que almacena repositorios y provee de una API HTTP para [gestionar la actualización y descarga de repositorios](https://docs.docker.com/engine/tutorials/dockerrepos/). Docker.com posee su propio [índice](https://hub.docker.com) como un Registry centralizado que contiene un gran número de repositorios. Dicho esto, aclarar que el docker Registry [no hace un buen trabajo verificando imágenes](https://titanous.com/posts/docker-insecurity), por lo que quizás deberías evitarlo si te preocupa la seguridad. * [`docker login`](https://docs.docker.com/engine/reference/commandline/login) para loguear en un registry. * [`docker logout`](https://docs.docker.com/engine/reference/commandline/logout) para desloguear de un registry. * [`docker search`](https://docs.docker.com/engine/reference/commandline/search) busca en el registry por una imágen. * [`docker pull`](https://docs.docker.com/engine/reference/commandline/pull) recupera una imágen del registry a local. * [`docker push`](https://docs.docker.com/engine/reference/commandline/push) sube una imágen local al registry. ### Ejecutar un registry local Puedes ejecutar un registry local utilizando el proyecto [distribución de docker](https://github.com/docker/distribution) y revisando las instrucciones de como realizar el [deploy local](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md) Adicionalmente revisa la [mailing list](https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution) ## Dockerfile [El archivo de configuración](https://docs.docker.com/engine/reference/builder/). Configura un contenedor de docker al ejecutar `docker build` en el. Mucho más preferible a `docker commit`. Aquí tienes varios editores de textos comunes y módulos de resaltado de sintaxis que puedes usar para crear Dockerfiles: * Si utilizas [jEdit](http://jedit.org), puedes hacer uso del módulo de resaltado de sintaxis para [Dockerfile](https://github.com/wsargent/jedit-docker-mode). * [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting) * [Atom](https://atom.io/packages/language-docker) * [Vim](https://github.com/ekalinin/Dockerfile.vim) * [Emacs](https://github.com/spotify/dockerfile-mode) * [TextMate](https://github.com/docker/docker/tree/master/contrib/syntax/textmate) * [VS Code](https://github.com/Microsoft/vscode-docker) * Revisa [Docker meets the IDE](https://domeide.github.io/) ### Instructions * [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * [FROM](https://docs.docker.com/engine/reference/builder/#from) utiliza una imágen de base para las siguientes instrucciones. * [MAINTAINER (deprecated - use LABEL instead)](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) especifica el autor que ha generado las imágenes. * [RUN](https://docs.docker.com/engine/reference/builder/#run) ejecuta cualquier comando en una nueva capa de la imágen y guarda el estado resultante. * [CMD](https://docs.docker.com/engine/reference/builder/#cmd) proporcionar valores predeterminados para un contenedor en ejecución. * [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) informa a Docker que el contenedor estará escuchando los puertos especificados mientras se ejecute. NOTA: no hace que los puertos sean accesibles. * [ENV](https://docs.docker.com/engine/reference/builder/#env) define una variable de entorno. * [ADD](https://docs.docker.com/engine/reference/builder/#add) copia nuevos ficheros, directorios o archivos remotos al contenedor. Invalida cachés. Procura evitar usar `ADD` e intenta utilizar `COPY` en su lugar. * [COPY](https://docs.docker.com/engine/reference/builder/#copy) copia nuevos ficheros o directorios al contenedor. Por defecto los copia como *root* independientemente de la configuración de USER/WORKDIR. Utiliza `--chown=:` para cambiar el dueño. (Lo mismo aplica a `ADD`). * [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) configura un contenedor que funcionará como ejecutable. * [VOLUME](https://docs.docker.com/engine/reference/builder/#volume) crea un punto de montaje para volúmenes externos u otros contenedores. * [USER](https://docs.docker.com/engine/reference/builder/#user) especifica el usuario que ejecutará los próximos comandos de tipo RUN / CMD / ENTRYPOINTS. * [WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir) especifica el directorio de trabajo. * [ARG](https://docs.docker.com/engine/reference/builder/#arg) define una variable que estará disponible durante el build. * [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) añade una instrucción que será lanzada cuando la imágen sea utilizada como base de otro build. * [STOPSIGNAL](https://docs.docker.com/engine/reference/builder/#stopsignal) define la señal que será enviada al contenedor para detenerse. * [LABEL](https://docs.docker.com/config/labels-custom-metadata/) aplica metadatos de clave/valor para las imágenes, contenedores o daemons (servicios). * [SHELL](https://docs.docker.com/engine/reference/builder/#shell) reemplaza la shell por defecto que es utilizada por Docker para ejecutar los comandos. * [HEALTHCHECK](https://docs.docker.com/engine/reference/builder/#healthcheck) indica a docker como probar el contenedor para revisar que sigue funcionando. ### Tutorial * [Flux7's Dockerfile Tutorial](https://www.flux7.com/tutorial/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/) ### Examples * [Ejemplos](https://docs.docker.com/engine/reference/builder/#dockerfile-examples) * [Buenas prácticas para escribir Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) * [Michael Crosby](http://crosbymichael.com/) tiene más consejos de [buenas prácticas para Dockerfile](http://crosbymichael.com/dockerfile-best-practices.html) / [toma 2](http://crosbymichael.com/dockerfile-best-practices-take-2.html). * [Construyendo buenas imágenes de Docker](http://jonathan.bergknoff.com/journal/building-good-docker-images) / [Construyendo mejores imágenes de Docker](http://jonathan.bergknoff.com/journal/building-better-docker-images) * [Gestionando la configuración de un contenedor utilizando metadatos](https://speakerdeck.com/garethr/managing-container-configuration-with-metadata) * [Cómo escribir excelentes Dockerfiles](https://rock-it.pl/how-to-write-excellent-dockerfiles/) ## Capas Las veriones de los sitemas de ficheros en docker se basan en capas. Son similares a los [git commits o conjuntos de cambios para sistemas de ficheros](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/). ## Enlaces Los enlaces definen como los contenedores de Docker se comunican entre ellos [mediante puertos TCP/IP](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). [Atlassian](https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/) lo explica con ejemplos. También puedes resolver [enlaces con nombres de equipo](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file). Esto ha sido parcialmente deprecado por [redes definidas por los usuarios](https://docs.docker.com/network/). NOTA: Si ÚNICAMENTE quieres que los contenedores se comuniquen mediante enlaces, inicia el servicio de Docker con `-icc=false` para desactivar la comunicación entre procesos. Si tienes un contenedor con el nombre CONTAINER (especificado vía `docker run --name CONTAINER`) y, en el Dockerfile, explones un puerto: ``` EXPOSE 1337 ``` Y entonces creas otro contenedor llamado LINKED de la forma: ```sh docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress ``` Entonces los puertos expuertos y alias de CONTAINER se mostrarán en LINKED con las siguientes variables de entorno: Then the exposed ports and aliases of CONTAINER will show up in LINKED with the following environment variables: ```sh $ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR ``` Y te puedes conectar a él de esta forma. Para eliminar los enlaces, utiliza `docker rm --link'. Generalmente, enlazar mediante servicios de docker es un subgrupo de "descrubrimiento de servicios", un gran problema si tienes pensado utilizar Docker para escalar en producción. Por favor, lee [The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) para más información. ## Volúmenes Los volúmenes de Docker son [sitemas de archivos flotantes](https://docs.docker.com/engine/tutorials/dockervolumes/). Estos no se conectan a un contenedor en particular. Puedes utilizar los volúmenes montados de [contenedores de únicamente datos](https://medium.com/@ramangupta/). A partir de Docker 1.9.0, Docker ha nombrado volúmenes que reemplazan los contenedores de solo datos. Considere usar volúmenes con nombre para implementarlo en lugar de contenedores de datos. ### Ciclo de vida * [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) * [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) ### Información * [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) * [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) Los volúmenes son útiles en situaciones donde no puedes utilizar enlaces (los cuales son sólo TCP/IP). Por ejemplo, si necesitases tener dos instancias de docker comunicándose dejando datos en el sistema de ficheros. Puedes montarlos en distintos contenedores de docker a la vez, utilizando `docker run --volumes-from`. Dadp que los volúmenes están aislados del sistema de ficheros, estos también son utilizados para almacenar el estado a partir de cálculos de contenedores temporales. Exacto, puedes tener un contenedor sin estado y temporal ejecutándose a partir de una receta, destruírlo, y entonecs tener otra instancia temporal que pueda recuperar lo que ha dejado atrás el primer contenedor. Revisa [volúmenes avanzados](http://crosbymichael.com/advanced-docker-volumes.html) para más información. [Container42](http://container42.com/2014/11/03/docker-indepth-volumes/) también es de utilidad. Puedes [mapear directorios de MacOS como volúmenes de Docker](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume): ```sh docker run -v /Users/wsargent/myapp/src:/src ``` Puedes utilizar un volúmen NFS remoto si [eres valiente](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume) También puedes plantearme utilizar contenedores de solo datos como se describen [aquí](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) para tener portabilidad de datos. Ten en cuenta que puedes montar [archivos como volúmenes](#volumes-can-be-files). ## Exponiendo puertos Exponer puertos de entrada a través de un contenedor es [complejo pero factible](https://docs.docker.com/engine/reference/run/#expose-incoming-ports). Puede hacerse a través del mapeo de puertos del contenedor hacia el host (utilizando únicamente la interficie de localhost) mediante el uso de `p`: ```sh docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT \ --name CONTAINER \ -t algunaimágen ``` Puedes decirle a docker que el contenedor escucha en el puerto especificado utilizando [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose): ```Dockerfile EXPOSE ``` Nótese que `EXPOSE` no expone el puerto por si mismo - solo `-p` lo hace. Para exponer el puerto de un contenedor en localhost, ejecuta: ```sh iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination : ``` Si estás ejecutando Docker en Virtualbox, también necesitarás hacer forward del puerto, utilizando [forwarded_port] (https://docs.vagrantup.com/v2/networking/forwarded_ports.html). Define un rango de puertos en tu Vagrantfile de la siguiente manera para mapearlos dinámicamente: ``` Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end ``` Si te olvidas de los puertos que has mapeado, utiliza `docker port` para mostrarlo: ```sh docker port CONTAINER $CONTAINERPORT ``` ## Buenas prácticas Aquí tienes algunas buenas prácticas de Docker y algunas batallitas: * [The Rabbit Hole of Using Docker in Automated Tests](http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/) * [Bridget Kromhout](https://twitter.com/bridgetkromhout) has a useful blog post on [running Docker in production](http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html) at Dramafever. * También tienes buenas prácticas en este [post](http://developers.lyst.com/devops/2014/12/08/docker/) de Lyst. * [Building a Development Environment With Docker](https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/) * [Discourse in a Docker Container](https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container) ## Docker-Compose Compose es una herramienta para definir y ejecutar varias aplicaciones en contenedores de Docker. Con Compose, utilizas un archivo YAML para configurar tus servicios. Entonces, con un único comando, creas e inicias todos los servicios desde tus configuraciones. Para aprender más sobre las características de Compose, revisa la [lista de características](https://docs.docker.com/compose/overview/#features). Utilizando el siguiente comando puedes iniciar tu aplicación: ```sh docker-compose -f up ``` También puedes ejecutar docker-compose en segundo plano utilizando el parámentro -d, entonces podrás detenerlo cuando lo necesitas con el comando: ```sh docker-compose stop ``` Puedes tirarlo todo, eliminando los contenedores completamente, con el comando down. Utiliza el parámetro `--volumes` para también eliminar los volúmenes de datos. ## Seguridad Aquí te dejamos algunso consejos de seguridad sobre como funciona Docker. La página de Docker de [seguridad]](https://docs.docker.com/engine/security/security/) lo explica en más detalle. Lo primero: Docker se ejecuta como root. Si estás en el grupo `docker`, [tienes acceso root](https://web.archive.org/web/20161226211755/http://reventlov.com/advisories/using-the-docker-command-to-root-the-host). Si expones el socket de unix de docker a un contenedor, le estás dando al contenedor acceso [root a la máquina host](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/). Docker no debería ser tu única defensa. Deberías asegurarlo y protejerlo. Para entender como se exponen los contenedores, deberías leer [Entendiendo y endureciendo Contenedores Linux](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf) de [Aaron Grattafiori](https://twitter.com/dyn___). Esta es una guía completa y entendible sobre los riesgos relacionados con los contenedores, con una gran cantidad de enlaces y notas a pié de página. Los siguientes consejos de seguridad son útiles si ya has protejido tus contenedores en el pasado, pero no son substitutos a entenderlo. ### Consejos de seguridad Para mayor seguridad, puedes ejecutar Docker dentro de una máquina virtual. Esto es un consejo del Jefe del Equipo de Seguridad de Docker -- [diapositivas](http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security) / [notas](http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/). Entonces, ejecutalo con AppArmor / seccomp / SELinux /grsec etc. para [limitar los permisos del contenedor](http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/). Revisa [las características de seguridad de Docker 1.10](https://blog.docker.com/2016/02/docker-engine-1-10-security/) para más detalles. Los identificadores de las imágenes de Docker son [información sensible](https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4) y no deberían exponerse al mundo exterior. Trátalos como contraseñas. Revisa la [Chuleta de Seguridad de Docker](https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc) de [Thomas Sjögren](https://github.com/konstruktoid): ahí podrás encontrar buenos consejos sobre como protejerse. Revisa el [script de seguridad de Docker Bench](https://github.com/docker/docker-bench-security). [Las 10 Mejores Prácticas de Seguridad para Imágenes de Docker](https://snyk.io/blog/10-docker-image-security-best-practices/) de Snyk Puedes empezar utilizando un Kernel con parches inestables de *grsecurity* / *pax* compilados, como [Alpine Linux](https://en.wikipedia.org/wiki/Alpine_Linux). Si haces uso de *grsecurity* en producción, deberías buscar [soporte comercial](https://grsecurity.net/business_support.php) para los [parches estables](https://grsecurity.net/announce.php), de la misma forma que deberías hacer para RedHat. Son unos 200$ al mes, lo cual es insignificante para el presupuesto de devops. A partir de Docker 1.11, puedes limitar fácilmente el número de procesos que se ejecutan en un contenedor para evitar *fork bombs*. Esto requiere utilizar un Kernel de Linux >= 4.3 con CGROUP_PIDS=y en la configuración del kernel. ```sb docker run --pids-limit=64 ``` A partir de Docker 1.11 también está disponible la posibilidad de evitar que los procesos ganen nuevos privilegios. Esta característica está en el Kernel de Linux desde la versión 3.5. Puedes leer más al respecto en [este](http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/) blog. ```sh docker run --security-opt=no-new-privileges ``` De la [Chuleta de Seguridad de Docker](http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf) (es un PDF y es un poco complejo de usar, así que mejor copia de abajo) de [Container Solutions](http://container-solutions.com/is-docker-safe-for-production/): Desactiva la comunicación interproceso con: ```sh docker -d --icc=false --iptables ``` Establece que el contenedor sea solo lectura: ```sh docker run --read-only ``` Verifica las imágenes con un *hashsum*: ```sh docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be ``` Establece el volúmen como solo lectura: ```sh docker run -v $(pwd)/secrets:/secrets:ro debian ``` Crea y utiliza un usiario en el Dockerfile para evitar ejecutar como root dentro del contenedor: ```Dockerfile RUN groupadd -r user && useradd -r -g user user USER user ``` ### Espacio de Nombres del Usuario (*User Namespaces*) También hay que trabajar con los [espacios de nombres de usuario](https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/) -- disponibles en la 1.10, pero no activados por defecto. Para activar esta característica ("reasignar los usuarios") en ubuntu 15.10, [sigue este ejemplo](https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/). ### Videos de Seguridad * [Using Docker Safely](https://youtu.be/04LOuMgNj9U) * [Securing your applications using Docker](https://youtu.be/KmxOXmPhZbk) * [Container security: Do containers actually contain?](https://youtu.be/a9lE9Urr6AQ) * [Linux Containers: Future or Fantasy?](https://www.youtube.com/watch?v=iN6QbszB1R8) ### Ruta de Seguridad La ruta de Docker habla sobre [el soporte de *seccomp*](https://github.com/docker/docker/blob/master/ROADMAP.md#11-security). También hay una política de AppArmor llamada [base](https://github.com/jfrazelle/bane), y están trabajando en [perfiles de seguridad](https://github.com/docker/docker/issues/17142) ## Consejos Fuentes: * [15 Docker Tips in 5 minutes](http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes) * [CodeFresh Everyday Hacks Docker](https://codefresh.io/blog/everyday-hacks-docker/) ### Prune Los nuevos [Comandos de manejo de datos](https://github.com/docker/docker/pull/26108) llegaron a Docker en la versión 1.13 * `docker system prune` * `docker volume prune` * `docker network prune` * `docker container prune` * `docker image prune` ### df `docker system df` muestra un resumen del espacio actualmente utilizado por los distintos elementos de Docker. ### Heredoc Docker Container ```sh docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF ``` ### Últimas IDs ```sh alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld ``` ### Commit con comando (necesita de Dockerfile) ```sh docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres ``` ### Recuperar la dirección IP ```sh docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4 ``` O, con [jq](https://stedolan.github.io/jq/) instalado: ```sh docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress' ``` O, utilizando una [plantilla](https://docs.docker.com/engine/reference/commandline/inspect): ```sh docker inspect -f '{{ .NetworkSettings.IPAddress }}' ``` O, al construir la imágen desde un Dockerfile, cuando quieres pasar argumentos de compilación: ```sh 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` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/ ``` ### Recuperar el mapping de puertos ```sh docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' ``` ### Encontrar contenedores mediante expresiones regulares ```sh for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done ``` ### Recuperar la configuraciín del entorno ```sh docker run --rm ubuntu env ``` ### Detener los contenedores en funcionamiento ```sh docker kill $(docker ps -q) ``` ### Eliminar todos los contenedores (¡FORZANDO! Los borrará estén funcionando o parados) ```sh docker rm -f $(docker ps -qa) ``` ### Eliminar los viejos contenedores ```sh docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm ``` ### Eliminar los contenedores detenidos ```sh docker rm -v $(docker ps -a -q -f status=exited) ``` ### Eliminar los contenedores después de pararlos ```sh docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq) ``` ### Eliminar las imágenes colgadas ```sh docker rmi $(docker images -q -f dangling=true) ``` ### Eliminar todas las imágenes ```sh docker rmi $(docker images -q) ``` ### Eliminar los volúmenes colgados Como en Docker 1.9: ```sh docker volume rm $(docker volume ls -q -f dangling=true) ``` En 1.90, el filtro `dangling=false` _no_ funciona - es ignorado y mostrará todos los volúmenes ### Mostrar las dependencias de las imágenes ```sh docker images -viz | dot -Tpng -o docker.png ``` ### Reducir el tamaño de los contenedores Docker - Limpiar el APT en una capa `RUN` - Esto debería hacerse en la misma capa que los otros comandos `apt`. Sino, las capas previas seguirán teniendo la información original y la imágen seguirá siendo pesada. ```Dockerfile RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ``` - Aplanar una imágen ```sh ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name ``` - Para las copias de seguridad ```sh ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name ``` ### Monitorizar los recursos del sistema utilizados por los contenedores en funcionamiento Para revisar el uso de CPU, memoria y E/S de red para un solo contenedor, puedes utilizar: ```sh docker stats ``` Para todos los contenedores listados por ID: ```sh docker stats $(docker ps -q) ``` Para todos los contenedores listados por nombre: ```sh docker stats $(docker ps --format '{{.Names}}') ``` Para todos los contenedores listados por imágen: ```sh docker ps -a -f ancestor=ubuntu ``` Eliminar todas las imágenes sin etiquetas: ```sh docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}') ``` Eliminar contenedores mediante una expresión regular: ```sh docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f ``` Elimina todos los contenedores en estado "Exit": ```sh docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }') ``` ### Los volúmenes pueden ser ficheros Ten encuenta que puedes montar ficheros como volúmenes. Por ejemplo, pueden inyectar un archivo de configuración así: ```sh # copia el archivo del contenedor docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # edita el archivo vim httpd.conf # inicia el contenedor con la configuracion modificada docker run --rm -it -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd ``` ## Contribución Aquí tienes como contribuír a esta chuleta. ### Open README.md hack click en el [README.md](https://github.com/wsargent/docker-cheat-sheet/blob/master/README.md) <-- este link ![Click](../images/click.png) ### Edit Page ![Edit](../images/edit.png) ### Make Changes and Commit ![Cambios](../images/change.png) ![Commit](../images/commit.png) ================================================ FILE: pt-br/README.md ================================================ # Docker Cheat Sheet **Deseja melhorar este *cheat sheet*? Veja a seção de [Contribuição](#contribution)** ## Conteúdo * [Porque usar docker](#why-docker) * [Pré-requisitos](#prerequisites) * [Instalação](#installation) * [Containers](#containers) * [Imagens](#images) * [Redes](#networks) * [Registro e Repositório](#registry--repository) * [Dockerfile](#dockerfile) * [Camadas](#layers) * [Links](#links) * [Volumes](#volumes) * [Expondo portas](#exposing-ports) * [Boas práticas](#best-practices) * [Docker-Compose](#docker-compose) * [Segurança](#security) * [Dicas](#tips) * [Contribuição](#contributing) ## Porque usar Docker "Com Docker, desenvolvedores podem construir qualquer app em qualquer linguagem usando qualquer conjunto de ferramentas. Apps *Dockerizados* são completamente portáveis e podem rodar em qualquer lugar -- OS X e Windows laptops, servidores QA rodando Ubuntu na nuvem e *data centers* em produção rodando Red Hat em Máquinas Virtuais. Desenvolverodes podem iniciar a utilizá-lo rapidamente com um dos mais de 13.000 apps disponíveis no Docker hub. Docker gerencia e rastreia alterações e dependências, tornando mais fácil para *sysadmins* o entendimento do funcionamento de apps construido pelos desenvolvedores. Além disso, com Docker Hub, desenvolvedores podem automatizar o pipeline de *build* e compartilhar *artifacts* com colaboradores através de repositórios públicos ou privados. Docker auxilia desenvolvedores a construir e entregar aplicações de alta qualidade de maneira mais rápida." -- [O que é Docker (*What is Docker*)](https://www.docker.com/what-docker#copy1) ## Pré-requisitos Eu utilizo [Oh My Zsh](https://github.com/ohmyzsh/oh-my-zsh) com [Docker plugin](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#docker) para autocompletar os comandos do docker. ### Linux O kernel 3.10.x é [o requisito mínimo](https://docs.docker.com/engine/installation/binaries/#check-kernel-dependencies) para o uso do Docker. ### MacOS É necessário *“Mountain Lion”* 10.8 ou mais recente. ### Windows 10 É necessário que o *Hyper-V* esteja habilitado na BIOS. Além disso, para precessadores intel, o VT-D também precisa estar habilidado caso esteja disponível. ### Windows Server Windows Server 2016 é a versão mínima necessária para instalar o docker e o docker-compose. Existem limitações nessa versão, como por exemplo múltiplas redes virtuais e containers Linux. Windows Server 2019 ou posterior é recomendado. ## Instalação ### Linux Um simples, fácil e rápido *script* é disponibilizado pelo Docker: ``` curl -sSL https://get.docker.com/ | sh ``` Se você não deseja rodar um *shell script* aleatório de internet, basta acessar as [instruções de instalação](https://docs.docker.com/engine/installation/linux/) para a sua distribuição. Se você não sabe nada sobre Docker, provavelmente você deveria seguir essa [série de tutoriais](https://docs.docker.com/engine/getstarted/) antes de continuar. ### macOS Baixe e instale o [*Docker Community Edition*](https://www.docker.com/community-edition). Se você possui o Homebrew-Cask, apenas utilize o comando `brew install --cask docker`. Ou baixe e instale o [*Docker Toolbox*](https://docs.docker.com/toolbox/overview/). [Docker para Mac](https://docs.docker.com/docker-for-mac/) é ok, mas ele ainda não é tão pronto quanto a instalação da VirtualBox. [Veja a comparação](https://docs.docker.com/docker-for-mac/docker-toolbox/). > **NOTA** *Docker Toolbox* está no estado *legacy*. Você deveria usar o *Docker Community Edition*. Veja o [*Docker Toolbox*](https://docs.docker.com/toolbox/overview/). Assim que você instalar o *Docker Community Edition*, clique no ícone do Docker no *Launchpad*. Em seguida inicie um container: ``` docker run hello-world ``` É isso! Agora você tem um Docker container rodando. Se você não sabe nada sobre Docker, provavelmente você deveria seguir essa [série de tutoriais](https://docs.docker.com/engine/getstarted/) antes de continuar. ### Windows 10 Você encontra instruções para instalar o Docker Desktop para Windows [neste link](https://docs.docker.com/desktop/windows/install/). Uma vez instalado, abra o *powershell* como administrador ```powershell #Exibe a versão do docker instalado docker version #Todos comandos pull, create, e run 'hello-world' em apenas um: docker run hello-world ``` Para continuar as instruções neste *cheat sheet*, clique com botão direito do mouse no ícone do Docker -- no menu iniciar ou onde quer que seja -- e vá em configurações. Para montar volumes, você precisa habilitar o disco C:/ para que as informaçõe sejam transmitidas para os containers (que ainda será explicado neste artigo). Para trocar entre containers Windows e Linux, clique com o botão direito no icone do Docker e, na sequência, clique no botão para trocar sistema operacional dos containers. Após fazer isso, todos os containers ques estiveram rodando serão desligados e ficaram inacessíveis até que o SO do container ser trocado novamente. Além disso, se você possui WSL ou WSL2 instalado no seu desktop, você pode instalar o Kernel do Linux para Windows. Instruções para executar tal tarefa podem ser encontradas [aqui] [here](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/using-wsl2-in-a-docker-linux-container-on-windows-to-run-a/ba-p/1482133). Atente-se ao fato de que para isso, é necessário o recurso do Subsistema Windows para Linux. Isso permitirá que os containers sejam acessados pelos sistemas operacionais WSL, bem como o ganho de eficiêcia da execução dos sistemas operacionais WSL no Docker. Por fim, tamém é preferível o uso do [terminal Windows](https://docs.microsoft.com/en-us/windows/terminal/get-started) para tal tarefa. ### Windows Server 2016 / 2019 Siga as instruções da Microsoft disponíveis [aqui](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/deploy-containers-on-server#install-docker) Se estiver usando a última versão de 2019, esteja preparado para trabalhar com o *powershell*, uma vez que esta versão não possui interface desktop. Quando inciar a máquina, ela vai logar e ir direto para um janela *powershell*. É recomendado instalar um editor de texto dentre outras ferramentas utilizando [Chocolatey](https://chocolatey.org/install). Após a instalação, esses comandos devem funcionar: ```powershell #Exibe a versão do docker instalado docker version #Todos comandos pull, create, e run 'hello-world' em apenas um: docker run hello-world ``` O Windows Server 2016 não é capar de rodar images Linux. O Windows Server Build 2004 é capar de rodar containers Linux e Windows simultâneamente através do isolamento *Hyper-V*. Quando rodar os containers, utilize o comando ```--isolation=hyperv``` que vai isolar o container utilizando uma instância de kernel separada. ### Checando a versão É muito importante que você sempre saiba a versão do Docker que você está utilizando. Isso é muito útil porque você vai saber quais *features* são compatíveis com aquilo que você está rodado. Além disso, isso também é importante pois você saberá quais containers você deve rodar a partir da *Docker store* quando você estiver tentando usar *containers templates*. Sendo assim, vamos dar um olhar em como saber a versão do Docker que você está rodando no momento. * [`docker version`](https://docs.docker.com/engine/reference/commandline/version/): mostra a versão do Docker que você está rodando Obtendo a versão do servidor: ``` $ docker version --format '{{.Server.Version}}' 1.8.0 ``` Você também pode fazer um *dump* dos dados em JSON: ``` $ docker version --format '{{json .}}' {"Client":{"Version":"1.8.0","ApiVersion":"1.20","GitCommit":"f5bae0a","GoVersion":"go1.4.2","Os":"linux","Arch":"am"} ``` ## Containers [O processo básico isolado do Docker](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/). Containers são para máquinas virtuais o que *threads* são para processos. Ou você pode imaginá-los como *chroots* com esteróides. ### Ciclo de vida * [`docker create`](https://docs.docker.com/engine/reference/commandline/create) cria um container mas não o inicia. * [`docker rename`](https://docs.docker.com/engine/reference/commandline/rename/) permite renomear um container. * [`docker run`](https://docs.docker.com/engine/reference/commandline/run) cria e inicia um container em uma única operação * [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) deleta um container * [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) atualiza os limites de recurso de um container. Normalmente, se você rodar um container sem utilizar nenhuma opção ele vai iniciar e parar imediatamente. Se você deseja que ele continue rodando você pode usar o comando `docker run -td `. A opção `-t` vai alocar uma sessão pseudo-TTY e o `-d` vai desacomplar o container automaticamente (ou seja, vai rodar o container em background e imprimir o ID do container). Se você deseja um container transiente, `docker run --rm` vai remover o container assim que ele parar. Se você deseja mapear um diretório da máquina *host* para o container do Docker, `docker run -v $HOSTDIR:$DOCKERDIR`. Saiba mais em [Volumes](https://github.com/wsargent/docker-cheat-sheet/#volumes). Se você também deseja remover o volume associado ao container, ao deletar o container você deve incluir a opção `-v`, por exemplo, `docker rm -v`. Também existe o [*logging driver*](https://docs.docker.com/engine/admin/logging/overview/), disponível para containers individuais no docker 1.10. Para rodar o docker com um *log driver* customizado (ou seja, para syslog), use `docker run --log-driver=syslog`. Outra opção muito útil é o `docker run --name ` porque você pode especificar o `--name` dentro do comando `run` que vai lhe permite iniciar e parar o container através do nome que você especificou quando o criou. ### Iniciando e parando * [`docker start`](https://docs.docker.com/engine/reference/commandline/start) inicia um container, então ele passa a rodar. * [`docker stop`](https://docs.docker.com/engine/reference/commandline/stop) para um container que esteja rodando. * [`docker restart`](https://docs.docker.com/engine/reference/commandline/restart) para e inicia um container. * [`docker pause`](https://docs.docker.com/engine/reference/commandline/pause/) pausa um container que esteja rodando, "congelando" ele da maneira que está. * [`docker unpause`](https://docs.docker.com/engine/reference/commandline/unpause/) vai despausar um container que estava rodando. * [`docker wait`](https://docs.docker.com/engine/reference/commandline/wait) bloqueia o container até que ele seja parado. * [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) envia um SIGKILL para um container que esteja rodando. * [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) vai se conectar a um container que esteja rodando. Se você deseja desacoplar um container que esteja rodando, utilize `Ctrl + p, Ctrl + q`. Se você deseja integrar um container com o [gerenciador de processos do host](https://docs.docker.com/engine/admin/host_integration/), inicialize o daemon com `-r=false` e depois use `docker start -a`. Se você deseja expor portas do container través do *host*, veja a seção [expondo portas](#exposing-ports). Políticas de reinicialização para instâncias "crashadas" do docker são [cobridas aqui](http://container42.com/2014/09/30/docker-restart-policies/). #### Restrições de CPU Você pode limitar o uso da CPU, seja usando uma porcentagem de todas as CPUs ou usando *cores* específicos. Por exemplo, você pode usar a configuração [`cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint). A configuração é um pouco estranha -- 1024 significa 100% da CPU, então se você quer um container que toma 50% de todos os *cores*, você deve utilizar 512. Veja para mais: ``` docker run -it -c 512 agileek/cpuset-test ``` Você também pode usar alguns *cores* de uma CPU com o comando [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint). Veja para mais detalhes e alguns vídeos bem legais: ``` docker run -it --cpuset-cpus=0,4,6 agileek/cpuset-test ``` Observe que o Docker ainda pode **enxergar** todas as CPUs de dentro do container -- ele apenas não está usando todas elas. Veja para mais detalhes. #### Restrições de memória Você também pode setar [restrições de memória](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) no Docker: ``` docker run -it -m 300M ubuntu:14.04 /bin/bash ``` #### *Capabilities* Linux *capabilities* podem ser setadas utilizand as opções `cap-add` e `cap-drop`. Veja See para mais detalhes. Elas devem ser utilizadas para aumentar a seguraça do sistema. Para montar um *filesystem* baseado no FUSE, você precisa combinar tanto `--cap-add` quanto `--device`: ``` docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs ``` Para dar acesso a um único *device*: ``` docker run -it --device=/dev/ttyUSB0 debian bash ``` Para dar acesso a todos os *devices*: ``` docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash ``` Para mais informações sobre privilégios em containers [clique aqui](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities). ### Info * [`docker ps`](https://docs.docker.com/engine/reference/commandline/ps) motra os containers que estão rodando. * [`docker logs`](https://docs.docker.com/engine/reference/commandline/logs) obtém um log dos containers. (Você pode usar um log customizado, mas eles estão disponíveis apenas para `json-file` e `journald` na versão 1.10). * [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) olha para todas as informações de um container (incluindo o endereço IP). * [`docker events`](https://docs.docker.com/engine/reference/commandline/events) obtém os eventos de um container. * [`docker port`](https://docs.docker.com/engine/reference/commandline/port) mostra a porta pública de um container. * [`docker top`](https://docs.docker.com/engine/reference/commandline/top) mostra os processos rodando dentro de um container. * [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats) mostra uma estatística dos recursos que o container está utilizando. * [`docker diff`](https://docs.docker.com/engine/reference/commandline/diff) mostra os arquivos alterados pelo FS de um container. `docker ps -a` mostra os containers que estão rodando e os que foram parados. `docker stats --all` mostra uma lista de todos os containers. O padrão é mostrar apenas os que estão rodando. ### Importar / Exportar * [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp) copia arquivos ou pastas entre o container e o *filesystem* local. * [`docker export`](https://docs.docker.com/engine/reference/commandline/export) transforma o *filesystem* do container em um fluxo de arquivo *tarball* para STDOUT. ### Executando comandos * [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) executa um comando dentro do container. Por exemplo, para entrar em um container fictício, que esteja rodando, chamado foo, inclua um shell a ele da seguinte maneira: `docker exec -it foo /bin/bash`. ## Imagens Imagens são apenas [templates de um container docker](https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work). ### Ciclo de vida * [`docker images`](https://docs.docker.com/engine/reference/commandline/images) mostra todas as imagens. * [`docker import`](https://docs.docker.com/engine/reference/commandline/import) cria uma imagem a partir de um *tarball*. * [`docker build`](https://docs.docker.com/engine/reference/commandline/build) cria uma imagem a partir de um Dockerfile. * [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit) cria uma imagem a partir de um container, pausando ele temporariamente caso ele esteja rodando. * [`docker rmi`](https://docs.docker.com/engine/reference/commandline/rmi) remove uma imagem. * [`docker load`](https://docs.docker.com/engine/reference/commandline/load) carrega uma imagem a partir de um arquivo tar no STDIN, incluindo imagess and tags (a partir da versão 0.7). * [`docker save`](https://docs.docker.com/engine/reference/commandline/save) salva uma imagem em um arquivo tar através do STDOUT com todas as camadas pais, tags e versões (a partir do 0.7). ### Info * [`docker history`](https://docs.docker.com/engine/reference/commandline/history) mostra o histórico de todas as imagens. * [`docker tag`](https://docs.docker.com/engine/reference/commandline/tag) dar uma tag a uma imagem (local ou *registry*) ### Fazendo uma limpeza Você pode utilizar o comando `docker rmi` para remover imagens específicas, porém, existe uma ferramenta chamada [docker-gc](https://github.com/spotify/docker-gc), que de maneira segura, limpa as imagens que não está sendo utilizada por nenhum container. that will safely clean up images that are no longer used by any containers. A partir do docker 1.13, o comando `docker image prune` também está disponível para remover imagens que não estão sendo usadas. Veja a seção [Prune](#prune). ### Carregar/Salvar imagens Carregue uma imagem a partir do arquivo: ``` docker load < my_image.tar.gz ``` Salve uma imagem existente usando: ``` docker save my_image:my_tag | gzip > my_image.tar.gz ``` ### Importar/Exportar containers Importe um container com uma imagem a partir de um arquivo: ``` cat my_container.tar.gz | docker import - my_image:my_tag ``` Exporte um container existente usando: ``` docker export my_container | gzip > my_container.tar.gz ``` ### Diferenças entre carregar uma imagem salva e importar um container exportado como uma imagem Carregar uma imagem usanfo o comando `load` cria uma nova imagem, incluindo o seu histórico. Importar um container como uma imagem usando o comando `import` cria uma nova imagem excluindo o seu histórico, o que resulta em uma imamgem de tamanho menor do que usando o comando anterior. ## Rede O Docker possui *features* de [rede](https://docs.docker.com/engine/userguide/networking/). Automaticamente, ele cria 3 interfaces de rede quando você o instala (*bridge*, *host*, *none*). Um novo container é inicializado, por padrão, dentro da rede *bridge*. Para habilitar a comunicação entre multiplos containers, você pode criar uma nova rede e iniciarlizar o mesmo com ela. Isso vai habilitar a comunicação entre os containers dentro dela ao mesmo tempo que os isola dos outros containers que não estejam conectados nesta rede. Além disso, isso permite mapear os nomes dos containers com o seus respectivos endereços IP. Veja [trabalhando com redes](https://docs.docker.com/engine/userguide/networking/work-with-networks/) para mais detalhes. ### Ciclo de vida * [`docker network create `](https://docs.docker.com/engine/reference/commandline/network_create/) cria uma nova rede (tipo padrão: *bridge*). * [`docker network rm `](https://docs.docker.com/engine/reference/commandline/network_rm/) remode uma ou mais redes especificadas pelo nome ou identificador. Nenhum container pode se conectar em uma rede quando deletada. ### Info * [`docker network ls`](https://docs.docker.com/engine/reference/commandline/network_ls/) lista todas as redes. * [`docker network inspect `](https://docs.docker.com/engine/reference/commandline/network_inspect/) mostra informações detalhadas de uma ou mais redes. ### Conexão * [`docker network connect `](https://docs.docker.com/engine/reference/commandline/network_connect/) Conecta um container a uma rede * [`docker network disconnect `](https://docs.docker.com/engine/reference/commandline/network_disconnect/) Desconecta um container de uma rede Você pode especificar um [endereço IP para um container](https://blog.jessfraz.com/post/ips-for-all-the-things/): ``` # cria uma nova rede bridge com sua subnet e gateway para seu bloco de endereço IP docker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic # roda um container nginx com um IP específico para o dado bloco $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx # da um culr no IP a partir de qualquer outro local (assumindo que este seja um IP público) $ curl 203.0.113.2 ``` ## Registry & Repositório Um repositório é uma coleção *hosteada* de imagens com tagas que juntas criam um sistema de arquivo para um container; Um *registry* é um *host* -- ou seja, um servidor que armazena repositórios e disponibiliza um API HTTP para [gerencias o upload e download dos repositórios](https://docs.docker.com/engine/tutorials/dockerrepos/). O Docker.com *hostea* seus prórpios [índices](https://hub.docker.com/) em uma central de *registries* qie contém um grande número de repositórios. Sendo assim, essa central [não é muito boa em verificar a procedência das imagens](https://titanous.com/posts/docker-insecurity) e deve ser evitada caso segurança seja algo crítico para você. * [`docker login`](https://docs.docker.com/engine/reference/commandline/login) efetua login em um *registry*. * [`docker logout`](https://docs.docker.com/engine/reference/commandline/logout) efetua logout de um *registry*. * [`docker search`](https://docs.docker.com/engine/reference/commandline/search) busca imagens dentro do *registry*. * [`docker pull`](https://docs.docker.com/engine/reference/commandline/pull) efetua um *pull* de uma imagem do *registry* para sua máquina local. * [`docker push`](https://docs.docker.com/engine/reference/commandline/push) efetua um *push* de uma imagem para o *registry* a partir da sua máquina local. ### Rodando um *registry* local Você pode rodar um *registry* local utilizando o projeto de [distribuição docker](https://github.com/docker/distribution) e seguindo as instruções de [*deploy* local](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md). Além disso, você pode se interessar pela [lista de emails](https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution). ## Dockerfile [O arquivo de configuração](https://docs.docker.com/engine/reference/builder/). Prepara um container Docker quando você executa o comando `docker build`. A maioria das pessoas preferem este comando do que o `docker commit`. Estes são alguns dos editores de texto que dão suporte, em termos de módulos que destacam a sintaxe, para criar Dockerfiles: * Se você utiliza o [jEdit](http://jedit.org), eu adicionei um módulo para destacar de sintaxe para o [Dockerfile](https://github.com/wsargent/jedit-docker-mode). Sinta-se livre para usar. * [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting) * [Atom](https://atom.io/packages/language-docker) * [Vim](https://github.com/ekalinin/Dockerfile.vim) * [Emacs](https://github.com/spotify/dockerfile-mode) * [TextMate](https://github.com/docker/docker/tree/master/contrib/syntax/textmate) * [VS Code](https://github.com/Microsoft/vscode-docker) * Veja também [Docker meets the IDE](https://domeide.github.io/) ### Instruções * [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * [FROM](https://docs.docker.com/engine/reference/builder/#from) Prepara a imagem base para as instruções subsequentes. * [MAINTAINER (depreciado - use a tag LABEL)](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) Define o autor que gerou a imagem. * [RUN](https://docs.docker.com/engine/reference/builder/#run) executa qualquer comando em uma nova camada em cima de uma imagem e *comita* o resultado. * [CMD](https://docs.docker.com/engine/reference/builder/#cmd) fornecer padrões para um container em execução. * [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) informa o Docker que o container pode escutar uma determinada porta de rede durante o tempo de execução. NOTA: isso não faz com que a porta seja acessível. * [ENV](https://docs.docker.com/engine/reference/builder/#env) define uma variável de ambiente. * [ADD](https://docs.docker.com/engine/reference/builder/#add) copia novos arquivos, diretórios, ou arquivos remotos em um container. Invalida cache. Evite usar `ADD` e use o comando `COPY`. * [COPY](https://docs.docker.com/engine/reference/builder/#copy) copia um novo arquivo ou diretórios para dentro do container. Por padrão copia como root independente das configurações do USER/WORKDIR. Utilize `--chown=:` para poderes de acesso a outros usuários/grupos. (o mesmo é válido para o comando `ADD`.) * [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) configura um container que vai rodar como um executável. * [VOLUME](https://docs.docker.com/engine/reference/builder/#volume) cria um ponto de montagem para montar volumes externos ou outros containers. * [USER](https://docs.docker.com/engine/reference/builder/#user) define o nome de usuário para os seguintes comandos: RUN / CMD / ENTRYPOINT. * [WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir) define o diretório de trabalho. * [ARG](https://docs.docker.com/engine/reference/builder/#arg) define uma variável que existe durante o tempo de execução do *build*. * [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) adicionar uma instrução alarme que dispara quando a imagem está sendo usada como base para outra *build*. * [STOPSIGNAL](https://docs.docker.com/engine/reference/builder/#stopsignal) define o sinal de alerta do sistema que vai ser enviado para sair do container. * [LABEL](https://docs.docker.com/config/labels-custom-metadata/) aplica uma chave/valor para suas imagens, containers, ou *daemons*. * [SHELL](https://docs.docker.com/engine/reference/builder/#shell) sobrecarrega o shell padrão para rodar os comandos do docker. * [HEALTHCHECK](https://docs.docker.com/engine/reference/builder/#healthcheck) informa docker como testar o container para testar se tudo está funcionando adequadamente. ### Tutorial * [Tutorial do Flux7 para o Dockerfile](https://www.flux7.com/tutorial/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/) ### Exemplos * [Exemplos](https://docs.docker.com/engine/reference/builder/#dockerfile-examples) * [Boas práticas para escrever Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) * [Michael Crosby](http://crosbymichael.com/) tem mais algumas [boas práticas para criar Dockerfiles](http://crosbymichael.com/dockerfile-best-practices.html) / [parte 2](http://crosbymichael.com/dockerfile-best-practices-take-2.html). * [Construindo boas imagens Docker](http://jonathan.bergknoff.com/journal/building-good-docker-images) / [Construindo imagens Dockers ainda melhores](http://jonathan.bergknoff.com/journal/building-better-docker-images) * [Gerenciando a configuração de um container com metadados](https://speakerdeck.com/garethr/managing-container-configuration-with-metadata) * [Como escrever excelentes Dockerfiles](https://rock-it.pl/how-to-write-excellent-dockerfiles/) ## Camadas O versionamento dos arquivos de sistema do docker é feito em camadas. Elas funcionam como [comits no git ou *changesets* para arquivos de sistemas](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/). ## Links Links são como os containers Docker conversam uns com os outros [através de portas TCP/IP](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). [Atlassian](https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/) mostra alguns exemplos funcionais. Você também pode determinar [links pelo hostname](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file). Este está depreciado para estender algumas [redes definidas por usuário](https://docs.docker.com/network/). NOTA: se você deseja que os containers comuniquem uns com os outros apenas utilizando links, inicie o do docker daemon com `-icc=false` para desebilitar os processor de intra-comunicação. Se você possui um container com nome CONTAINER (especificado por `docker run --name CONTAINER`) e em um Dockerfile, ele possui uma porta exposta: ``` EXPOSE 1337 ``` Então, se nós criarmos qualquer outro container chamado LINKED como este: ``` docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress ``` Então, as portas expostas e os *aliases* do CONTAINER serão mostrados em LINKED com as seguintes variáveis de ambiente: ``` $ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR ``` Você pode se conectar nele dessa maneira. Para deletar os links, utilize o comando `docker rm --link`. Geralmente, a *linkagem* entre serviços docker é um subconjunto de um "descobrimento de serviço", um grande problema caso você esteja planejando usar Docker para escalar em produção. Você pode se referir ao livro [The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) para mais informações. ## Volumes Os volumes no Docker são [arquivos de sistemas flutuantes](https://docs.docker.com/engine/tutorials/dockervolumes/). Eles não possuem uma conexão particular com um container. Você pode usar volumes montados a partir de [container somente de dados](https://medium.com/@ramangupta/why-docker-data-containers-are-good-589b3c6c749e) para fins de portabilidade. A partir do Docker 1.9.0, o Docker passou a nomear volumes que substituem containers apenas de dados. Considere usar volumes nomeados para implementar isso ao invés de containers de dados. ### Ciclo de vidar * [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) * [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) ### Informações * [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) * [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) Volumes são úteis em situações em que você não quer usar links (que são apenas TCP/IP). Por exemplo, se você precisar ter duas instancias docker comunicando através de algo deixado no arquivo de sistema. Você pode montar vários containers docker de uma vez usando o comando `docker run --volumes-from`. Como os volumes são sistemas de arquivos isolados, frequentemente, eles são usados para armazenar estados de alguma computação que é transiente no container. Isto é, você pode ter um container sem estado e transiente continuado de ponto que útimo container deixou. Veja [volumes avançados](http://crosbymichael.com/advanced-docker-volumes.html) para mais detalhes. [Container42](http://container42.com/2014/11/03/docker-indepth-volumes/) também é bem útil. Você pode [mapear diretórios hosts do MacOS como volumes docker](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume): ``` docker run -v /Users/wsargent/myapp/src:/src ``` Você pode usar columes NFS remotos se você estiver se You can use remote NFS volumes if you're [sentindo corajoso](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume). Você também pode considerar rodar containers apenas de dados como descrito [aqui](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) para obter uma certa portabilidade de dados. Saiba que você pode [montar arquivos como volumes](#volumes-can-be-files). ## Expondo portas Expor as portas de entrada através do container *host* é [complicado, mas factível](https://docs.docker.com/engine/reference/run/#expose-incoming-ports). Isso é feito mapeando a porta do container para com a porta do *host* (apenas usando a interface *localhost*) usando a opção `-p`: ``` docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t ALGUMA_IMAGEM ``` Você pode informar ao Docker que o container escuta uma porta de rede específica durante a execução ao usar o comando [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose): ``` EXPOSE ``` Note que `EXPOSE` não expões a porta propriamente dita -- apenas a opção `-p` faz isso. Para expor uma porta do container na sua porta *localhost*: ``` iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination : ``` Se você estiver rodando Docker em uma VirtualBox, então você precisa encaminha a porta para lá também usando uma [*forwarded_port*](https://docs.vagrantup.com/v2/networking/forwarded_ports.html). Defina um intervalo de portas que no seu *Vagrantfile* dessa maneira para que vcê possa mapeá-las dinamicamente: ``` Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end ``` Se você esquecer o que você mapeou na porta do seu container *host*, utilize `docker port` para mostrar o que você fez: ``` docker port CONTAINER $CONTAINERPORT ``` ## Boas práticas É aqui onde boas práticas gerais do Docker uma discusão começa: * [A toca do coelho do uso do Docker em testes automatizados](http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/) * [Bridget Kromhout](https://twitter.com/bridgetkromhout) possui um post muito útil no blog: [rodando Docker em produção](http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html) no Dramafever. * Também tem o [blog post](http://developers.lyst.com/devops/2014/12/08/docker/) de boas práticas feito pela Lyst. * [Contruindo um ambiente de desenvolvimento com Docker](https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/) * [Discurso em um container Docker](https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container) ## Docker-Compose *Compose* é uma ferramenta para definir e rodar aplicações em vários containers Docker. Com o *compose* você utiliza uma arquivo YAML para configurar os serviços de sua aplicação. Na sequência, com uum único comando, você cria e inicia todos os serviços a partir da sua configuração. Para aprender mais sobre todas as funcionalidades do *Compose*, veja a [lista de funcionalidades](https://docs.docker.com/compose/overview/#features). Ao usar este comando, você inicia sua aplicação: ``` docker-compose -f up ``` Você também pode rodar `docker-compose` de maneira desacoplada usando a opção `-d` e parar ele quando quiser utilizando o comando: ``` docker-compose stop ``` Você pode desligar tudo Você pode desligar tudo, remover os containers inteiramente, com o comando `down`. Passe `--volumes` para remover também o dados. ## Segurança Aqui vão as dicas de segurança do Docker! A página sobre [segurança](https://docs.docker.com/engine/security/security/) do Docker fornece muito mais detalhes. Começando do começo: Docker roda como root. Se você está dentro do `docker group`, você [possui acesso root](https://web.archive.org/web/20161226211755/http://reventlov.com/advisories/using-the-docker-command-to-root-the-host). Se você expor um unix socket do docker para um container, você está dando para este container [acesso root para o host](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/). Docker não pode ser sua única defesa. Você deve protegê-lo da melhor maneira possível. Para entender o que os containers deixam exposto, você deveria ler o tutorial [Entendendo e Protegendo Containers Linux](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf) escrito por [Aaron Grattafiori](https://twitter.com/dyn___). Ele um guia completo e compreensível para as questões envolvendo containers com uma grande quantidade de links e notas de rodapés que te leva para conteúdos ainda mais úteis. As dicas de seguranças que vêm a seguir são úteis se você já vem aumentando a segurança dos seus conteiners. Entretanto, elas não substituem o conhecimento sobre o assunto. ### Dicas de segurança Para a maior segurança possível, é desejável rodar o Docker dentro de uma máquina virtual. Essa dica vem direto do líder do time de segurança do Docker -- [slides](http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security) / [notas](http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/). Na sequência, rode ele com AppArmor / seccomp / SELinux / grsec etc para [limitar as permissões do container](http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/). Veja as [funcionalidades de segurança do Docker 1.10](https://blog.docker.com/2016/02/docker-engine-1-10-security/) para mais detalhes. As IDs de imagens do Docker são [informações sensíveis](https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4) e não devem serem expostas para o mundo. Trate elas como *passwords*. Veja o [*Cheat Sheet* de segurança do Docker](https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc) por [Thomas Sjögren](https://github.com/konstruktoid): tem bastante coisa boa sobre aumentar a segurança em containers lá. Dê uma olhada no [script de segurança docker bench](https://github.com/docker/docker-bench-security), baixe os [*white papers*](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/). Veja as [10 melhores práticas de segurança para imagens Docker](https://snyk.io/blog/10-docker-image-security-best-practices/) do Snyk. Você deve começar usando *kernels* com *patches* estáveis do grsecurity / pax compilados, por exemplo, no [Linux Alpine ](https://en.wikipedia.org/wiki/Alpine_Linux). Se você está usando grsecurity em produção, você deve adquirir o [suporte comercial](https://grsecurity.net/business_support.php) para ter [*patches* estáveis](https://grsecurity.net/announce.php), da mesma forma que você faria para o RedHat. Ele custa $200 por mês, o que pe nada para o seu orçamento de DevOps. Desde o Docker 1.11, é fácil limitar o número de processos ativos rodando dentro do container para evitar *fork bombs*. É necessário um kernel Linux >= 4.3 com `CGROUP_PIDS=y` estar na configuração do Kernel. ``` docker run --pids-limit=64 ``` Também está disponível, desde a versão 1.11, uma maneira de prevenir que processos ganhem novos privilégios. Essa funcionalidade está no *kernel* Linux desde a versão 3.5. Saiba mais sobre ela neste [post](http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/) blog post. ``` docker run --security-opt=no-new-privileges ``` No [*Chear sheet* de segurança do Docker](http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf) (está em PDF, o que o torna difícil de usar, então esta copiado na sequência) por [Soluções para containers](http://container-solutions.com/is-docker-safe-for-production/): Desligue a comunicação entre processor usando: ``` docker -d --icc=false --iptables ``` Defina o container como apenas leitura: ``` docker run --read-only ``` Verique as imagens usando `hashsum`: ``` docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be ``` Defina os volumes como apenas leitura: ``` docker run -v $(pwd)/secrets:/secrets:ro debian ``` Defina e roda um usuário no seu Dockerfile, assim você não vai rodar como root dentro do container: ``` RUN groupadd -r user && useradd -r -g user user USER user ``` ### Usando *Namespaces* Também temos que trabalha no [*namespaces* do usuário](https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/) -- ele está na versão 1.1, mas não está disponível por padrão. Para habilitar os *namespaces* do usuário no Ubuntu 15.10, [siga o exemplo descrito neste blog](https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/). ### Vídeos sobre segurança * [Usando Docker de maneira segura](https://youtu.be/04LOuMgNj9U) * [Protegendo suas aplicações usando Docker](https://youtu.be/KmxOXmPhZbk) * [Segurança do container: eles realmente a tem?](https://youtu.be/a9lE9Urr6AQ) * [Linux Containers: Futuro ou Fantasia?](https://www.youtube.com/watch?v=iN6QbszB1R8) ### Roteiro da Segurança O roteiro do Docker fala sobre [suporte ao `secomp`] (https://github.com/docker/docker/blob/master/ROADMAP.md#11-security). Existe também o gerador de política AppArmor chamado [bane](https://github.com/jfrazelle/bane), e eles estão rodando dentro dos [perfis de segurança](https://github.com/docker/docker/issues/17142). ## Dicas Fontes: * [15 dicas do Docjer em 5 minutos](http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes) * [Docker CodeFresh: hacks para o Docker](https://codefresh.io/blog/everyday-hacks-docker/) ### *Prune* Os novos [comandos de gerenciamento de dados](https://github.com/docker/docker/pull/26108) chegaram no Docker 1.13: * `docker system prune` * `docker volume prune` * `docker network prune` * `docker container prune` * `docker image prune` ### df `docker system df` apresenta um resumo do espaço utilizado pelos objetos do Docker. ### Heredoc Docker Container ``` docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF ``` ### Últimos IDs ``` alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld ``` ### Comitar com comandos (precisa de um Dockerfile) ``` docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres ``` ### Obter o endereço IP ``` docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4 ``` ou com [jq](https://stedolan.github.io/jq/) instalado: ``` docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress' ``` ou usando o [template go](https://docs.docker.com/engine/reference/commandline/inspect): ``` docker inspect -f '{{ .NetworkSettings.IPAddress }}' ``` ou quando *buildando* um imagem com Dockerfile, quando você quiser passar um argumento de build: ``` 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` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/ ``` ### Obter mapeamento de porta ``` docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' ``` ### Encontrar container com expressão regular ``` for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done ``` ### Obter configurações de ambiente ``` docker run --rm ubuntu env ``` ### Matar containers que estão rodando ``` docker kill $(docker ps -q) ``` ### Deletar todos os containers (Forçado!! containers que esteja parados ou rodando) ``` docker rm -f $(docker ps -qa) ``` ### Deletar containers antigos ``` docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm ``` ### Deletar containers parados ``` docker rm -v $(docker ps -a -q -f status=exited) ``` ### Deletar containers depois de para-los ``` docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq) ``` ### Deletar imagens pendentes ``` docker rmi $(docker images -q -f dangling=true) ``` ### Delete todas as imagens ``` docker rmi $(docker images -q) ``` ### Deletar volumes pendentes As of Docker 1.9: ``` docker volume rm $(docker volume ls -q -f dangling=true) ``` In 1.9.0, the filter `dangling=false` does _not_ work - it is ignored and will list all volumes. ### Mostrar dependências das imagens ``` docker images -viz | dot -Tpng -o docker.png ``` ### Reduzingo o tamanho dos containers - Limpando APT em uma camada RUN Isso deve ser feito na mesma camada dos outros comandos `apt`. Caso contrário, as camadas anteriores irão persistir e as informações originais das suas imagens vão contiuar grandes. ``` RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ``` - Achatar uma imagem ``` ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name ``` - Fazendo backup ``` ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name ``` ### Monitorar os recursos utilizados pelos containers Para verificar CPU, memória, ou I/O de rede em um único container, você pode usar: To check the CPU, memory, and network I/O usage of a single container, you can use: ``` docker stats ``` Para todos os containers listados por ID: ``` docker stats $(docker ps -q) ``` Para todos os containers listados por nome: ``` docker stats $(docker ps --format '{{.Names}}') ``` Para todos os containers listados por imagem: ``` docker ps -a -f ancestor=ubuntu ``` Remover todas imagens sem tag: ``` docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}') ``` Remover um container usando expressão regular: ``` docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f ``` Remover todos os containers *exitados*: ``` docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }') ``` ### Volumes podem ser arquivos Saiba que você pode montar arquivos como volumes. Por exemplo, se você pode injetar uma configuração dessa forma: ``` bash # copia o arquivo para o container docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # edita o arquivo vim httpd.conf # inicia o container com a configuração que foi modificada docker run --rm -it -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd ``` ## Contrinbuindo com este *chear sheet* Aqui está um pequeno tutorial de como contribuir com este documento. ### Abra o README.md Clique em [README.md](https://github.com/wsargent/docker-cheat-sheet/blob/master/README.md) <-- neste link ![Clique aqui](../images/click.png) ### Edite a página ![Edite aqui](../images/edit.png) ### Faça as mudanças e commit elas ![Mude aqui](../images/change.png) ![Commit](../images/commit.png) ================================================ FILE: ru/README.md ================================================ # Docker Cheat Sheet **Want to improve this cheat sheet? See the [Contributing](#contributing) section!** ## Содержание * [Почему Docker](#Почему-Docker) * [Предпосылки](#Предпосылки) * [Установка](#Установка) * [Контейнеры](#Контейнеры) * [Образы](#Образы) * [Сеть](#Сеть) * [Реестр и репозиторий](#registry--repository) * [Dockerfile](#dockerfile) * [Слои](#layers) * [Ссылка](#links) * [Тома](#volumes) * [Отображение портов](#exposing-ports) * [Лучшая практика](#best-practices) * [Безопасность](#security) * [Советы](#tips) * [Содействие](#contributing) ## Почему Docker "С Docker разработчики могут создавать любое приложение на любом языке, используя любую инструментальную цепочку. Приложения помещаются в контейнер - становятся полностью переносимы и могут работать где угодно - на компьютерах под управлением OS X и Windows, серверах QA, работающих под управлением Ubuntu в облаке, и виртуальных машинах производственного центра обработки данных Red Hat. Разработчики могут быстро начать работу, начиная с одного из 13 000 приложений, доступных на Docker Hub. Docker управляет и отслеживает изменения и зависимости, что облегчает для системных администраторов понимание того, как работают приложения, созданные разработчиками. И с Docker Hub разработчики могут автоматизировать свой процес сборки и совместно использовать артефакты с сотрудниками через публичные или частные репозитории. Docker помогает разработчикам создавать и отправлять более качественные приложения быстрее " -- [Что такое Docker](https://www.docker.com/what-docker#copy1) ## Предпосылки Я использую [Oh My Zsh](https://github.com/robbyrussell/oh-my-zsh) вместе с [Docker plugin](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#docker) для автозаполнения команд docker. Возможно у вас другой подход. ### Linux Ядро 3.10.x [минимальное требование](https://docs.docker.com/engine/installation/binaries/#check-kernel-dependencies) для Docker. ### MacOS 10.8 “Mountain Lion” или более новый. ## Установка ### Linux Быстрый и простой скрипт установки, предоставляемый Docker: ``` curl -sSL https://get.docker.com/ | sh ``` Если вы не хотите запускать случайный сценарий оболочки, см. [Инструкции](https://docs.docker.com/engine/installation/linux/) по установке на ваш дистрибутив. Если вы являетесь полноправным новичком Docker, вы должны следовать [сериям учебников](https://docs.docker.com/engine/getstarted/) сейчас. ### macOS Скачать и установить [Docker Community Edition](https://www.docker.com/community-edition). если у вас есть Homebrew-Cask, просто введите `brew install --cask docker`. Или загрузите и установите [Docker Toolbox](https://docs.docker.com/toolbox/overview/). [Docker для Mac](https://docs.docker.com/docker-for-mac/) это хорошо, но это не совсем так, как установка VirtualBox. [ См. Сравнение](https://docs.docker.com/docker-for-mac/docker-toolbox/). > ** ПРИМЕЧАНИЕ ** Docker Toolbox является устаревшим. вы должны использовать Docker Community Edition, см. (Docker Toolbox)[https://docs.docker.com/toolbox/overview/] После установки Docker Community Edition щелкните значок докера. Затем запустите контейнер: ``` docker run hello-world ``` Вот и все, у вас есть работающий контейнер Docker. Если вы являетесь полноправным новичком докеров, вы должны, вероятно, исследовать [серию учебников] (https://docs.docker.com/engine/getstarted/) сейчас. ## Контейнеры [Ваш основной изолированный процесс Докера](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/). Контейнеры - это виртуальные машины, поскольку потоки относятся к процессам. Или вы можете думать о них как о chroot на стероидах. ### Жизненный цикл * [`docker create`](https://docs.docker.com/engine/reference/commandline/create) создает контейнер, но не запускает его. * [`docker rename`](https://docs.docker.com/engine/reference/commandline/rename/) позволяет переименовать контейнер. * [`docker run`](https://docs.docker.com/engine/reference/commandline/run) создает и запускает контейнер за одну операцию. * [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) удаляет контейнер. * [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) обновляет ограничения ресурсов контейнера. Обычно, если вы запускаете контейнер без параметров, он запускается и останавливается немедленно, если вы хотите его запустить, вы можете использовать команду, `docker run -td container_id` это будет использовать опцию `-t` который будет выделять псевдо-TTY сессию и `-d` который автоматически отсоединяет контейнер (запускает контейнер в фоновом режиме и показыват ID контейнера). Если вам нужен переходный контейнер, `docker run --rm` удалит контейнер после его остановки. Если вы хотите сопоставить каталог на хосте с контейнером докера, `docker run -v $HOSTDIR:$DOCKERDIR`. Также смотрите [Тома](https://github.com/wsargent/docker-cheat-sheet/#volumes). Если вы хотите удалить также тома, связанные с контейнером, удаление контейнера должно включать `-v` измените примерно так `docker rm -v`. Существует также [логирование](https://docs.docker.com/engine/admin/logging/overview/) доступны для отдельных контейнеров в докерах 1.10. Чтобы запустить докер с помощью специального лог журнала (например, в syslog), используйте `docker run --log-driver=syslog`. Другим полезным вариантом является `docker run --name yourname docker_image` потому что, когда вы укажете `--name` внутри команды run это позволит вам запускать и останавливать контейнер, вызывая его с именем, которое вы указали при его создании. ### Запуск и остановка * [`docker start`](https://docs.docker.com/engine/reference/commandline/start) запускает контейнер, чтобы он работал. * [`docker stop`](https://docs.docker.com/engine/reference/commandline/stop) останавливает запущенный контейнер. * [`docker restart`](https://docs.docker.com/engine/reference/commandline/restart) останавливается и запускает контейнер. * [`docker pause`](https://docs.docker.com/engine/reference/commandline/pause/) приостанавливает работу контейнера, "замораживает" его на месте. * [`docker unpause`](https://docs.docker.com/engine/reference/commandline/unpause/) снимает "заморозку" контейнера. * [`docker wait`](https://docs.docker.com/engine/reference/commandline/wait) блокирует до остановки контейнера. * [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) посылает SIGKILL к запущеннному контейнеру. * [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) будет подключаться к работающему контейнеру. Если вы хотите интегрировать контейнер с [диспетчером хостов](https://docs.docker.com/engine/admin/host_integration/), запустите демона с помощью `-r = false`, а затем используйте` docker start -a `. Если вы хотите открыть порты контейнера через хост, см. Раздел [раскрытие портов](#открытие-портов). Перезагрузка политик в разбитых экземплярах докеров [рассматривается здесь](http://container42.com/2014/09/30/docker-restart-policies/). #### Ограничения процессора Вы можете ограничить процессор, используя либо процент от всех процессоров, либо используя определенные ядра. Например, вы можете указать параметр [`cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint). Параметр немного странный - 1024 означает 100% CPU, поэтому, если вы хотите, чтобы контейнер занимал 50% всех ядер процессора, вы должны указать 512. См. https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/#_cpu для получения дополнительной информации: ``` docker run -ti --c 512 agileek/cpuset-test ``` Вы также можете использовать только некоторые ядра процессора, используя [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint). См. https://agileek.github.io/docker/2014/08/06/docker-cpuset/ для получения дополнительной информации: ``` docker run -ti --cpuset-cpus=0,4,6 agileek/cpuset-test ``` Обратите внимание, что Docker все еще может **видеть** все процессоры внутри контейнера -- он просто не использует все из них. Подробнее см. https://github.com/docker/docker/issues/20770. #### Ограничения памяти Вы также можете установить [ограничения памяти](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) на Docker: ``` docker run -it -m 300M ubuntu:14.04 /bin/bash ``` #### Возможности Возможности Linux можно установить, используя `cap-add` и `cap-drop`. См. https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities для подробностей. Это должно использоваться для большей безопасности. Чтобы подключить файловую систему на основе FUSE, вам необходимо объединить оба --cap-add и --device: ``` docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs ``` Обеспечить доступ к одному устройству: ``` docker run -it --device=/dev/ttyUSB0 debian bash ``` Обеспечить доступ ко всем устройствам: ``` docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash ``` подробнее о привилегированных контейнерах [здесь]( https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities) ### Info * [`docker ps`](https://docs.docker.com/engine/reference/commandline/ps) показывает запущенные контейнеры. * [`docker logs`](https://docs.docker.com/engine/reference/commandline/logs) получает журналы из контейнера. (Вы можете использовать собственный драйвер журнала, но журналы доступны только для `json-file` и `journald` в 1.10). * [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) просматривает всю информацию о контейнере (включая IP-адрес). * [`docker events`](https://docs.docker.com/engine/reference/commandline/events) получает события из контейнера. * [`docker port`](https://docs.docker.com/engine/reference/commandline/port) показывает открытый порт контейнера. * [`docker top`](https://docs.docker.com/engine/reference/commandline/top) показывает запущенные процессы в контейнере. * [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats) показывает статистику использования ресурсов контейнеров. * [`docker diff`](https://docs.docker.com/engine/reference/commandline/diff) показывает измененные файлы в FS контейнера. `docker ps -a` показывает запущенные и остановленные контейнеры. `docker stats --all` показывает текущий список контейнеров. ### Импорт / Экспорт * [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp) копирует файлы или папки между контейнером и локальной файловой системой. * [`docker export`](https://docs.docker.com/engine/reference/commandline/export) экспортировать файловую систему контейнера в качестве tar-архива. ### Выполнение команд * [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) для выполнения команды в контейнере. Чтобы войти в запущенный контейнер, присоедините новый процесс оболочки к запущенному контейнеру с именем foo, используйте:`docker exec -it foo /bin/bash`. ## Образы Образы - это просто [шаблоны для docker контейнеров](https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work). ### Жизненный цикл * [`docker images`](https://docs.docker.com/engine/reference/commandline/images) показывает все образы. * [`docker import`](https://docs.docker.com/engine/reference/commandline/import) создает образ из архива. * [`docker build`](https://docs.docker.com/engine/reference/commandline/build) создает образ из Dockerfile. * [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit) создает образ из контейнера, временно приостанавливая его, если он запущен. * [`docker rmi`](https://docs.docker.com/engine/reference/commandline/rmi) удаляет образ. * [`docker load`](https://docs.docker.com/engine/reference/commandline/load) загружает образ из архива tar в качестве STDIN, включая образы и теги (начиная с 0.7). * [`docker save`](https://docs.docker.com/engine/reference/commandline/save) сохраняет образ в поток архива tar в STDOUT со всеми родительскими слоями, тегами и версиями (начиная с 0,7). ### Info * [`docker history`](https://docs.docker.com/engine/reference/commandline/history) показывает историю образа. * [`docker tag`](https://docs.docker.com/engine/reference/commandline/tag) теги образа к имени (локальному или реестру). ## Проверка версии Docker Очень важно, чтобы вы всегда знали текущую версию Docker, в которой вы сейчас работаете, в любой момент времени. Это очень полезно, потому что вы узнаете, какие функции совместимы с тем, что вы используете. Это также важно, потому что вы знаете, какие контейнеры запускать из хранилища докеров, когда вы пытаетесь получить контейнеры шаблонов. Это говорит о том, как узнать, какая версия докера у нас работает в настоящее время: * ['docker version'](https://docs.docker.com/engine/reference/commandline/version/) проверьте, какая версия докера у вас запущена. * [docker version [OPTIONS]] Получить версию сервера $ docker version --format '{{.Server.Version}}' 1.8.0 Dump raw JSON data $ docker version --format '{{json .}}' {"Client":{"Version":"1.8.0","ApiVersion":"1.20","GitCommit":"f5bae0a","GoVersion":"go1.4.2","Os":"linux","Arch":"am"} ### Cleaning up Хотя вы можете использовать команду `docker rmi` для удаления определенных образов, есть инструмент под названием [docker-gc](https://github.com/spotify/docker-gc), который будет безопасно очищать образы, которые больше не используются любыми контейнерами. ### Загрузка/Сохранение образов Загрузите образ из файла: ``` docker load < my_image.tar.gz ``` Сохранить существующий образ: ``` docker save my_image:my_tag | gzip > my_image.tar.gz ``` ### Импорт/Экспорт контейнера Импортировать контейнер как образ из файла: ``` cat my_container.tar.gz | docker import - my_image:my_tag ``` Экспортировать существующий контейнер: ``` docker export my_container | gzip > my_container.tar.gz ``` ### Разница между загрузкой сохраненного образа и импортом экспортированного контейнера в качестве образа Загрузка изображения с помощью команды `load` создает новый образ, включая его историю. Импорт контейнера в качестве образа с помощью команды `import` создает новый образ, исключая историю, которая приводит к меньшему размеру образов по сравнению с загрузкой образа. ## Сети Docker имеет функцию [network](https://docs.docker.com/engine/userguide/networking/). Об этом мало что известно, поэтому это хорошее место для расширения чит-листа. Существует примечание, в котором говорится, что это хороший способ настроить контейнеры докеров, чтобы разговаривать друг с другом без использования портов. Подробнее см. [Работа с сетями](https://docs.docker.com/engine/userguide/networking/work-with-networks/). ### Жизненный цикл * [`docker network create`](https://docs.docker.com/engine/reference/commandline/network_create/) * [`docker network rm`](https://docs.docker.com/engine/reference/commandline/network_rm/) ### Info * [`docker network ls`](https://docs.docker.com/engine/reference/commandline/network_ls/) * [`docker network inspect`](https://docs.docker.com/engine/reference/commandline/network_inspect/) ### Connection * [`docker network connect`](https://docs.docker.com/engine/reference/commandline/network_connect/) * [`docker network disconnect`](https://docs.docker.com/engine/reference/commandline/network_disconnect/) Вы можете указать [конкретный IP-адрес для контейнера](https://blog.jessfraz.com/post/ips-for-all-the-things/): ``` # создать новую сеть bridge с вашей подсетью и шлюзом для вашего ip-блока docker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic # запустите контейнер nginx с определенным ip в этом блоке $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx # curl ip из любого другого места (при условии, что это общедоступный ip-блок) $ curl 203.0.113.2 ``` ## Реестр и репозиторий Репозиторий - это * размещенная * коллекция помеченных образов, которые вместе создают файловую систему для контейнера. Реестр - это * хост * - сервер, который хранит репозитории и предоставляет HTTP API для [управления загрузкой и загрузкой репозиториев](https://docs.docker.com/engine/tutorials/dockerrepos/). Docker.com размещает свой собственный [index](https://hub.docker.com/) в центральном реестре, который содержит большое количество репозиториев. Сказав это, центральный реестр докеров (не делает хорошую работу по проверке образов)(https://titanous.com/posts/docker-insecurity), и его следует избегать, если вас беспокоит безопасность. * [`docker login`](https://docs.docker.com/engine/reference/commandline/login) для входа в реестр. * [`docker logout`](https://docs.docker.com/engine/reference/commandline/logout) для выхода из реестра. * [`docker search`](https://docs.docker.com/engine/reference/commandline/search) ищет реестр для образа. * [`docker pull`](https://docs.docker.com/engine/reference/commandline/pull) вытаскивает образ из реестра на локальный компьютер. * [`docker push`](https://docs.docker.com/engine/reference/commandline/push) толкает образ в реестр с локальной машины. ### Запуск локального реестра Вы можете запустить локальный реестр с помощью проекта [docker distribution](https://github.com/docker/distribution) и посмотреть на [локальное развертывание](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md) инструкци. Также см. [Список рассылки](https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution). ## Dockerfile [Файл конфигурации](https://docs.docker.com/engine/reference/builder/). Устанавливает контейнер Docker, когда вы запускаете на нем `docker build`. Крайне предпочтительнее `docker commit`. Вот некоторые распространенные текстовые редакторы и их модули подсветки синтаксиса, которые вы могли бы использовать для создания Dockerfiles: * Если вы используете [jEdit](http://jedit.org), я установил модуль подсветки синтаксиса для [Dockerfile](https://github.com/wsargent/jedit-docker-mode) вы можете использовать. * [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting) * [Atom](https://atom.io/packages/language-docker) * [Vim](https://github.com/ekalinin/Dockerfile.vim) * [Emacs](https://github.com/spotify/dockerfile-mode) * [TextMate](https://github.com/docker/docker/tree/master/contrib/syntax/textmate) * [VS Code](https://github.com/Microsoft/vscode-docker) * Также см. [Docker meets the IDE](https://domeide.github.io/) ### Инструкции * [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * [FROM](https://docs.docker.com/engine/reference/builder/#from) Устанавливает базовое изображение для последующих инструкций. * [MAINTAINER (устаревший - вместо этого используйте LABEL)](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) Задайте поле Author созданных образов. * [RUN](https://docs.docker.com/engine/reference/builder/#run) выполнять любые команды в новом слое поверх текущего образа и фиксировать результаты. * [CMD](https://docs.docker.com/engine/reference/builder/#cmd) предоставлять значения по умолчанию для исполняемого контейнера. * [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) сообщает Docker, что контейнер прослушивает указанные сетевые порты во время выполнения. ПРИМЕЧАНИЕ: на самом деле не делает доступными порты. * [ENV](https://docs.docker.com/engine/reference/builder/#env) устанавливает переменную среды. * [ADD](https://docs.docker.com/engine/reference/builder/#add) копирует в контейнер новые файлы, каталоги или удаленный файл. Недействительный кеш. Избегайте `ADD` и вместо этого используйте` COPY`. * [COPY](https://docs.docker.com/engine/reference/builder/#copy) копирует в контейнер новые файлы или каталоги. Обратите внимание, что это копируется только с правами root, поэтому вы должны вручную управлять вне зависимости от настроек USER / WORKDIR. См. https://github.com/moby/moby/issues/30110 * [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) настраивает контейнер, который будет запускаться как исполняемый файл. * [VOLUME](https://docs.docker.com/engine/reference/builder/#volume) создает точку монтирования для внешних томов или других контейнеров. * [USER](https://docs.docker.com/engine/reference/builder/#user) задает имя пользователя для следующих команд RUN / CMD / ENTRYPOINT. * [WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir) устанавливает рабочий каталог. * [ARG](https://docs.docker.com/engine/reference/builder/#arg) определяет переменную времени сборки. * [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) добавляет инструкцию триггера, когда изображение используется в качестве основы для другой сборки. * [STOPSIGNAL](https://docs.docker.com/engine/reference/builder/#stopsignal) устанавливает сигнал системного вызова, который будет отправлен в контейнер для выхода. * [LABEL](https://docs.docker.com/engine/userguide/labels-custom-metadata/) устанавливает сигнал системного вызова, который будет отправлен в контейнер для выхода. ### Tutorial * [Учебник Flux7's Dockerfile ](http://flux7.com/blogs/docker/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/) ### Примеры * [Примеры](https://docs.docker.com/engine/reference/builder/#dockerfile-examples) * [Рекомендации по написанию Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) * [Michael Crosby](http://crosbymichael.com/) has some more [Dockerfiles best practices](http://crosbymichael.com/dockerfile-best-practices.html) / [take 2](http://crosbymichael.com/dockerfile-best-practices-take-2.html). * [Building Good Docker Images](http://jonathan.bergknoff.com/journal/building-good-docker-images) / [Создание лучших образов docker](http://jonathan.bergknoff.com/journal/building-better-docker-images) * [Управление конфигурацией контейнера с метаданными](https://speakerdeck.com/garethr/managing-container-configuration-with-metadata) * [ Как написать отличный Dockerfiles](https://rock-it.pl/how-to-write-excellent-dockerfiles/) ## Слои Файловая система с версией в Docker основана на слоях. Они похожи на [git комиты или измекнения для файловой системы](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/). ## Связи Ссылки, как контейнеры Docker общаются друг с другом [через порты TCP/IP](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). [Связь с Redis](https://docs.docker.com/engine/examples/running_redis_service/) и [Atlassian](https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/) показать приведенные примеры. Вы также можете разрешить [ссылки по имени хоста](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file). Это в некоторой степени устарело [сетями определяемыми пользователем](https://docs.docker.com/engine/userguide/networking/#user-defined-networks). ПРИМЕЧАНИЕ. Если вы хотите, чтобы контейнеры ТОЛЬКО связывались друг с другом по ссылкам, запустите демон docker с помощью `-icc = false`, чтобы отключить межпроцессное общение. Если у вас есть контейнер с именем CONTAINER (указанный `docker run -name CONTAINER`) и в Dockerfile, он имеет открытый порт: ``` EXPOSE 1337 ``` Тогда, если мы создадим еще один контейнер LINKED, например: ``` docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress ``` Затем открытые порты и псевдонимы CONTAINER будут отображаться в LINKED со следующими переменными среды: ``` $ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR ``` И вы можете подключиться к нему таким образом. Чтобы удалить ссылки, используйте `docker rm --link`. Как правило, связи между контейнерами Docker является подмножеством «обнаружения сервисов», что является большой проблемой, если вы планируете использовать Docker в производстве. Пожалуйста, прочитайте [The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) или большей информации. ## Тома Тома Docker - [свободно плавающие файловые системы](https://docs.docker.com/engine/tutorials/dockervolumes/).Они не обязательно должны быть подключены к конкретному контейнеру. Вы должны использовать тома, примонированные из [контейнеров только для данных](https://medium.com/@ramangupta/why-docker-data-containers-are-good-589b3c6c749e) для переносимости. ### Жизненный цикл * [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) * [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) ### Info * [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) * [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) Тома полезны в ситуациях, когда вы не можете использовать ссылки (которые только TCP / IP). Например, если вам нужно, чтобы два экземпляра docker обменивались данными, оставив результат в файловой системе. Вы можете смонтировать их в нескольких контейнерах докеров сразу, используя `docker run --volumes-from`. Поскольку тома являются изолированными файловыми системами, они часто используются для хранения состояния из вычислений между переходными контейнерами. То есть, у вас может быть контейнер без учета состояния и переходный процесс, запускаемый из скрипта, сдуть его, а затем добавить второй экземпляр переходного контейнера, откуда он остановился. См. [Расширенные тома](http://crosbymichael.com/advanced-docker-volumes.html) для больших подробностей. Container42 is [also helpful](http://container42.com/2014/11/03/docker-indepth-volumes/). You can [map MacOS host directories as docker volumes](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume): ``` docker run -v /Users/wsargent/myapp/src:/src ``` You can use remote NFS volumes if you're [feeling brave](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume). You may also consider running data-only containers as described [here](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) to provide some data portability. [Вы можете [сопоставлять каталоги хостов MacOS в виде докеровских томов]](#volumes-can-be-files) ## Открытие портов Exposing incoming ports through the host container is [fiddly but doable](https://docs.docker.com/engine/reference/run/#expose-incoming-ports). This is done by mapping the container port to the host port (only using localhost interface) using `-p`: ``` docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage ``` You can tell Docker that the container listens on the specified network ports at runtime by using [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose): ``` EXPOSE ``` Note that EXPOSE does not expose the port itself -- only `-p` will do that. To expose the container's port on your localhost's port: ``` iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination : ``` If you're running Docker in Virtualbox, you then need to forward the port there as well, using [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html). Define a range of ports in your Vagrantfile like this so you can dynamically map them: ``` Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end ``` If you forget what you mapped the port to on the host container, use `docker port` to show it: ``` docker port CONTAINER $CONTAINERPORT ``` ## Лучша практика This is where general Docker best practices and war stories go: * [The Rabbit Hole of Using Docker in Automated Tests](http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/) * [Bridget Kromhout](https://twitter.com/bridgetkromhout) has a useful blog post on [running Docker in production](http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html) at Dramafever. * There's also a best practices [blog post](http://developers.lyst.com/devops/2014/12/08/docker/) from Lyst. * [Building a Development Environment With Docker](https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/) * [Discourse in a Docker Container](https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container) ## Безопасность This is where security tips about Docker go. The Docker [security](https://docs.docker.com/engine/security/security/) page goes into more detail. First things first: Docker runs as root. If you are in the `docker` group, you effectively [have root access](http://reventlov.com/advisories/using-the-docker-command-to-root-the-host). If you expose the docker unix socket to a container, you are giving the container [root access to the host](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/). Docker should not be your only defense. You should secure and harden it. For an understanding of what containers leave exposed, you should read [Understanding and Hardening Linux Containers](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf) by [Aaron Grattafiori](https://twitter.com/dyn___). This is a complete and comprehensive guide to the issues involved with containers, with a plethora of links and footnotes leading on to yet more useful content. The security tips following are useful if you've already hardened containers in the past, but are not a substitute for understanding. ### Советы по безопасности For greatest security, you want to run Docker inside a virtual machine. This is straight from the Docker Security Team Lead -- [slides](http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security) / [notes](http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/). Then, run with AppArmor / seccomp / SELinux / grsec etc to [limit the container permissions](http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/). See the [Docker 1.10 security features](https://blog.docker.com/2016/02/docker-engine-1-10-security/) for more details. Docker image ids are [sensitive information](https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4) and should not be exposed to the outside world. Treat them like passwords. See the [Docker Security Cheat Sheet](https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc) by [Thomas Sjögren](https://github.com/konstruktoid): some good stuff about container hardening in there. Check out the [docker bench security script](https://github.com/docker/docker-bench-security), download the [white papers](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/) and subscribe to the [mailing lists](https://www.docker.com/docker-security) (unfortunately Docker does not have a unique mailing list, only dev / user). You should start off by using a kernel with unstable patches for grsecurity / pax compiled in, such as [Alpine Linux](https://en.wikipedia.org/wiki/Alpine_Linux). If you are using grsecurity in production, you should spring for [commercial support](https://grsecurity.net/business_support.php) for the [stable patches](https://grsecurity.net/announce.php), same as you would do for RedHat. It's $200 a month, which is nothing to your devops budget. Since docker 1.11 you can easily limit the number of active processes running inside a container to prevent fork bombs. This requires a linux kernel >= 4.3 with CGROUP_PIDS=y to be in the kernel configuration. ``` docker run --pids-limit=64 ``` Also available since docker 1.11 is the ability to prevent processes from gaining new privileges. This feature have been in the linux kernel since version 3.5. You can read more about it in [this](http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/) blog post. ``` docker run --security-opt=no-new-privileges ``` From the [Docker Security Cheat Sheet](http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf) (it's in PDF which makes it hard to use, so copying below) by [Container Solutions](http://container-solutions.com/is-docker-safe-for-production/): Отключите межпроцессное взаимодействие с: ``` docker -d --icc=false --iptables ``` Установите контейнер только для чтения: ``` docker run --read-only ``` Проверьте образы с помощью хэш-функции: ``` docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be ``` Установить тома только для чтения: ``` docker run -v $(pwd)/secrets:/secrets:ro debian ``` Определите и запустите пользователя в вашем файле Docker, чтобы вы не запускались как root внутри контейнера: ``` RUN groupadd -r user && useradd -r -g user user USER user ``` ### User Namespaces There's also work on [user namespaces](https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/) -- it is in 1.10 but is not enabled by default. To enable user namespaces ("remap the userns") in Ubuntu 15.10, [follow the blog example](https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/). ### Security Videos * [Using Docker Safely](https://youtu.be/04LOuMgNj9U) * [Securing your applications using Docker](https://youtu.be/KmxOXmPhZbk) * [Container security: Do containers actually contain?](https://youtu.be/a9lE9Urr6AQ) * [Linux Containers: Future or Fantasy?](https://www.youtube.com/watch?v=iN6QbszB1R8) ### Security Roadmap В дорожной карте docker говорится о [поддержке seccomp]https://github.com/docker/docker/blob/master/ROADMAP.md#11-security). Существует генератор политики AppArmor, называемый [bane](https://github.com/jfrazelle/bane), и они работают над [профилями безопасности](https://github.com/docker/docker/issues/17142). ## Советы Источники: * [15 Советы docker за 5 минут](http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes) * [CodeFresh Everyday Hacks Docker](https://codefresh.io/blog/everyday-hacks-docker/) ### Prune Новые [Команды управления данными](https://github.com/docker/docker/pull/26108) Появились с Docker 1.13: * `docker system prune` * `docker volume prune` * `docker network prune` * `docker container prune` * `docker image prune` ### df `docker system df` presents a summary of the space currently used by different docker objects. ### Контейнер для докеров Heredoc ``` docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF ``` ### Последние идентификаторы ``` alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld ``` ### Commit с командой (требуется Dockerfile) ``` docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres ``` ### Получить IP-адрес ``` docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4 ``` или установите [jq](https://stedolan.github.io/jq/): ``` docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress' ``` или используя [go шаблон](https://docs.docker.com/engine/reference/commandline/inspect): ``` docker inspect -f '{{ .NetworkSettings.IPAddress }}' ``` или при создании обрзов из файла Docker, когда вы хотите передать аргумент построения: ``` 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` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/ ``` ### Получить сопоставление портов ``` docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' ``` ### Поиск контейнеров путем регулярного выражения ``` for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done ``` ### Получить настройки среды ``` docker run --rm ubuntu env ``` ### Убить запущенные контейнеры ``` docker kill $(docker ps -q) ``` ### Удалите все контейнеры (принудительные или запущенные контейнеры) ``` docker rm -f $(docker ps -qa) ``` ### Удалить старые контейнеры ``` docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm ``` ### Удалить остановленные контейнеры ``` docker rm -v $(docker ps -a -q -f status=exited) ``` ### Удаление контейнеров после остановки ``` docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq) ``` ### Удалить оборванные образы ``` docker rmi $(docker images -q -f dangling=true) ``` ### Удалить все образы ``` docker rmi $(docker images -q) ``` ### Удалить оборванные тома Начиная с Docker 1.9: ``` docker volume rm $(docker volume ls -q -f dangling=true) ``` In 1.9.0, the filter `dangling=false` does _not_ work - it is ignored and will list all volumes. В 1.9.0, фильтр `dangling=false` _не_ работает - он игнорируется и будет перечислять все тома. ### Показать зависимости образов ``` docker images -viz | dot -Tpng -o docker.png ``` ### Похудение Docker контейнеров - Очистка APT на уровне RUN Это должно быть сделано в том же слое, что и другие команды apt. В противном случае предыдущие слои по-прежнему сохраняют исходную информацию, и ваши образы будут по-прежнему жирными. ``` RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ``` - Сгладить образ ``` ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name ``` - Для резервного копирования ``` ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name ``` ### Мониторинг использования ресурсов системы для запуска контейнеров Чтобы проверить использование ЦП, памяти и сетевого ввода-вывода в одном контейнере, вы можете использовать: ``` docker stats ``` Для всех контейнеров, перечисленных в id: ``` docker stats $(docker ps -q) ``` Для всех контейнеров, перечисленных по имени: ``` docker stats $(docker ps --format '{{.Names}}') ``` Для всех контейнеров, перечисленных по образам: ``` docker ps -a -f ancestor=ubuntu ``` Удалить все непомеченные образы ``` docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}') ``` Удалить контейнер с помощью регулярного выражения ``` docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f ``` Удалить все завершенные контейнеры ``` docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }') ``` ### Томы могут быть файлами Имейте в виду, что вы можете монтировать файлы в виде томов. Например, вы можете ввести файл конфигурации следующим образом: ``` bash # копировать файл из контейнера docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # редактировать файл vim httpd.conf # запускать контейнер с измененной конфигурацией docker run --rm -ti -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd ``` ## Содействие Вот как внести свой вклад в этот чит-лист. ### Открыть README.md Click [README.md](https://github.com/wsargent/docker-cheat-sheet/blob/master/README.md) <-- this link ![Click This](../images/click.png) ### Отредактировать страницу ![Edit This](../images/edit.png) ### Внести изменения и зафиксировать ![Change This](../images/change.png) ![Commit](../images/commit.png) ================================================ FILE: zh-cn/README.md ================================================ # Docker Cheat Sheet **想要一起来完善这份速查表吗?参见[贡献手册](#贡献手册contributing)部分吧!** > 译者注:以下部分链接需科学上网后使用。 > > Due to GFW, varies links below could not be accessed in China Mainland. ## 目录 * [为何使用 Docker](#为何使用-docker) * [系统环境(Prerequisites)](#系统环境) * [安装(Installation)](#安装) * [容器(Containers)](#容器container) * [镜像(Images)](#镜像images) * [网络(Networks)](#网络networks) * [仓管中心和仓库(Registry & Repository)](#仓管中心和仓库registry--repository) * [Dockerfile](#dockerfile) * [层(Layers)](#层layers) * [链接(Links)](#链接links) * [卷标(Volumes)](#卷标volumes) * [暴露端口(Exposing Ports)](#暴露端口exposing-ports) * [最佳实践(Best Practices)](#最佳实践) * [安全(security)](#安全security) * [小贴士(Tips)](#小贴士) * [贡献手册(Contributing)](#贡献手册contributing) ## 为何使用 Docker 「通过 Docker,开发者可以使用任何语言任何工具创建任何应用。“Dockerized” 的应用是完全可移植的,能在任何地方运行 - 不管是同事的 OS X 和 Windows 笔记本,或是在云端运行的 Ubuntu QA 服务,还是在虚拟机运行的 Red Hat 产品数据中心。 Docker Hub 上有 13000+ 的应用,开发者可以从中选取一个进行快速扩展开发。Docker 跟踪管理变更和依赖关系,让系统管理员能更容易理解开发人员是如何让应用运转起来的。而开发者可以通过 Docker Hub 的共有/私有仓库,构建他们的自动化编译,与其他合作者共享成果。 Docker 帮助开发者更快地构建和发布高质量的应用。」—— [什么是 Docker](https://www.docker.com/what-docker/#copy1) ## 系统环境 我用的是 [Oh My Zsh](https://github.com/robbyrussell/oh-my-zsh) 和 [Docker 插件](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#docker),它可以自动补全 Docker 命令。你的环境可能有所不同。 ### Linux Docker 对于 Linux 内核版本的 [最低要求](https://docs.docker.com/engine/installation/binaries/#check-kernel-dependencies) 为 `3.10.x`。 ### MacOS 10.8「Mountain Lion」或更新版本。 ### 检查版本 时刻关注你当前正在使用的 Docker 版本是十分重要的,这能够帮助你了解可用的特性。同时,可以让你在查找镜像时选择使用的版本。接下来让我们看看如何操作。 * [`docker version`](https://docs.docker.com/engine/reference/commandline/version/) 查看你正在运行的 Docker 版本。 获取 Docker 服务版本: ``` $ docker version --format '{{.Server.Version}}' 1.8.0 ``` 你也可以输出原始的 JSON 数据: ``` $ docker version --format '{{json .}}' {"Client":{"Version":"1.8.0","ApiVersion":"1.20","GitCommit":"f5bae0a","GoVersion":"go1.4.2","Os":"linux","Arch":"am"} ``` ## 安装 ### Linux Docker 官方提供了快速、易用的安装脚本: ``` curl -sSL https://get.docker.com/ | sh ``` 如果你不想执行一个不明不白的 Shell 脚本,那么请看 [安装说明](https://docs.docker.com/engine/installation/linux/),选择你在用的发行版本。 如果你是一个 Docker 超新手,那么你应当先去看看 [系列教程](https://docs.docker.com/engine/getstarted/)。 ### macOS 下载并安装 [Docker Community Edition](https://www.docker.com/community-edition)。如果你在使用 Homebrew-Cask,只需在命令行输入 `brew install --cask docker` 即可。下载安装 [Docker Toolbox](https://docs.docker.com/toolbox/overview/) 亦可。[Docker For Mac](https://docs.docker.com/docker-for-mac/) 很赞,但是它的安装过程与 VirtualBox 不太一样。详情请查阅 [比较](https://docs.docker.com/docker-for-mac/docker-toolbox/)。 > **注意**:Docker Toolbox 已经过时。你应当使用 Docker Community Edition,详见 [Docker Toolbox](https://docs.docker.com/toolbox/overview/) 安装好 Docker Community Edition 后,点击 Launchpad 内的 Docker 图标。接着即可启动容器了: ``` docker run hello-world ``` 好了,现在你有了一个运行中的 Docker 容器了。 ## 容器(Container) [关于 Docker 进程隔离的基础](http://etherealmind.com/basics-docker-containers-hypervisors-coreos/)。容器 (Container) 之于虚拟机 (Virtual Machine) 就好比线程之于进程。或者你可以把他们想成是「吃了类固醇的 chroots」。 ### 生命周期 * [`docker create`](https://docs.docker.com/engine/reference/commandline/create) 创建容器但不启动它。 * [`docker rename`](https://docs.docker.com/engine/reference/commandline/rename/) 用于重命名容器。 * [`docker run`](https://docs.docker.com/engine/reference/commandline/run) 一键创建并同时启动该容器。 * [`docker rm`](https://docs.docker.com/engine/reference/commandline/rm) 删除容器。 * [`docker update`](https://docs.docker.com/engine/reference/commandline/update/) 调整容器的资源限制。 通常情况下,不使用任何命令行选项启动一个容器,该容器将会立即启动并停止。若需保持其运行,你可以使用 `docker run -td container_id` 命令。选项 `-t` 表示分配一个 pseudo-TTY 会话,`-d` 表示自动将容器与终端分离(也就是说在后台运行容器,并输出容器 ID)。 如果你需要一个临时容器,可使用 `docker run --rm` 会在容器停止之后删除它。 如果你需要映射宿主机 (host) 的目录到 Docker 容器内,可使用 `docker run -v $HOSTDIR:$DOCKERDIR`。详见 [卷标(Volumes)](#卷标volumes) 一节。 如果你想同时删除与容器相关联的卷标,那么在删除容器的时候必须包含 `-v` 选项,像这样 `docker rm -v`。 从 Docker 1.10 起,其内置一套各容器独立的 [日志引擎](https://docs.docker.com/engine/admin/logging/overview/),每个容器可以独立使用。你可以使用 `docker run --log-driver=syslog` 来自定义日志引擎(例如以上的 `syslog`)。 ### 启动和停止 * [`docker start`](https://docs.docker.com/engine/reference/commandline/start) 启动已存在的容器。 * [`docker stop`](https://docs.docker.com/engine/reference/commandline/stop) 停止运行中的容器。 * [`docker restart`](https://docs.docker.com/engine/reference/commandline/restart) 重启容器。 * [`docker pause`](https://docs.docker.com/engine/reference/commandline/pause/) 暂停运行中的容器,将其「冻结」在当前状态。 * [`docker unpause`](https://docs.docker.com/engine/reference/commandline/unpause/) 结束容器暂停状态。 * [`docker wait`](https://docs.docker.com/engine/reference/commandline/wait) 阻塞地等待某个运行中的容器直到停止。 * [`docker kill`](https://docs.docker.com/engine/reference/commandline/kill) 向运行中的容器发送 SIGKILL 指令。 * [`docker attach`](https://docs.docker.com/engine/reference/commandline/attach) 连接到运行中的容器。 如果你想将容器的端口 (ports) 暴露至宿主机,请见 [暴露端口](#暴露端口exposing-ports) 一节。 关于 Docker 实例崩溃后的重启策略,详见 [本文](http://container42.com/2014/09/30/docker-restart-policies/)。 #### CPU 限制 你可以限制 CPU 资源占用,无论是指定百分比,或是特定核心数。 例如,你可以设置 [`cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint)。该配置看起来有点奇怪 -- 1024 表示 100% CPU,因此如果你希望容器使用所有 CPU 内核的 50%,应将其设置为 512: ``` docker run -ti --c 512 agileek/cpuset-test ``` 更多信息请参阅 。 通过 [`cpuset-cpus`](https://docs.docker.com/engine/reference/run/#/cpuset-constraint) 可使用特定 CPU 内核。 ``` docker run -ti --cpuset-cpus=0,4,6 agileek/cpuset-test ``` 请参阅 获取更多细节以及一些不错的视频。 注意,Docker 在容器内仍然能够 **看到** 全部 CPU -- 它仅仅是不使用全部而已。请参阅 获取更多细节。 #### 内存限制 同样,亦可给 Docker 设置 [内存限制](https://docs.docker.com/engine/reference/run/#/user-memory-constraints): ``` docker run -it -m 300M ubuntu:14.04 /bin/bash ``` #### 能力(Capabilities) Linux 的 Capability 可以通过使用 `cap-add` 和 `cap-drop` 设置。请参阅 获取更多细节。这有助于提高安全性。 如需要挂载基于 FUSE 的文件系统,你需要结合 `--cap-add` 和 `--device` 使用: ``` docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs ``` 授予对某个设备的访问权限: ``` docker run -it --device=/dev/ttyUSB0 debian bash ``` 授予对所有设备的访问权限: ``` docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash ``` 有关容器特权的更多信息请参阅 [本文](https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities)。 ### 信息 * [`docker ps`](https://docs.docker.com/engine/reference/commandline/ps) 查看运行中的所有容器。 * [`docker logs`](https://docs.docker.com/engine/reference/commandline/logs) 从容器中读取日志。(你也可以使用自定义日志驱动,不过在 1.10 中,它只支持 `json-file` 和 `journald`)。 * [`docker inspect`](https://docs.docker.com/engine/reference/commandline/inspect) 查看某个容器的所有信息(包括 IP 地址)。 * [`docker events`](https://docs.docker.com/engine/reference/commandline/events) 从容器中获取事件 (events)。 * [`docker port`](https://docs.docker.com/engine/reference/commandline/port) 查看容器的公开端口。 * [`docker top`](https://docs.docker.com/engine/reference/commandline/top) 查看容器中活动进程。 * [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats) 查看容器的资源使用量统计信息。 * [`docker diff`](https://docs.docker.com/engine/reference/commandline/diff) 查看容器文件系统中存在改动的文件。 `docker ps -a` 将显示所有容器,包括运行中和已停止的。 `docker stats --all` 同样将显示所有容器,默认仅显示运行中的容器。 ### 导入 / 导出 * [`docker cp`](https://docs.docker.com/engine/reference/commandline/cp) 在容器和本地文件系统之间复制文件或目录。 * [`docker export`](https://docs.docker.com/engine/reference/commandline/export) 将容器的文件系统打包为归档文件流 (tarball archive stream) 并输出至标准输出 (STDOUT)。 ### 执行命令 * [`docker exec`](https://docs.docker.com/engine/reference/commandline/exec) 在容器内执行命令。 例如,进入正在运行的 `foo` 容器,并连接 (attach) 到一个新的 Shell 进程:`docker exec -it foo /bin/bash`。 ## 镜像(Images) 镜像是 [Docker 容器的模板](https://docs.docker.com/engine/understanding-docker/#how-does-a-docker-image-work)。 ### 生命周期 * [`docker images`](https://docs.docker.com/engine/reference/commandline/images) 查看所有镜像。 * [`docker import`](https://docs.docker.com/engine/reference/commandline/import) 从归档文件创建镜像。 * [`docker build`](https://docs.docker.com/engine/reference/commandline/build) 从 Dockerfile 创建镜像。 * [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit) 为容器创建镜像,如果容器正在运行则会临时暂停。 * [`docker rmi`](https://docs.docker.com/engine/reference/commandline/rmi) 删除镜像。 * [`docker load`](https://docs.docker.com/engine/reference/commandline/load) 从标准输入 (STDIN) 加载归档包 (tar archive) 作为镜像,包括镜像本身和标签 (tags, 0.7 起)。 * [`docker save`](https://docs.docker.com/engine/reference/commandline/save) 将镜像打包为归档包,并输出至标准输出 (STDOUT),包括所有的父层、标签和版本 (parent layers, tags, versions, 0.7 起)。 ### 其它信息 * [`docker history`](https://docs.docker.com/engine/reference/commandline/history) 查看镜像的历史记录。 * [`docker tag`](https://docs.docker.com/engine/reference/commandline/tag) 给镜像打标签命名(本地或者仓库均可)。 ### 清理 虽然你可以用 `docker rmi` 命令来删除指定的镜像,不过有个名为 [docker-gc](https://github.com/spotify/docker-gc) 的工具,它可以以一种安全的方式,清理掉那些不再被任何容器使用的镜像。Docker 1.13 起,使用 `docker image prune` 亦可删除未使用的镜像。参见 [清理](#清理)。 ### 加载 / 保存镜像 从文件中加载镜像: ``` docker load < my_image.tar.gz ``` 保存既有镜像: ``` docker save my_image:my_tag | gzip > my_image.tar.gz ``` ### 导入 / 导出容器 从文件中导入容器镜像: ``` cat my_container.tar.gz | docker import - my_image:my_tag ``` 导出既有容器: ``` docker export my_container | gzip > my_container.tar.gz ``` ### 加载已保存的镜像 与 导入已导出为镜像的容器 的不同 通过 `load` 命令来加载镜像,会创建一个新的镜像,并继承原镜像的所有历史。 通过 `import` 将容器作为镜像导入,也会创建一个新的镜像,但并不包含原镜像的历史,因此会比使用 `load` 方式生成的镜像更小。 ## 网络(Networks) Docker 具备 [网络](https://docs.docker.com/engine/userguide/networking/) 功能。我并不是很了解它,所以这是一个扩展本文的好地方。文档 [使用网络](https://docs.docker.com/engine/userguide/networking/work-with-networks/) 指出,这是一种无需暴露端口即可实现 Docker 容器间通信的好方法。 ### 生命周期 * [`docker network create`](https://docs.docker.com/engine/reference/commandline/network_create/) * [`docker network rm`](https://docs.docker.com/engine/reference/commandline/network_rm/) ### 其它信息 * [`docker network ls`](https://docs.docker.com/engine/reference/commandline/network_ls/) * [`docker network inspect`](https://docs.docker.com/engine/reference/commandline/network_inspect/) ### 建立连接 * [`docker network connect`](https://docs.docker.com/engine/reference/commandline/network_connect/) * [`docker network disconnect`](https://docs.docker.com/engine/reference/commandline/network_disconnect/) 你可以 [为容器指定 IP 地址](https://blog.jessfraz.com/post/ips-for-all-the-things/): ``` # 使用你自己的子网和网关创建一个桥接网络 docker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic # 基于以上创建的网络,运行一个 Nginx 容器并指定 IP $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx # 在其他地方使用 CURL 访问这个 IP(假设该 IP 为公网) $ curl 203.0.113.2 ``` ## 仓管中心和仓库(Registry & Repository) 仓库 (repository) 是 *被托管(hosted)* 的已命名镜像 (tagged images) 的集合,这组镜像用于构建容器文件系统。 仓管中心 (registry) 则是 *托管服务(host)* -- 用于存储仓库并提供 HTTP API,以便 [管理仓库的上传和下载](https://docs.docker.com/engine/tutorials/dockerrepos/)。 Docker 官方托管着自己的 [仓管中心](https://hub.docker.com/),包含着数量众多的仓库。不过话虽如此,这个仓管中心 [并没有很好地验证镜像](https://titanous.com/posts/docker-insecurity),所以如果你担心安全问题的话,请尽量避免使用它。 * [`docker login`](https://docs.docker.com/engine/reference/commandline/login) 登入仓管中心。 * [`docker logout`](https://docs.docker.com/engine/reference/commandline/logout) 登出仓管中心。 * [`docker search`](https://docs.docker.com/engine/reference/commandline/search) 从仓管中心检索镜像。 * [`docker pull`](https://docs.docker.com/engine/reference/commandline/pull) 从仓管中心拉取镜像到本地。 * [`docker push`](https://docs.docker.com/engine/reference/commandline/push) 从本地推送镜像到仓管中心。 ### 本地仓管中心 你可以使用 [docker distribution](https://github.com/docker/distribution) 项目搭建本地的仓管中心,详情参阅 [本地发布 (local deploy)](https://github.com/docker/docker.github.io/blob/master/registry/deploying.md) 的介绍。 科学上网后,也可以看看 [Google+ Group](https://groups.google.com/a/dockerproject.org/forum/#!forum/distribution)。 ## Dockerfile 当你执行 `docker build` 时,Docker 将会根据 [配置文件](https://docs.docker.com/engine/reference/builder/) 启动 Docker 容器。远优于使用 `docker commit`。 以下是一些编写 Dockerfile 的常用编辑器,并链接到适配的语法高亮模块︰ * 如果你在使用 [jEdit](http://jedit.org),你可以使用我开发的 Dockerfile [语法高亮模块](https://github.com/wsargent/jedit-docker-mode)。 * [Sublime Text 2](https://packagecontrol.io/packages/Dockerfile%20Syntax%20Highlighting) * [Atom](https://atom.io/packages/language-docker) * [Vim](https://github.com/ekalinin/Dockerfile.vim) * [Emacs](https://github.com/spotify/dockerfile-mode) * [TextMate](https://github.com/docker/docker/tree/master/contrib/syntax/textmate) * 更多信息请参阅 [Docker 遇上 IDE](https://domeide.github.io/) ### 指令 * [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) * [FROM](https://docs.docker.com/engine/reference/builder/#from) 为其他指令设置基础镜像 (Base Image)。 * [MAINTAINER (deprecated - use LABEL instead)](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) 为生成的镜像设置作者字段。 * [RUN](https://docs.docker.com/engine/reference/builder/#run) 在当前镜像的基础上生成一个新层并执行命令。 * [CMD](https://docs.docker.com/engine/reference/builder/#cmd) 设置容器默认执行命令。 * [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker 容器在运行时所要监听的网络端口。注意:并没有实际上将端口设置为可访问。 * [ENV](https://docs.docker.com/engine/reference/builder/#env) 设置环境变量。 * [ADD](https://docs.docker.com/engine/reference/builder/#add) 将文件、目录或远程文件复制到容器中。缓存无效。请尽量用 `COPY` 代替 `ADD`。 * [COPY](https://docs.docker.com/engine/reference/builder/#copy) 将文件或文件夹复制到容器中。注意:将使用 ROOT 用户复制文件,故无论 USER / WORKDIR 指令如何配置,你都需要手动修改其所有者(`chown`),`ADD` 也是一样。 * [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) 将容器设为可执行的。 * [VOLUME](https://docs.docker.com/engine/reference/builder/#volume) 在容器内部创建挂载点 (mount point) 指向外部挂载的卷标或其他容器。 * [USER](https://docs.docker.com/engine/reference/builder/#user) 设置随后执行 RUN / CMD / ENTRYPOINT 命令的用户名。 * [WORKDIR](https://docs.docker.com/engine/reference/builder/#workdir) 设置工作目录 (working directory)。 * [ARG](https://docs.docker.com/engine/reference/builder/#arg) 定义编译时 (build-time) 变量。 * [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) 添加触发指令,当该镜像被作为其他镜像的基础镜像时该指令会被触发。 * [STOPSIGNAL](https://docs.docker.com/engine/reference/builder/#stopsignal) 设置停止容器时,向容器内发送的系统调用信号 (system call signal)。 * [LABEL](https://docs.docker.com/config/labels-custom-metadata/) 将键值对元数据 (key/value metadata) 应用到镜像、容器或是守护进程。 ### 教程 * [Flux7's Dockerfile Tutorial](http://flux7.com/blogs/docker/docker-tutorial-series-part-3-automation-is-the-word-using-dockerfile/) ### 例子 * [Examples](https://docs.docker.com/engine/reference/builder/#dockerfile-examples) * [Best practices for writing Dockerfiles](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/) * [Michael Crosby](http://crosbymichael.com/) 还有更多的 [Dockerfiles best practices](http://crosbymichael.com/dockerfile-best-practices.html) / [take 2](http://crosbymichael.com/dockerfile-best-practices-take-2.html) * [Building Good Docker Images](http://jonathan.bergknoff.com/journal/building-good-docker-images) / [Building Better Docker Images](http://jonathan.bergknoff.com/journal/building-better-docker-images) * [Managing Container Configuration with Metadata](https://speakerdeck.com/garethr/managing-container-configuration-with-metadata) ## 层(Layers) Docker 的版本化文件系统是基于层的。就像 [Git 的提交或文件变更系统](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/) 一样。 ## 链接(Links) 链接 (links) [通过 TCP/IP 端口](https://docs.docker.com/userguide/dockerlinks/) 实现 Docker 容器之间的通讯。[Atlassian](https://blogs.atlassian.com/2013/11/docker-all-the-things-at-atlassian-automation-and-wiring/) 展示了可用的例子。你还可以 [通过主机名 (hostname) 链接](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/#/updating-the-etchosts-file)。 在某种意义上来说,该特性已经被 [自定义网络](https://docs.docker.com/network/) 所替代。 注意: 如果你希望容器之间**只**通过链接进行通讯,在启动 Docker 守护进程时,请使用 `-icc=false` 来禁用内部进程通讯。 假设你有一个名为 CONTAINER 的容器(通过 `docker run --name CONTAINER` 指定)并且在 Dockerfile 中,暴露了一个端口: ``` EXPOSE 1337 ``` 然后,我们创建另外一个名为 LINKED 的容器: ``` docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress ``` 然后 CONTAINER 暴露的端口和别名将会以如下的环境变量出现在 LINKED 中: ``` $ALIAS_PORT_1337_TCP_PORT $ALIAS_PORT_1337_TCP_ADDR ``` 那么你便可以通过这种方式来连接它了。 使用 `docker rm --link` 即可删除链接。 通常,Docker 容器(亦可理解为「服务」)之间的链接,是「服务发现」的一个子集。如果你打算在生产中大规模使用 Docker,这将是一个很大的问题。请参阅[The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) 获取更多信息。 ## 卷标(Volumes) Docker 的卷标 (volumes) 是 [独立的文件系统](https://docs.docker.com/engine/tutorials/dockervolumes/)。它们并非必须连接到特定的容器上。 ### 生命周期 * [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) * [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) ### 信息 * [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) * [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) 卷标在不能使用链接(只有 TCP/IP)的情况下非常有用。例如,如果你有两个 Docker 实例需要通讯并在文件系统上留下记录。 你可以一次性将其挂载到多个 docker 容器上,通过 `docker run --volumes-from`。 因为卷标是独立的文件系统,它们通常被用于存储各容器之间的瞬时状态。也就是说,你可以配置一个无状态临时容器,关掉之后,当你有第二个这种临时容器实例的时候,你可以从上一次保存的状态继续执行。 查看 [卷标进阶](http://crosbymichael.com/advanced-docker-volumes.html) 来获取更多细节。[Container42](http://container42.com/2014/11/03/docker-indepth-volumes/) 非常有用。 你可以 [将宿主 MacOS 的文件夹映射为 Docker 卷标](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume): ``` docker run -v /Users/wsargent/myapp/src:/src ``` 你也可以用远程 NFS 卷标,如果你觉得你 [有足够勇气](https://docs.docker.com/engine/tutorials/dockervolumes/#/mount-a-shared-storage-volume-as-a-data-volume)。 还可以考虑运行一个纯数据容器,像 [这里](http://container42.com/2013/12/16/persistent-volumes-with-docker-container-as-volume-pattern/) 所说的那样,提供可移植数据。 记得,[文件也可以被挂载为卷标](#将文件挂载为卷标)。 ## 暴露端口(Exposing ports) 通过宿主容器暴露输入端口相当 [繁琐但有效的](https://docs.docker.com/engine/reference/run/#expose-incoming-ports)。 例如使用 `-p` 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口): ``` docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage ``` 你可以使用 [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker,该容器在运行时监听指定的端口: ``` EXPOSE ``` 但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 `-p` 。比如说你要在 localhost 上暴露容器的端口: ``` iptables -t nat -A DOCKER -p tcp --dport -j DNAT --to-destination : ``` 如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html) 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了: ``` Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| ... (49000..49900).each do |port| config.vm.network :forwarded_port, :host => port, :guest => port end ... end ``` 如果你忘记了将什么端口映射到宿主机上的话,可使用 `docker port` 查看: ``` docker port CONTAINER $CONTAINERPORT ``` ## 最佳实践 这里有一些最佳实践,以及争论焦点: * [The Rabbit Hole of Using Docker in Automated Tests](http://gregoryszorc.com/blog/2014/10/16/the-rabbit-hole-of-using-docker-in-automated-tests/) * [Bridget Kromhout](https://twitter.com/bridgetkromhout) has a useful blog post on [running Docker in production](http://sysadvent.blogspot.co.uk/2014/12/day-1-docker-in-production-reality-not.html) at Dramafever. * There's also a best practices [blog post](http://developers.lyst.com/devops/2014/12/08/docker/) from Lyst. * [A Docker Dev Environment in 24 Hours!](https://engineering.salesforceiq.com/2013/11/05/a-docker-dev-environment-in-24-hours-part-2-of-2.html) * [Building a Development Environment With Docker](https://tersesystems.com/2013/11/20/building-a-development-environment-with-docker/) * [Discourse in a Docker Container](https://samsaffron.com/archive/2013/11/07/discourse-in-a-docker-container) ## 安全(Security) 这节准备讨论一些关于 Docker 安全性的问题。Docker 官方文档 [安全](https://docs.docker.com/articles/security/) 页面讲述了更多细节。 首先第一件事:Docker 是有 root 权限的。如果你在 `docker` 组,那么你就有 [root 权限](https://web.archive.org/web/20161226211755/http://reventlov.com/advisories/using-the-docker-command-to-root-the-host)。如果你将 Docker 的 Unix Socket 暴露给容器,意味着你赋予了容器 [宿主机 root 权限](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container/)。 Docker 不应当作为唯一的防御措施。你应当使其更加安全可靠。 为了更好地理解容器暴露了什么,可参阅由 [Aaron Grattafiori](https://twitter.com/dyn___) 编写的 [Understanding and Hardening Linux Containers](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2016/april/ncc_group_understanding_hardening_linux_containers-1-1.pdf)。这是一个完整全面且包含大量链接和脚注的容器问题指南,介绍了许多有用的内容。即使你已经加固过容器,以下的安全提示依然十分有帮助,但并不能代替理解的过程。 ### 安全提示 为了最大的安全性,你应当考虑在虚拟机上运行 Docker。这是直接从 Docker 安全团队拿来的资料 -- [slides](http://www.slideshare.net/jpetazzo/linux-containers-lxc-docker-and-security) / [notes](http://www.projectatomic.io/blog/2014/08/is-it-safe-a-look-at-docker-and-security-from-linuxcon/)。之后,可使用 AppArmor、seccomp、SELinux、grsec 等来 [限制容器的权限](http://linux-audit.com/docker-security-best-practices-for-your-vessel-and-containers/)。更多细节,请查阅 [Docker 1.10 security features](https://blog.docker.com/2016/02/docker-engine-1-10-security/)。 Docker 镜像 ID 属于 [敏感信息](https://medium.com/@quayio/your-docker-image-ids-are-secrets-and-its-time-you-treated-them-that-way-f55e9f14c1a4) 所以它不应该向外界公开。请将它们当作密码来对待。 阅读由 [Thomas Sjögren](https://github.com/konstruktoid) 编写的 [Docker Security Cheat Sheet](https://github.com/konstruktoid/Docker/blob/master/Security/CheatSheet.adoc):关于加固容器的不错的建议。 查看 [Docker 安全测试脚本](https://github.com/docker/docker-bench-security),下载 [最佳实践白皮书](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/)。 你应当远离使用非稳定版本 grsecurity / pax 的内核,比如 [Alpine Linux](https://en.wikipedia.org/wiki/Alpine_Linux)。如果在产品中用了 grsecurity,那么你应该考虑使用有 [商业支持](https://grsecurity.net/business_support.php) 的 [稳定版本](https://grsecurity.net/announce.php),就像你对待 RedHat 那样。虽然要 $200 每月,但对于你的运维预算来说不值一提。 从 Docker 1.11 开始,你可以轻松的限制在容器中可用的进程数,以防止 fork 炸弹。 这要求 Linux 内核 >= 4.3,并且要在内核配置中打开 CGROUP_PIDS=y。 ``` docker run --pids-limit=64 ``` 同时,你也可以限制进程再获取新权限。该功能是 Linux 内核从 3.5 版本开始就拥有的。你可以从 [这篇博客](http://www.projectatomic.io/blog/2016/03/no-new-privs-docker/) 中阅读到更多关于这方面的内容。 ``` docker run --security-opt=no-new-privileges ``` 以下内容摘选自 [Container Solutions](http://container-solutions.com/is-docker-safe-for-production/) 的 [Docker Security Cheat Sheet](http://container-solutions.com/content/uploads/2015/06/15.06.15_DockerCheatSheet_A2.pdf)(PDF 版本,难以使用,故复制至此): 关闭内部进程通讯: ``` docker -d --icc=false --iptables ``` 设置容器为只读: ``` docker run --read-only ``` 通过 hashsum 来验证卷标: ``` docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be ``` 设置卷标为只读: ``` docker run -v $(pwd)/secrets:/secrets:ro debian ``` 在 Dockerfile 中定义用户并以该用户运行,避免在容器中以 ROOT 身份操作: ``` RUN groupadd -r user && useradd -r -g user user USER user ``` ### 用户命名空间(User Namespaces) 还可以通过使用 [用户命名空间](https://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/) -- 自 1.10 版本起已内置,但默认并未启用。 要在 Ubuntu 15.10 中启用用户命名空间 (remap the userns),请 [跟着这篇博客的例子](https://raesene.github.io/blog/2016/02/04/Docker-User-Namespaces/) 来做。 ### 安全相关视频 * [Using Docker Safely](https://youtu.be/04LOuMgNj9U) * [Securing your applications using Docker](https://youtu.be/KmxOXmPhZbk) * [Container security: Do containers actually contain?](https://youtu.be/a9lE9Urr6AQ) * [Linux Containers: Future or Fantasy?](https://www.youtube.com/watch?v=iN6QbszB1R8) ### 安全路线图 Docker 的路线图提到关于 [seccomp 的支持](https://github.com/docker/docker/blob/master/ROADMAP.md#11-security)。 一个名为 [bane](https://github.com/jfrazelle/bane) 的 AppArmor 策略生成器正在实现 [安全配置文件](https://github.com/docker/docker/issues/17142)。 ## 小贴士 链接: * [15 Docker Tips in 5 minutes](http://sssslide.com/speakerdeck.com/bmorearty/15-docker-tips-in-5-minutes) * [CodeFresh Everyday Hacks Docker](https://codefresh.io/blog/everyday-hacks-docker/) ### 清理 最新的 [数据管理命令](https://github.com/docker/docker/pull/26108) 已在 Docker 1.13 实现: * `docker system prune` * `docker volume prune` * `docker network prune` * `docker container prune` * `docker image prune` ### df 命令 `docker system df` 将显示当前 Docker 各部分占用的磁盘空间。 ### Heredoc 声明 Docker 容器 ``` docker build -t htop - << EOF FROM alpine RUN apk --no-cache add htop EOF ``` ### 最近一次的容器 ID ``` alias dl='docker ps -l -q' docker run ubuntu echo hello world docker commit $(dl) helloworld ``` ### 带命令的提交(需要 Dockerfile) ``` docker commit -run='{"Cmd":["postgres", "-too -many -opts"]}' $(dl) postgres ``` ### 获取 IP 地址 ``` docker inspect $(dl) | grep -wm1 IPAddress | cut -d '"' -f 4 ``` 或使用 [jq](https://stedolan.github.io/jq/): ``` docker inspect $(dl) | jq -r '.[0].NetworkSettings.IPAddress' ``` 或使用 [go 模板](https://docs.docker.com/engine/reference/commandline/inspect): ``` docker inspect -f '{{ .NetworkSettings.IPAddress }}' ``` 或在通过 Dockerfile 构建镜像时,通过构建参数 (build argument) 传入: ``` 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` echo DOCKER_HOST_IP = $DOCKER_HOST_IP docker build \ --build-arg ARTIFACTORY_ADDRESS=$DOCKER_HOST_IP -t sometag \ some-directory/ ``` ### 获取端口映射 ``` docker inspect -f '{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' ``` ### 通过正则匹配容器 ``` for i in $(docker ps -a | grep "REGEXP_PATTERN" | cut -f1 -d" "); do echo $i; done` ``` ### 获取环境变量配置 ``` docker run --rm ubuntu env ``` ### 强行终止运行中的容器 ``` docker kill $(docker ps -q) ``` ### 删除所有容器(强行删除!无论容器运行或停止) ``` docker rm -f $(docker ps -qa) ``` ### 删除旧容器 ``` docker ps -a | grep 'weeks ago' | awk '{print $1}' | xargs docker rm ``` ### 删除已停止的容器 ``` docker rm -v `docker ps -a -q -f status=exited` ``` ### 停止并删除容器 ``` docker stop $(docker ps -aq) && docker rm -v $(docker ps -aq) ``` ### 删除无用 (dangling) 的镜像 ``` docker rmi $(docker images -q -f dangling=true) ``` ### 删除所有镜像 ``` docker rmi $(docker images -q) ``` ### 删除无用 (dangling) 的卷标 Docker 1.9 版本起: ``` docker volume rm $(docker volume ls -q -f dangling=true) ``` 1.9.0 中,参数 `dangling=false` 居然 _没_ 用 - 它会被忽略然后列出所有的卷标。 ### 查看镜像依赖 ``` docker images -viz | dot -Tpng -o docker.png ``` ### Docker 容器瘦身 - 在某层 (RUN layer) 清理 APT 这应当和其他 apt 命令在同一层中完成。 否则,前面的层将会保持原有信息,而你的镜像则依旧臃肿。 ``` RUN {apt commands} \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ``` - 压缩镜像 ``` ID=$(docker run -d image-name /bin/bash) docker export $ID | docker import – flat-image-name ``` - 备份 ``` ID=$(docker run -d image-name /bin/bash) (docker export $ID | gzip -c > image.tgz) gzip -dc image.tgz | docker import - flat-image-name ``` ### 监视运行中容器的系统资源利用率 检查某个容器的 CPU、内存以及网络 I/O 使用情况,你可以: ``` docker stats ``` 按 ID 列出所有容器: ``` docker stats $(docker ps -q) ``` 按名称列出所有容器: ``` docker stats $(docker ps --format '{{.Names}}') ``` 按指定镜像名称列出所有容器: ``` docker ps -a -f ancestor=ubuntu ``` 删除所有未标签命名 (untagged) 的容器: ``` docker rmi $(docker images | grep “^” | awk '{split($0,a," "); print a[3]}') ``` 通过正则匹配删除指定容器: ``` docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f ``` 删除所有已退出 (exited) 的容器: ``` docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }') ``` ### 将文件挂载为卷标 文件也可以被挂载为卷标。例如你可以仅仅注入单个配置文件: ``` bash # 从容器复制文件 docker run --rm httpd cat /usr/local/apache2/conf/httpd.conf > httpd.conf # 编辑文件 vim httpd.conf # 挂载修改后的配置启动容器 docker run --rm -ti -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro" -p "80:80" httpd ``` ## 贡献手册(Contributing) 以下是如何贡献本速查表的说明。 ### 打开 README.md 点击 [README.md](https://github.com/wsargent/docker-cheat-sheet/blob/master/README.md) <-- 这个链接 ![点击](../images/click.png) ### 编辑页面 ![编辑](../images/edit.png) ### 更新并提交 ![修改](../images/change.png) ![提交](../images/commit.png)