您现在的位置是: 网站首页 >服务部署 服务部署
【docker】Docker核心技术快速入门及私有仓库搭建
admin2020年3月12日 23:07 【Docker | Linux 】 1657人已围观
# 什么是Docker? [官方文档翻译](https://yeasy.gitbooks.io/docker_practice/content/introduction/) Docker 是基于Go语言实现的开源容器项目。利用操作系统本身已有的机制和特性,可以实现远超传统虚拟机的轻量级虚拟化。它是内核级的虚拟化。期望达到使项目运行环境“一次封装,到处运行的目的”。 Docker作为一个软件集装箱化平台,可以让开发者构建应用程序时,将它与其**依赖环境一起打包到一个容器**中,然后很容易地发布和应用到任意平台中。 利用docker创建的运行环境叫做docker容器,容器是通过docker镜像创建的,docker镜像文件可以放在私有仓库中也可以放在共有仓库中。最大的公有仓库是官方Docker Hub。 ## 思想 - 集装箱 - 标准化 - 隔离 ## 核心 docker有3大核心:镜像、容器、仓库。 ## 为什么要使用 Docker? 作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。 ### 更高效的利用系统资源 由于容器**不需要进行硬件虚拟以及运行完整操作系统**等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 ### 更快速的启动时间 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,**无需启动完整的操作系统**,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 ### 一致的运行环境 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了**应用运行环境一致性**,从而不会再出现 *「这段代码在我机器上没问题啊」* 这类问题。 ### 持续交付和部署 对开发和运维(DevOps)人员来说,最希望的就是**一次创建或配置,可以在任意地方正常运行**。 使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。 而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。 ### 更轻松的迁移 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以**在很多平台上运行**,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。 ### 更轻松的维护和扩展 Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 ### 对比传统虚拟机总结 | 特性 | 容器 | 虚拟机 | | --------- | ---------------- | ---------- | | 启动 | 秒级 | 分钟级 | | 硬盘使用 | 一般为 `MB` | 一般为 `GB` | | 性能 | 接近原生 | 弱于 | | 系统支持量 | 单机支持上千个容器 | 一般几十个 | ## 架构 ![BLOG_20200312_230810_39](/media/blog/images/2020/03/BLOG_20200312_230810_39.png "博客图集BLOG_20200312_230810_39.png") ## 基本概念 ### 镜像 轻量级、可执行的独立软件包,**用来打包软件运行环境和基于运行环境开发的软件**。包含运行某个软件所需的所有内容,包含代码、运行时、库、环境变量和配置文件。 操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。 Docker 镜像是一个特殊的文件系统,除了**提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数**(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。 **分层存储** 因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。 镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。 分层存储的特征还使得**镜像的复用**、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。 **镜像特点** Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,容器层之下的都叫镜像层。镜像分层叠加,构成Docker镜像。 ### 容器 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。**容器可以被创建、启动、停止、删除、暂停等**。 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。 前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。 容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。 按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。 数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。 可以把容器看成一个**简易版的Linux环境**(包括root用户权限、进程空间、用户空间和网络空间等)和**运行在其中的应用程序**。 容器的定义和镜像几乎一样,也是一堆层的统一视角,唯一的区别在于容器的最上层是可读可写的。 ### 仓库 镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。 一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。 仓库名经常以 两段式路径 形式出现,比如 `jwilder/nginx-proxy`,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。 **Docker Registry 公开服务** Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。 最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。除此以外,还有 CoreOS 的 Quay.io,CoreOS 相关的镜像存储在这里;Google 的 Google Container Registry,Kubernetes 的镜像使用的就是这个服务。 由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为加速器。常见的有 阿里云加速器、DaoCloud 加速器 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。在 安装 Docker 一节中有详细的配置方法。 国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 **网易云镜像服务**、DaoCloud 镜像市场、**阿里云镜像库** 等。 **私有 Docker Registry** 除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。在 私有仓库 一节中,会有进一步的搭建私有 Registry 服务的讲解。 开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 Docker Trusted Registry 中,提供了这些高级功能。 除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,**Harbor** 和 Sonatype Nexus。 # 配置Docker环境 ## 安装Docker 安装环境为CentOS7 可以在 https://docs.docker.com/install/linux/docker-ce/centos/ 找到安装文档 ```bash # 安装依赖 [root@localhost ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 [root@localhost ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 如果官方源安装下载慢就换 [root@localhost ~]# yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo [root@localhost ~]# yum install docker-ce docker-ce-cli containerd.io -y [root@localhost ~]# systemctl enable docker [root@localhost ~]# systemctl start docker ``` docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。 ```bash [root@localhost ~]# groupadd docker groupadd:“docker”组已存在 [root@localhost ~]# usermod -aG docker $USER ``` 安装完成 ```bash [root@localhost ~]# docker info Client: Debug Mode: false Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 19.03.7 Storage Driver: overlay2 Backing Filesystem: <unknown> Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-1062.4.1.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 972.4MiB Name: localhost.localdomain ID: KVPR:Z3C3:36GW:UBAP:QJ4R:D2OS:AGPZ:IB7X:O4VK:TQNZ:BODA:HFO3 Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false ``` ## 镜像加速 内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,例如: - [Azure 中国镜像 `https://dockerhub.azk8s.cn`](https://github.com/Azure/container-service-for-azure-china/blob/master/aks/README.md#22-container-registry-proxy) - [阿里云加速器(需登录账号获取)](https://cr.console.aliyun.com/cn-hangzhou/mirrors) - [网易云加速器 `https://hub-mirror.c.163.com`](https://www.163yun.com/help/documents/56918246390157312) 对于CentOS7系统 ```bash [root@localhost ~]# vim /etc/docker/daemon.json # 添加以下内容 { "registry-mirrors": [ "https://dockerhub.azk8s.cn", "https://hub-mirror.c.163.com" ] } ``` 然后重启Docker ```bash [root@localhost ~]# systemctl restart docker [root@localhost ~]# docker info Client: Debug Mode: false Server: Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 19.03.7 Storage Driver: overlay2 Backing Filesystem: <unknown> Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-1062.4.1.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 972.4MiB Name: localhost.localdomain ID: KVPR:Z3C3:36GW:UBAP:QJ4R:D2OS:AGPZ:IB7X:O4VK:TQNZ:BODA:HFO3 Docker Root Dir: /var/lib/docker Debug Mode: false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: https://dockerhub.azk8s.cn/ https://hub-mirror.c.163.com/ Live Restore Enabled: false ``` 可以看到`Registry Mirrors`已经替换成了自定义的链接。 ## 测试镜像使用 ```bash root@localhost ~]# docker run hello-world # run的时候现在本地找是否有这个镜像 Unable to find image 'hello-world:latest' locally # 如果没有就去Docker hub中下载 latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:fc6a51919cfeb2e6763f62b6d9e8815acbf7cd2e476ea353743570610737b752 Status: Downloaded newer image for hello-world:latest # 下载完成后再运行 Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/ ``` # Docker常用命令 ## 帮助命令 ### docker version ```bash [root@localhost ~]# docker version Client: Docker Engine - Community Version: 19.03.7 API version: 1.40 Go version: go1.12.17 Git commit: 7141c199a2 Built: Wed Mar 4 01:24:10 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.7 API version: 1.40 (minimum version 1.12) Go version: go1.12.17 Git commit: 7141c199a2 Built: Wed Mar 4 01:22:45 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683 ``` ### docker info ### docker --help 可以查看docker命令的参数。 ```bash [root@localhost ~]# docker --help Usage: docker [OPTIONS] COMMAND A self-sufficient runtime for containers Options: --config string Location of client config files (default "/root/.docker") -c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use") -D, --debug Enable debug mode -H, --host list Daemon socket(s) to connect to -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info") --tls Use TLS; implied by --tlsverify --tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem") --tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem") --tlskey string Path to TLS key file (default "/root/.docker/key.pem") --tlsverify Use TLS and verify the remote -v, --version Print version information and quit Management Commands: builder Manage builds config Manage Docker configs container Manage containers context Manage contexts engine Manage the docker engine image Manage images network Manage networks node Manage Swarm nodes plugin Manage plugins secret Manage Docker secrets service Manage services stack Manage Docker stacks swarm Manage Swarm system Manage Docker trust Manage trust on Docker images volume Manage volumes Commands: attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container`s changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container`s filesystem events Get real time events from the server exec Run a command in a running container export Export a container`s filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes Run 'docker COMMAND --help' for more information on a command. ``` ## 镜像命令 ### 列出:docker images 列出本地主机的镜像 ```bash [root@localhost ~]# docker images #镜像的仓库源 镜像标签 镜像ID 创建时间 镜像大小 REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB ``` 同一仓库源可以有多个TAG,代表这个仓库源的不同个版本,可以使用 REPOSITORY:TAG 来定义不同的镜像。 如果不指定镜像的标签版本,则默认使用`hello-world:latest`镜像 命令帮助 ```bash [root@localhost ~]# docker images --help Usage: docker images [OPTIONS] [REPOSITORY[:TAG]] List images Options: -a, --all Show all images (default hides intermediate images) # 显示所有镜像,不要-a默认隐藏中间镜像层,因为镜像是分层的 --digests Show digests # 显示摘要 -f, --filter filter Filter output based on conditions provided --format string Pretty-print images using a Go template --no-trunc Don`t truncate output # 显示完整的镜像信息,ID会很长 -q, --quiet Only show numeric IDs # 只显示镜像的ID # 可以多个选项公用,例如docker images -qa,显示所有镜像的ID ``` ### 搜索:docker search 镜像名 ```bash [root@localhost ~]# docker search nginx #名称 描述 在hub上的star数 官方版 自动构建的 NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 12758 [OK] jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1749 [OK] richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 758 [OK] ``` 命令帮助 ```bash [root@localhost ~]# docker search --help Usage: docker search [OPTIONS] TERM Search the Docker Hub for images Options: -f, --filter filter Filter output based on conditions provided # 根据提供的条件过滤输出 --format string Pretty-print search using a Go template # 搜索时使用Go模板进行漂亮的打印 --limit int Max number of search results (default 25) # 最多搜寻结果数目(预设25个) --no-trunc Don`t truncate output # 不截断输出,描述完整显示 # stars数量大于10000的列表 [root@localhost ~]# docker search --filter=stars=10000 nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 12758 [OK] # 只显示官方版 [root@localhost ~]# docker search --filter=is-official=true nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 12758 [OK] # 只显示自动构建的 [root@localhost ~]# docker search --filter=is-automated=true nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1749 [OK] ``` ### 拉取:docker pull 镜像名[:标签] ```bash [root@localhost ~]# docker pull nginx Using default tag: latest latest: Pulling from library/nginx 68ced04f60ab: Pull complete 28252775b295: Pull complete a616aa3b0bf2: Pull complete Digest: sha256:2539d4344dd18e1df02be842ffc435f8e1f699cfc55516e2cf2cb16b7a9aea0b Status: Downloaded newer image for nginx:latest docker.io/library/nginx:latest [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 6678c7c2e56c 40 hours ago 127MB hello-world latest fce289e99eb9 14 months ago 1.84kB ``` ### 删除:docker rmi 镜像名[:标签] 删除本地镜像,可以为镜像名,也可以镜像ID,加上`-f`选项表示强制删除 ```bash # 删除镜像,如果运行的容器正在使用这个镜像需要强制删除 [root@localhost ~]# docker rmi hello-world Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 6422bf65891a is using its referenced image fce289e99eb9 # 添加-f选项强制删除镜像 [root@localhost ~]# docker rmi -f hello-world Untagged: hello-world:latest Untagged: hello-world@sha256:fc6a51919cfeb2e6763f62b6d9e8815acbf7cd2e476ea353743570610737b752 Deleted: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 6678c7c2e56c 40 hours ago 127MB ``` 删除多个镜像 ```bash [root@localhost ~]# docker rmi hello-world nginx ``` 删除所有镜像 ```bash [root@localhost ~]# docker images -qa 6678c7c2e56c fce289e99eb9 [root@localhost ~]# $(docker images -qa) -bash: 6678c7c2e56c: 未找到命令 [root@localhost ~]# echo $(docker images -qa) 6678c7c2e56c fce289e99eb9 # 批量删除所有镜像 [root@localhost ~]# docker rmi $(docker images -qa) ``` ## 容器命令 有镜像才能创建容器 ```bash [root@localhost ~]# docker pull centos [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 470671670cac 7 weeks ago 237MB ``` ### 运行:docker run 镜像名[镜像ID] #### 常用选项 - `--name`:为容器指定一个名称; - `-d`:后台运行容器,并返回容器的ID,即启动守护式容器; - `-i`:以交互模式运行容器,通常与`-t`一起使用 - `-t`:为容器重新分配一个伪输入终端,通常与`-i`一起使用; - `-P`:随机端口映射`docker run -it -P nginx`随机分配端口`0.0.0.0:32768->80/tcp`; - `-p`:指定端口映射,有以下格式: - `ip:宿主机端口:容器端口` - `ip::容器端口` - `宿主机端口:容器端口`:`docker run -it -p 8000:80 nginx`,外部通过8000端口访问容器内部80端口。 - `容器端口` 更多内容可以使用`[root@localhost ~]# docker run --help`获取 #### 前台运行容器 ```bash [root@localhost ~]# docker run -it centos # 以centos生成新的对象:02983b4225c6(容器ID) # 然后就会进入容器的终端 [root@02983b4225c6 /]# pwd / [root@02983b4225c6 /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var ``` #### -p 端口映射 `-p 外部端口:内部端口`映射端口 ```bash # 一个窗口启动nginx,将容器中的80端口映射到外部8080上 [root@localhost ~]# docker run -it -p 8080:80 nginx # 另一个窗口访问8080端口 [root@localhost ~]# curl localhost:8080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> # 容器会显示以下日志 172.17.0.1 - - [09/Mar/2020:08:05:33 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-" ``` #### 后台运行容器 ```bash [root@localhost ~]# docker run -d centos 9c950523ef0507a33bddd5182af726b886dde063a0ede403d96b66ad45f1c8dc [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # 使用-d运行的容器,运行后就退出了 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9c950523ef05 centos "/bin/bash" 17 seconds ago Exited (0) 16 seconds ago gallant_sanderson ``` Docker容器后台运行,就必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如:top、tail),就是会自动退出的。 这是Docker的机制问题,例如web容器nginx,正常情况下,配置启动服务只需要启动相应的service即可`service nginx start`,但是这样,nginx为后台进程模式运行,就导致Docker前台没有运行的应用,这样的容器后台启动后,会立即退出,因为它觉得自己没有事可做了,所以最佳的解决方案是,将**要运行的程序以前台进程的形式运行**。 所以让其程序保持前台运行 ```bash [root@localhost ~]# docker run -d centos /bin/bash -c "while true;do echo hello world; sleep 5;done" 90c18302fe0a4d64c615cfb0813e9d498dec89bdb084c1dc42340a8f6a576f31 # 可以看到这个后台运行的容器为Up的 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 90c18302fe0a centos "/bin/bash -c 'while…" 4 seconds ago Up 3 seconds tender_engelbart # 可以看到该容器的日志 [root@localhost ~]# docker logs 90c18302fe0a hello world ``` ### 退出:exit,离开Ctrl+P+Q `-it`运行容器后可以通过输入`exit`命令回车退出当前容器,返回到宿主系统。 ```bash # 这就给新建的容器指定一个别名,即docker ps中NAMES列显示该名称 [root@localhost ~]# docker run -it --name ctos centos [root@02983b4225c6 /]# exit exit ``` 在容器中按 Ctrl+P+Q 暂时离开容器,而不停止容器 ```bash [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7b59830862d4 centos "/bin/bash" 4 minutes ago Up 4 minutes ctos ``` 可以看到`STATUS`为`Up`,表示容器在后台运行着 ### 列出:docker ps 查看docker中运行的容器,新开一个终端,查看运行中的容器 ```bash [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 02983b4225c6 centos "/bin/bash" 3 minutes ago Up 3 minutes suspicious_proskuriakova ``` #### 常用选项 - `-a`:累出当前所有正在运行的容器和历史上运行过的容器 - `-l`:显示最近创建的容器 - `-n`:显示最近n个创建的容器 - `-q`:静默模式,只显示容器编号`CONTAINER ID`列表 - `--no-trunc`:不截断输出 可以通过`[root@localhost ~]# docker ps --help`查看该命令的所有选项。 ### 启动:docker start 容器ID[容器名] `start`启动退出的容器会保持容器之前的配置。 ```bash 02983b4225c6 centos "/bin/bash" 2 hours ago Exited (0) 13 minutes ago suspicious_proskuriakova ``` 对于状态为`Exited`的容器,如果想重新进入,可以指定其ID`02983b4225c6`或容器名称 ```bash [root@localhost ~]# docker start 02983b4225c6 02983b4225c6 [root@localhost ~]# docker ps -a | grep 02983b4225c6 02983b4225c6 centos "/bin/bash" 2 hours ago Up 17 seconds suspicious_proskuriakova ``` ### 重启:docker restart 容器ID[容器名] 对于运行中的容器,可以通过`restart`进行重启 ```bash [root@localhost ~]# docker ps -a | grep -E 'ctos|STATUS' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7b59830862d4 centos "/bin/bash" 13 minutes ago Up 13 minutes ctos # 指定容器名进行重启 [root@localhost ~]# docker restart ctos ctos [root@localhost ~]# docker ps -a | grep -E 'ctos|STATUS' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7b59830862d4 centos "/bin/bash" 13 minutes ago Up 3 seconds ctos ``` 可以看到重启成功后`STATUS`中`Up`时间发生变化。 ### 停止:docker stop 容器ID[容器名] `stop`类似于电脑正常关机 ### 强制停止:docker kill 容器ID[容器名] `kill`类似于电脑拔电源 ### 删除:docker rm 容器ID[容器名] 删除已停止的容器 ```bash [root@localhost ~]# docker ps -a | grep -E 'STATUS|Exited' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6422bf65891a hello-world "/hello" 46 hours ago Exited (0) 46 hours ago xenodochial_shtern [root@localhost ~]# docker rm 6422bf65891a 6422bf65891a [root@localhost ~]# docker ps -a | grep -E 'STATUS|Exited' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ``` `docker rm -f 容器ID[容器名]`强制删除,可以强制删除正在运行的容器。 一次性删除多个容器 ```bash docker rm -f $(docker ps -a -q) docker ps -a -q | xargs docker rm ``` ### 日志:docker logs 容器ID `docker logs -f -t --tail 10 容器ID` `-t`:加入时间戳 `-f`:跟随最新的日志打印 `--tail 数字`:显示最后多少条 ```bash # 查看容器的运行日志 [root@localhost ~]# docker logs 90c18302fe0a # 查看日志前面会添加上时间,例如2020-03-08T09:22:28.787068489Z [root@localhost ~]# docker logs -t 90c18302fe0a # 实时日志输出 [root@localhost ~]# docker logs -t -f 90c18302fe0a # 显示最后多少条 [root@localhost ~]# docker logs -t -f --tail 3 90c18302fe0a ``` ### 进程:docker top 容器ID 查看指定容器运行的进程 ```bash [root@localhost ~]# docker top 90c18302fe0a UID PID PPID C STIME TTY TIME CMD root 9697 9681 0 17:21 ? 00:00:00 /bin/bash -c while true;do echo hello world; sleep 5;done root 9860 9697 0 17:27 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 5 ``` ### 细节:docker inspect 容器ID 查看容器内部细节,以键值对的形式看到ID、创建时间、路径、参数、状态等详细信息。 ```bash [root@localhost ~]# docker inspect 90c18302fe0a ``` ### 进入:docker attach [exec -t 命令] 容器ID 进入正在运行中的容器并以命令行交换: - `docker exec -t 容器ID bash脚本`:在容器中打开新的终端,并且可以启动新的进程。 - `docker attach 容器ID`等效`docker exec -it 容器ID /bin/bash`:重新进入,直接进入容器启动命令的终端,不会启动新的进程。 ```bash # 前台运行容器后,按Ctrl+P+Q返回到宿主机 [root@localhost ~]# docker run -it centos [root@12396f0fe5e7 /]# [root@localhost ~]# [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 12396f0fe5e7 centos "/bin/bash" 11 seconds ago Up 11 seconds amazing_ishizaka # 要重新进入容器 [root@localhost ~]# docker attach 12396f0fe5e7 [root@12396f0fe5e7 /]# ls /tmp/ ks-script-_srt3u3c ks-script-gpqu_kuo # 等效与 [root@localhost ~]# docker exec -it 12396f0fe5e7 /bin/bash [root@12396f0fe5e7 /]# ls /tmp/ ks-script-_srt3u3c ks-script-gpqu_kuo # 再按Ctrl+P+Q返回,这个容器没有退出 [root@localhost ~]# docker exec -t 12396f0fe5e7 ls /tmp/ ks-script-_srt3u3c ks-script-gpqu_kuo # 直接在宿主机中显示容器中的执行结果 ``` ### 拷贝:docker cp 容器ID:容器内路径 目的主机路径 容器内的文件拷贝到宿主机上 ```bash [root@localhost ~]# docker cp 12396f0fe5e7:/var/log/dnf.log /root/ [root@localhost ~]# ls /root/ | grep log dnf.log ``` ### 提交镜像:docker commit 提交容器副本使之成为一个新的镜像。 `docker commit -m="提交的描述信息" -a="作者" 容器ID [命名空间]要创建的目标镜像名[:标签名]` ```bash [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 12396f0fe5e7 centos "/bin/bash" 23 hours ago Up 23 hours amazing_ishizaka # 修改过的容器提交为新的镜像 [root@localhost ~]# docker commit -a="username" -m="new centos" 12396f0fe5e7 namespace/centos:0.2 sha256:1195bb59f2dd1dbf2542ef37545ea05cc972373e2227a5636afb3ff76ea4529e # 查看新提交的镜像 [root@localhost ~]# docker images | grep -E 'TAG|centos' REPOSITORY TAG IMAGE ID CREATED SIZE namespace/centos 0.2 1195bb59f2dd 2 minutes ago 300MB centos latest 470671670cac 7 weeks ago 237MB # 运行自己创建的镜像,由于自己的镜像创建了标签不是latest,需要加上标签 [root@localhost ~]# docker run -it namespace/centos:0.2 [root@6c67e5e78506 /]# exit exit ``` # Docker容器数据卷 ## 概念 Docker理念: - 将运用与运行的环境打包形成容器运行,运行可以伴随着容器,但要对数据的要求希望是持久化的; - 容器之间希望有可能共享数据。 Docker容器产生的数据,如果不通过`docker commit`生成新的镜像,使数据作为镜像的一部分保存下来,那么容器删除后,数据就没有了。 而容器数据卷就是为了能保存数据。类似于Redis中的rdb和aof文件。 ## 作用 卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但不属于联合文件系统,因此能够绕过Union Filre System提供一些用于持久存储或共享数据的特性。 卷的设计目的就是数据的持久化,完全独立于容器的生命周期,因此Docker不会在容器删除时删除其挂载的数据卷。 特点: - 数据卷可以在容器之间共享或重用数据; - 数据卷中的更改可以直接生效; - 数据卷中的更改不会包含在镜像的更新中; - 数据卷的生命周期一直持续到没有容器使用它为止; - 即容器数据的持久化,容器间继承和共享数据。 ## 添加数据卷 -v 路径映射 容器内添加数据卷 ### 直接命令添加 **`docker run -it -v /宿主机的绝对路径目录:/容器内目录 镜像名` :映射可读可写目录。** ```bash [root@localhost ~]# docker run -it -v /hostData:/dockerData centos # 容器内 [root@2222a6d184c9 /]# ls | grep Data dockerData [root@2222a6d184c9 /]# touch /dockerData/1.py # 宿主机内根目录 [root@localhost ~]# ls / | grep Data hostData [root@localhost ~]# ls /hostData/ # 查看该容器的细节 [root@localhost ~]# docker inspect 2222a6d184c9 "Binds": [ "/hostData:/dockerData" ], # 主机路径为/hostData,容器对应路径为/dockerData # ... "Mounts": [ { "Type": "bind", "Source": "/hostData", "Destination": "/dockerData", "Mode": "", "RW": true, # 目录可读写 "Propagation": "rprivate" } ], ``` 可以看到`-v`创建目录映射后,会在宿主机和容器内都创建指定的路径,并实现数据共享。 容器停止或退出后,如果修改了宿主机中的数据,当容器再次`start`启动后,容器内数据保持一致。 **`docker run -it -v /宿主机的绝对路径目录:/容器内目录:ro 镜像名` :映射容器内只读目录,`ro`表示只读。** ```bash # 启动容器,容器内只读 [root@localhost ~]# docker run -it -v /hostData:/dockerData:ro centos [root@9440e1cef6d4 /]# ls /dockerData/ 1.py # 在容器内删除文件,由于设置的ro,只读不允许删除 [root@9440e1cef6d4 /]# rm -f /dockerData/1.py rm: cannot remove '/dockerData/1.py': Read-only file system # 容器内也不能创建文件 [root@9440e1cef6d4 /]# touch /dockerData/2.sh touch: cannot touch '/dockerData/2.sh': Read-only file system # 宿主机内创建文件 [root@localhost ~]# touch /hostData/2.sh # 容器内可以直接查看 [root@9440e1cef6d4 /]# ls /dockerData/ 1.py 2.sh # 查看该容器的细节 [root@localhost ~]# docker inspect 9440e1cef6d4 "Binds": [ "/hostData:/dockerData:ro" ], # 映射目录 # ... "Mounts": [ { "Type": "bind", "Source": "/hostData", "Destination": "/dockerData", "Mode": "ro", # 设置为ro,表示只读,不允许写操作 "RW": false, "Propagation": "rprivate" } ], ``` ### Dockerfile添加 Dockerfile:对镜像源码级的描述。 可在Dockerfile中使用`VOLUME`指令来给镜像添加一个或多个数据卷。 `VOLUME["/dataVolumeContainer1","/dataVolumeContainer2"],"/dataVolumeContainer3"]]` 说明: 出于可移植和分享的考虑,用`-v 主机目录:容器目录`这种方式不能直接在Dockerfile中实现; 由于宿主机目录是依赖于特定宿主机的,并不能保证在所有的宿主机上都存在这样的特定目录。 可以查看 https://hub.docker.com/_/redis redis的Dockerfile,编写一个自己的,只涉及到`VOLUME` ```bash [root@localhost ~]# vim Dockerfile # 添加以下内容,即Dockerfile脚本 FROM centos VOLUME ["/dataVolumeContainer1","dataVolumeContainer2"] CMD echo "finished!" CMD /bin/bash ``` `FROM`指定基础镜像。`VOLUME`指定在在容器内新建的容器卷,该镜像启动的容器会在容器中自动创建指定的目录。`CMD`指定运行命令。 使用`docker build`基于Dockerfile构建新的镜像 ```bash [root@localhost ~]# docker build -f ./Dockerfile -t username/centos . Sending build context to Docker daemon 73.01MB Step 1/4 : FROM centos ---> 470671670cac Step 2/4 : VOLUME ["/dataVolumeContainer1","dataVolumeContainer2"] ---> Running in 802acfdb9c70 Removing intermediate container 802acfdb9c70 ---> 56afc199843d Step 3/4 : CMD echo "finished!" ---> Running in 3257a1985c98 Removing intermediate container 3257a1985c98 ---> c42d4cf661b0 Step 4/4 : CMD /bin/bash ---> Running in 826e6bf4540d Removing intermediate container 826e6bf4540d ---> e798b17c7ed0 Successfully built e798b17c7ed0 # 一层一层叠加构建最后的镜像 Successfully tagged username/centos:latest # 查看构建的新镜像 [root@localhost ~]# docker images username/centos REPOSITORY TAG IMAGE ID CREATED SIZE username/centos latest e798b17c7ed0 4 minutes ago 237MB ``` `-f`:指定Dockerfile文件位置 `-t`:构建的镜像仓库名 `.`:表示当前目录,是在指定 **上下文路径** 运行容器 ```bash [root@localhost ~]# docker run -it username/centos # 自动创建了改目录 [root@b7a12418ff2c /]# ls | grep data dataVolumeContainer1 dataVolumeContainer2 # 查看容器挂载信息 [root@localhost ~]# docker inspect b7a12418ff2c "Mounts": [ { "Type": "volume", "Name": "18d983de94e78375e1f3bc200043319520c0a7fea8f5931129a12298df1d0674", "Source": "/var/lib/docker/volumes/18d983de94e78375e1f3bc200043319520c0a7fea8f5931129a12298df1d0674/_data", # 宿主机目录 "Destination": "/dataVolumeContainer1", # 容器内目录 "Driver": "local", "Mode": "", "RW": true, "Propagation": "" }, { "Type": "volume", "Name": "52e0c8b0d644a11a498e2dbc64abeb6b7fbc042507a1004247b4c2eb18578630", "Source": "/var/lib/docker/volumes/52e0c8b0d644a11a498e2dbc64abeb6b7fbc042507a1004247b4c2eb18578630/_data", "Destination": "dataVolumeContainer2", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], # ... "Volumes": { "/dataVolumeContainer1": {}, "dataVolumeContainer2": {} }, # 可以在宿主机中创建文件,查看容器内是否存在 [root@localhost ~]# touch /var/lib/docker/volumes/18d983de94e78375e1f3bc200043319520c0a7fea8f5931129a12298df1d0674/_data/1.py # 在容器内可以查看该目录文件 [root@b7a12418ff2c /]# ls /dataVolumeContainer1 1.py ``` 也就是使用`VOLUME`也实现了宿主机与容器内数据共享。 ### privileged=true 另外假如Docker挂载主机目录Docker内访问出现`cannot open directory:Permission denied`,解决办法是,在挂载目录后多加一个`--privileged=true`参数即可。即`docker run -it username/centos --privileged=true`。 ## 数据卷容器:容器卷共享给另一容器 命名的容器挂载数据卷,其它同期通过挂载这个(父容器)实现数据共享,容器数据卷的容器,称之为数据卷容器。吧容器比喻为移动硬盘,移动硬盘上挂载移动硬盘,实现数据的传递依赖。 ### 容器数据传递 --volumes-from 使用上面Dockerfile生成的镜像启动容器。 ```bash # 创建一个新的容器,指定明曾为ctos01,使用Dockerfile主要是用他的挂载数据卷功能 [root@localhost ~]# docker run -it --name ctos01 username/centos [root@4343d5788088 /]# ls -l | grep data drwxr-xr-x. 2 root root 6 Mar 10 04:11 dataVolumeContainer1 drwxr-xr-x. 2 root root 6 Mar 10 04:11 dataVolumeContainer2 # 在该ctos01容器内创建一个文件 [root@4343d5788088 /]# touch /dataVolumeContainer1/1.py [root@4343d5788088 /]# ls /dataVolumeContainer1 1.py # Ctrl+P+Q离开容器 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4343d5788088 username/centos "/bin/sh -c /bin/bash" 2 minutes ago Up 2 minutes ctos01 # 再启动另一个容器取名为ctos02,数据卷继承于ctos01 [root@localhost ~]# docker run -it --name ctos02 --volumes-from ctos01 username/centos [root@0ea7362e24c7 /]# ls -l | grep data drwxr-xr-x. 2 root root 18 Mar 10 04:12 dataVolumeContainer1 drwxr-xr-x. 2 root root 6 Mar 10 04:11 dataVolumeContainer2 [root@0ea7362e24c7 /]# ls /dataVolumeContainer1/ 1.py # 如果在容器2内新建一个文件,那么在容器1中也同样有 [root@0ea7362e24c7 /]# touch dataVolumeContainer2/2.py [root@0ea7362e24c7 /]# [root@localhost ~]# [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ea7362e24c7 username/centos "/bin/sh -c /bin/bash" 5 minutes ago Up 5 minutes ctos02 4343d5788088 username/centos "/bin/sh -c /bin/bash" 9 minutes ago Up 9 minutes ctos01 [root@localhost ~]# docker attach 4343d5788088 [root@4343d5788088 /]# ls /dataVolumeContainer2/ 2.py ``` - 子容器创建时可以通过`--volumes-from 父容器名`来继承父容器的数据卷; - 如果子容器继承了父容器的数据卷,即使父容器被删除了,子容器内数据依旧存在; - 继承父容器,即子容器都有相同的宿主机对应目录,即不管创建多少子容器,只要通过`--volumes-from`指定,则拥有相同的映射目录,这一点可以查看各个容器的`inspect`信息,`Mounts`中`Source`宿主机路径一样; - 容器之间配置信息的传递,数据卷的生命周期一直吃需要没有容器使用它为止。 # Dockerfile ## 概念 Dockerfile是用来构建Docker镜像的构建文件,是一系列命令和参数构成的脚本。 构建三步骤:编写Dockerfile文件 -> `docker build` -> `docker run` 参考centos的Dockerfile,访问 https://hub.docker.com/_/centos 即可,可以上dockerhub上搜索 ```bash # 以下即为最新的centos8的Dockerfile FROM scratch ADD CentOS-8-Container-8.1.1911-20200113.3-layer.x86_64.tar.xz / LABEL org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20200114" \ org.opencontainers.image.title="CentOS Base Image" \ org.opencontainers.image.vendor="CentOS" \ org.opencontainers.image.licenses="GPL-2.0-only" \ org.opencontainers.image.created="2020-01-14 00:00:00-08:00" CMD ["/bin/bash"] ``` ## 基础知识 - 每条保留字指令都必须为大写字母后面要跟随至少一个参数,不能没有参数; - 指定按照从上到下,顺序执行; - `#`表示注释; - 每条指令都会创建一个新的镜像层,并对镜像进行提交 ## 执行Dockerfile大致流程 1. docker从基础镜像运行一个容器; 2. 执行一条指令并对容器作出修改; 3. 执行类似`docker commit`的操作提交一个新的镜像层; 4. 再基于刚提交的镜像运行一个新容器; 5. 执行Dockerfile中的下一条指令,提交,运行,直到所有指令都执行完成。 从应用软件的角度看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个阶段: - Dockerfile是软件的原材料 - Docker镜像是软件的交付品 - Docker容器则可以认为是软件的运行态 Dockerfile面向开发,Docker镜像称为交付标准,Docker容器则涉及到部署与运维。 ## 体系结构,保留字指令 ### FROM 基础镜像,当前新镜像是基于哪个镜像的。 ### MAINTAINER 镜像维护者的姓名和邮箱地址 ### RUN 容器构建时需要运行的命令 ### EXPOSE 当前容器对外暴露的端口号 ### WORKDIR 指定在创建容器后,终端默认登录进来的工作目录 ### ENV 用来在构建镜像过程中设置环境变量 `ENV MY_PATH /data`这个环境变量可以在后续的任何`RUN`指令中使用,这就像在命令前面指定了环境变量前缀一样,也可以在其它指令中直接使用这些环境变量,比如`WORKDIR $MY_PATH`,那么用户登录后就会切换到`/data`目录。 ### ADD 将宿主机目录下的文件拷贝到镜像,且`ADD`命令会自动处理URL和解压tar压缩包 ### COPY 类似`ADD`,拷贝文件和目录到镜像中。 将从构建上下文目录中<源路径>的 文件/目录 复制到新的一层镜像内的<目标路径>位置。 ### VOLUME 容器数据卷,用于数据保存和持久化工作。 ### CMD 指定一个容器启动时要运行的命令。 Dockerfile中可以有多个`CMD`指令,但只有最后一个生效,`CMD`会被`docker run`之后的参数替换。 ### ENTRYPOINT 指定一个容器启动时要运行的命令。 `ENTRYPOINT`的目的和`CMD`一样,都是在指定容器启动程序及参数。人为在`docker run`添加参数会被追加,不会覆盖。 ### ONBUILD 当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后,父镜像的`ONBUILD`被触发。 ## 构建:docker build **`docker build -f /oath/Dockerfilexx -t [命名空间/]新镜像名[:TAG] .`** 如果Dockerfile文件的名字为`Dockerfile`,可以不要`-f`,即`docker build -t [命名空间/]新镜像名[:TAG] .` 构建时默认会使用缓存,如果不需要加上`--no-cache` ## 案例 Base镜像(`FROM scratch`),Dockerhub中绝大多数镜像都是通过在base镜像中安装和配置需要的软件构建出来的。 ### 自定义镜像centos #### 编写Dockerfile文件 ```bash [root@localhost ~]# vim NewCentOSDockerfile [root@localhost ~]# cat NewCentOSDockerfile FROM centos MAINTAINER name<admin@adimn.com> ENV myPath /usr/local WORKDIR $myPath CMD echo $myPath RUN yum install vim -y CMD echo "success!" CMD /bin/bash ``` #### 构建镜像 ```bash [root@localhost ~]# docker build -f ./NewCentOSDockerfile -t mycentos:1.2 . Sending build context to Docker daemon 73.01MB Error response from daemon: Dockerfile parse error line 6: unknown instruction: ECHO [root@localhost ~]# vim NewCentOSDockerfile [root@localhost ~]# vim NewCentOSDockerfile [root@localhost ~]# docker build -f ./NewCentOSDockerfile -t mycentos:1.2 . Sending build context to Docker daemon 73.01MB Step 1/8 : FROM centos ---> 470671670cac Step 2/8 : MAINTAINER name<admin@adimn.com> ---> Running in 52d2b6895fdc Removing intermediate container 52d2b6895fdc ---> 45d8217d2eb8 Step 3/8 : ENV myPath /usr/local ---> Running in 230bb81d9fab Removing intermediate container 230bb81d9fab ---> 1a457ebf46b4 Step 4/8 : WORKDIR $myPath ---> Running in 00fd62387ffd Removing intermediate container 00fd62387ffd ---> 16ac794f9fca Step 5/8 : CMD echo $myPath ---> Running in 3e38360ba88e Removing intermediate container 3e38360ba88e ---> 86bdd475d6c2 Step 6/8 : RUN yum install vim -y ---> Running in a6c768596f78 CentOS-8 - AppStream 2.1 MB/s | 6.5 MB 00:03 CentOS-8 - Base 1.1 MB/s | 5.0 MB 00:04 CentOS-8 - Extras 82 B/s | 2.1 kB 00:26 Dependencies resolved. # 安装vim步骤 Complete! Removing intermediate container a6c768596f78 ---> 02b0c69b9d48 Step 7/8 : CMD echo "success!" ---> Running in 582dfaf2fb2b Removing intermediate container 582dfaf2fb2b ---> 18a387f8de7d Step 8/8 : CMD /bin/bash ---> Running in 66733aa5f7c3 Removing intermediate container 66733aa5f7c3 ---> 9c093775a751 Successfully built 9c093775a751 Successfully tagged mycentos:1.2 ``` 可以看到生成的新镜像和原centos对比 ```bash [root@localhost ~]# docker images mycentos REPOSITORY TAG IMAGE ID CREATED SIZE mycentos 1.2 9c093775a751 7 minutes ago 300MB [root@localhost ~]# docker images centos REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 470671670cac 7 weeks ago 237MB ``` #### 运行容器 ```bash [root@localhost ~]# docker run -it mycentos:1.2 # 运行容器可以看到,登录的位置即为Dockerfile中WORKDIR指定的 [root@3802d2b22c0d local]# pwd /usr/local # 由于Dockerfile中安装了vim,则新的容器就支持vim编辑器了 [root@3802d2b22c0d local]# vim ``` #### 查看镜像修改历史 docker history ```bash [root@localhost ~]# docker history mycentos:1.2 IMAGE CREATED CREATED BY SIZE COMMENT 9c093775a751 14 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B 18a387f8de7d 14 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B 02b0c69b9d48 14 minutes ago /bin/sh -c yum install vim -y 63.2MB 86bdd475d6c2 15 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B 16ac794f9fca 15 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B 1a457ebf46b4 15 minutes ago /bin/sh -c #(nop) ENV myPath=/usr/local 0B 45d8217d2eb8 15 minutes ago /bin/sh -c #(nop) MAINTAINER name<admin@adi… 0B 470671670cac 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 7 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 7 weeks ago /bin/sh -c #(nop) ADD file:aa54047c80ba30064… 237MB ``` 从下往上一层一层叠加的镜像。 ### CMD对比ENTRYPOINT #### CMD指令 对于centos的镜像的Dockerfile文件,最后是`CMD ["/bin/bash"]` ```bash # 创建一个新的Dockerfile [root@localhost ~]# vim Dockerfile1 [root@localhost ~]# cat Dockerfile1 FROM centos CMD ["ls"] # 构建新的镜像 [root@localhost ~]# docker build -f ./Dockerfile1 -t xx/centos1 . Sending build context to Docker daemon 73.01MB Step 1/2 : FROM centos ---> 470671670cac Step 2/2 : CMD ["ls"] ---> Running in 05ebaa6aea53 Removing intermediate container 05ebaa6aea53 ---> d21d177ce3cc Successfully built d21d177ce3cc Successfully tagged xx/centos1:latest # 查看新生成的镜像 [root@localhost ~]# docker images xx/centos1 REPOSITORY TAG IMAGE ID CREATED SIZE xx/centos1 latest d21d177ce3cc About a minute ago 237MB ``` 那么启动该镜像默认使用`ls`显示根目录的信息 ```bash # 使用该镜像启动新的容器 [root@localhost ~]# docker run -it xx/centos1 bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr # 如果还想扩展其参数,例如ls -l,那么运行时就会报错,因为他是替换原DockerfileCMD 命令 [root@localhost ~]# docker run -it xx/centos1 -l docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown. # 要想实现该功能,需要完整书写ls -l命令 [root@localhost ~]# docker run -it xx/centos1 ls -l total 0 lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin drwxr-xr-x. 5 root root 360 Mar 10 13:02 dev drwxr-xr-x. 1 root root 66 Mar 10 13:02 etc drwxr-xr-x. 2 root root 6 May 11 2019 home lrwxrwxrwx. 1 root root 7 May 11 2019 lib -> usr/lib lrwxrwxrwx. 1 root root 9 May 11 2019 lib64 -> usr/lib64 drwx------. 2 root root 6 Jan 13 21:48 lost+found drwxr-xr-x. 2 root root 6 May 11 2019 media drwxr-xr-x. 2 root root 6 May 11 2019 mnt drwxr-xr-x. 2 root root 6 May 11 2019 opt dr-xr-xr-x. 135 root root 0 Mar 10 13:02 proc dr-xr-x---. 2 root root 162 Jan 13 21:49 root drwxr-xr-x. 11 root root 163 Jan 13 21:49 run lrwxrwxrwx. 1 root root 8 May 11 2019 sbin -> usr/sbin drwxr-xr-x. 2 root root 6 May 11 2019 srv dr-xr-xr-x. 13 root root 0 Mar 5 10:02 sys drwxrwxrwt. 7 root root 145 Jan 13 21:49 tmp drwxr-xr-x. 12 root root 144 Jan 13 21:49 usr drwxr-xr-x. 20 root root 262 Jan 13 21:49 var ``` Dockerfile中最后一个`CMD`指令在启动容器时不加任何参数情况下生效,如果`docker run`后添加参数,那么`CMD`会被参数替换,也就是Dockerfile中的最后一个`CMD`无效了。 例如Dockerfile中是`CMD ["ls"]`,如果使用`docker run 镜像 ls -l`,则会替换原来的命令组合`CMD ["ls","-l"]` #### ENTRYPOINT指令 ```bash # 创建一个新的Dockerfile [root@localhost ~]# vim Dockerfile2 [root@localhost ~]# cat Dockerfile2 FROM centos ENTRYPOINT ["ls"] # 构建新的镜像 [root@localhost ~]# docker build -f ./Dockerfile2 -t xx/centos2 . Sending build context to Docker daemon 73.01MB Step 1/2 : FROM centos ---> 470671670cac Step 2/2 : ENTRYPOINT ["ls"] ---> Running in 43ad265872ea Removing intermediate container 43ad265872ea ---> da5ea4042a02 Successfully built da5ea4042a02 Successfully tagged xx/centos2:latest # 使用该镜像启动容器,默认会执行ls命令 [root@localhost ~]# docker run -it xx/centos2 bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr # 如果run后面添加参数,例如添加-l,就相当于把 ENTRYPOINT ["ls"] 变为 ENTRYPOINT ["ls","-l"],即执行 ls -l 命令了 [root@localhost ~]# docker run -it xx/centos2 -l total 0 lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin drwxr-xr-x. 5 root root 360 Mar 10 13:08 dev drwxr-xr-x. 1 root root 66 Mar 10 13:08 etc drwxr-xr-x. 2 root root 6 May 11 2019 home lrwxrwxrwx. 1 root root 7 May 11 2019 lib -> usr/lib lrwxrwxrwx. 1 root root 9 May 11 2019 lib64 -> usr/lib64 drwx------. 2 root root 6 Jan 13 21:48 lost+found drwxr-xr-x. 2 root root 6 May 11 2019 media drwxr-xr-x. 2 root root 6 May 11 2019 mnt drwxr-xr-x. 2 root root 6 May 11 2019 opt dr-xr-xr-x. 135 root root 0 Mar 10 13:08 proc dr-xr-x---. 2 root root 162 Jan 13 21:49 root drwxr-xr-x. 11 root root 163 Jan 13 21:49 run lrwxrwxrwx. 1 root root 8 May 11 2019 sbin -> usr/sbin drwxr-xr-x. 2 root root 6 May 11 2019 srv dr-xr-xr-x. 13 root root 0 Mar 5 10:02 sys drwxrwxrwt. 7 root root 145 Jan 13 21:49 tmp drwxr-xr-x. 12 root root 144 Jan 13 21:49 usr drwxr-xr-x. 20 root root 262 Jan 13 21:49 var ``` `docker run ***`之后的参数,会被当作参数传递给`ENTRYPOINT`,形成新的命令组合。 例如Dockerfile中是`ENTRYPOINT ["ls"]`,如果使用`docker run 镜像 -l`,则形成新的组合为`ENTRYPOINT ["ls","-l"]` ### ONBUILD指令 子镜像构建时,触发父镜像的`ONBUILD`指令 ```bash # 创建父镜像的Dockerfile [root@localhost ~]# vim Dockerfile3 [root@localhost ~]# cat Dockerfile3 FROM centos ONBUILD RUN echo "父镜像被继承" # 构建父镜像 [root@localhost ~]# docker build -f ./Dockerfile3 -t xx/centos3 . Sending build context to Docker daemon 73.01MB Step 1/2 : FROM centos ---> 470671670cac Step 2/2 : ONBUILD RUN echo "父镜像被继承" ---> Running in 69744e0d9c78 Removing intermediate container 69744e0d9c78 ---> 96719c852415 Successfully built 96719c852415 Successfully tagged xx/centos3:latest # 创建子镜像的Dockerfile [root@localhost ~]# vim Dockerfile4 [root@localhost ~]# cat Dockerfile4 FROM xx/centos3 CMD echo "子镜像继承centos3父镜像" # 构建子镜像 [root@localhost ~]# docker build -f ./Dockerfile4 -t xx/centos4 . Sending build context to Docker daemon 73.01MB Step 1/2 : FROM xx/centos3 # Executing 1 build trigger # 执行一个构建触发器 ---> Running in 2a4a53e3bfda 父镜像被继承 # 并执行触发器中的内容 Removing intermediate container 2a4a53e3bfda ---> 3497155cb295 Step 2/2 : CMD echo "子镜像继承centos3父镜像" ---> Running in 6f36286e630a Removing intermediate container 6f36286e630a ---> 68641db9fdfd Successfully built 68641db9fdfd Successfully tagged xx/centos4:latest ``` ### 基于centos的tomcat自定义 #### 准备需要的文件 ```bash # 创建一个文件夹,主要是放构建Docker镜像存放的文件 [root@localhost ~]# mkdir mytomcat9 [root@localhost ~]# cd mytomcat9/ # 这个文件仅作为COPY功能的讲解 [root@localhost mytomcat9]# touch test.txt # 准备要Linux上用的jdk和tomcat [root@localhost mytomcat9]# ls -l 总用量 198044 -rw-r--r--. 1 root root 11042076 3月 10 22:48 apache-tomcat-9.0.31.tar.gz -rw-r--r--. 1 root root 191753373 3月 10 22:48 jdk-8u191-linux-x64.tar.gz -rw-r--r--. 1 root root 0 3月 10 22:38 test.txt ``` #### 创建Dockerfile文件 ```bash # 创建Dockerfile文件 [root@localhost mytomcat9]# vim Dockerfile [root@localhost mytomcat9]# cat Dockerfile # ---------Dockerfile 内容开始--------- FROM centos MAINTAINER user<admin@admin.com> # 把宿主机当前上下文的test.txt文件拷贝到容器/usr/local/路径下 COPY test.txt /usr/local/docker_ts.txt # 把java与tomcat添加到容器中,ADD文件拷贝到镜像,且自动处理tar ADD apache-tomcat-9.0.31.tar.gz /usr/local ADD jdk-8u191-linux-x64.tar.gz /usr/local # 安装vim编辑器,RUN表示容器构建时需要运行命令 RUN yum install vim -y # 设置登录路径 ENV MYPATH /usr/local WORKDIR $MYPATH # 配置java与tomcat环境变量 # 解压文件:jdk-8u191-linux-x64.tar.gz\jdk-8u191-linux-x64.tar\jdk1.8.0_191 ENV JAVA_HOME $MYPATH/jdk1.8.0_191 # 解压文件:apache-tomcat-9.0.31.tar.gz\apache-tomcat-9.0.31.tar\apache-tomcat-9.0.31 ENV CATALINA_HOME $MYPATH/apache-tomcat-9.0.31 ENV CATALINA_BASE $MYPATH/apache-tomcat-9.0.31 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin # 容器运行时监听的端口 EXPOSE 8080 # 启动tomcat # 可以将tail -f修改为tail -F,如果是-f,知不道文件就直接退出了,-F保持等待状态,如果生成了该文件,则读取该文件 CMD $TOMCAT_HOME/bin/startup.sh && tail -f $TOMCAT_HOME/bin/logs/catalina.out # ---------Dockerfile 内容结束--------- ``` #### 构建镜像 ```bash # 构建镜像,由于这儿Dockerfile文件名字就是Dockerfile,就不需要-t指定Dockerfile的位置了。 Sending build context to Docker daemon 202.8MB Step 1/15 : FROM centos ---> 470671670cac Step 2/15 : MAINTAINER user<admin@admin.com> ---> Running in 1b12d8e8ddb5 Removing intermediate container 1b12d8e8ddb5 ---> 2e9788470b9e Step 3/15 : COPY test.txt /usr/local/docker_ts.txt ---> 1383ea131647 Step 4/15 : ADD apache-tomcat-9.0.31.tar.gz /usr/local ---> be1bc068b64b Step 5/15 : ADD jdk-8u191-linux-x64.tar.gz /usr/local ---> 8b368c4df92a Step 6/15 : RUN yum install vim -y ---> Running in d81f55b59bf5 # 安装vim过程 Complete! Removing intermediate container d81f55b59bf5 ---> c4d4aa75b738 Step 7/15 : ENV MYPATH /usr/local ---> Running in 6e3e187123b0 Removing intermediate container 6e3e187123b0 ---> 5e7df3381148 Step 8/15 : WORKDIR $MYPATH ---> Running in e46a5f8e5923 Removing intermediate container e46a5f8e5923 ---> b6d994641f70 Step 9/15 : ENV JAVA_HOME $MYPATH/jdk1.8.0_191 ---> Running in fbc8d90ec7dc Removing intermediate container fbc8d90ec7dc ---> a7f5817c6d4a Step 10/15 : ENV CATALINA_HOME $MYPATH/apache-tomcat-9.0.31 ---> Running in 8f57522b9746 Removing intermediate container 8f57522b9746 ---> a7f0c37e8e52 Step 11/15 : ENV CATALINA_BASE $MYPATH/apache-tomcat-9.0.31 ---> Running in 7bd62a5e63e6 Removing intermediate container 7bd62a5e63e6 ---> ba9bb1a1c673 Step 12/15 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ---> Running in 328cc850b6ed Removing intermediate container 328cc850b6ed ---> afef88932865 Step 13/15 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin ---> Running in 20d65387be48 Removing intermediate container 20d65387be48 ---> b690839100b7 Step 14/15 : EXPOSE 8080 ---> Running in 271962a4a2ae Removing intermediate container 271962a4a2ae ---> a01da27056e9 Step 15/15 : CMD $CATALINA_HOME/bin/startup.sh && tail -f $CATALINA_HOME/logs/catalina.out ---> Running in 67a4b5f746ff Removing intermediate container 67a4b5f746ff ---> 88d770b804b0 Successfully built 88d770b804b0 Successfully tagged mytomcat9:latest # 查看构建的镜像 [root@localhost mytomcat9]# docker images mytomcat9 REPOSITORY TAG IMAGE ID CREATED SIZE mytomcat9 latest 88d770b804b0 42 seconds ago 712MB ``` #### 指定该镜像运行容器 映射端口`-p 9090:8080` 映射路径`-v /mydocker/mytomcat9/test:/usr/local/apache-tomcat-9.0.31/webapps/test` 映射路径`-v /mydocker/mytomcat9/logs:/usr/local/apache-tomcat-9.0.31/logs` 如果Docker容器内访问宿主机目录出现权限问题使用`--privileged=true` ```bash [root@localhost mytomcat9]# docker run -d -p 9090:8080 --name mytc9 -v /mydocker/mytomcat9/test:/usr/local/apache-tomcat-9.0.31/webapps/test -v /mydocker/mytomcat9/logs:/usr/local/apache-tomcat-9.0.31/logs --privileged=true mytomcat9 df51a503bd2a8677ff72489faee89f11674f440a70bf460bab90d0e8ef747479 # 查看容器运行状态 [root@localhost mytomcat9]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES df51a503bd2a mytomcat9 "/bin/sh -c '$CATALI…" 8 seconds ago Up 7 seconds 0.0.0.0:9090->8080/tcp mytc9 [root@localhost mytomcat9]# docker logs df51a503bd2a Tomcat started. 11-Mar-2020 02:54:56.948 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/9.0.31 11-Mar-2020 02:54:56.965 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Feb 5 2020 19:32:12 UTC 11-Mar-2020 02:54:56.965 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 9.0.31.0 11-Mar-2020 02:54:56.965 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux 11-Mar-2020 02:54:56.965 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 3.10.0-1062.4.1.el7.x86_64 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/local/jdk1.8.0_191/jre 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 1.8.0_191-b12 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/apache-tomcat-9.0.31 11-Mar-2020 02:54:56.966 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/apache-tomcat-9.0.31 # 很多日志输出 # 另外宿主机也自动创建了这两个目录 [root@localhost mytomcat9]# tree /mydocker/mytomcat9 /mydocker/mytomcat9 ├── logs │ ├── catalina.2020-03-11.log │ ├── catalina.out │ ├── host-manager.2020-03-11.log │ ├── localhost.2020-03-11.log │ ├── localhost_access_log.2020-03-11.txt │ └── manager.2020-03-11.log └── test # 容器内/usr/local目录 [root@localhost mytomcat9]# docker exec -it df51a503bd2a ls apache-tomcat-9.0.31 docker_ts.txt include lib64 share apache-tomcat-9.0.31.logs etc jdk1.8.0_191 libexec src bin games lib sbin [root@localhost mytomcat9]# docker exec -it df51a503bd2a java -version java version "1.8.0_191" Java(TM) SE Runtime Environment (build 1.8.0_191-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode) ``` #### 浏览器验证访问 ```bash # 防火墙允许端口 [root@localhost mytomcat9]# firewall-cmd --add-port 9090/tcp success ``` 然后浏览器访问 http://192.168.99.102:9090/ 就可以看到`Apache Tomcat/9.0.31`的页面了 #### 发布测试的web服务 ```bash [root@localhost mytomcat9]# cd /mydocker/mytomcat9/test/ [root@localhost test]# mkdir WEB-INF [root@localhost test]# cd WEB-INF/ [root@localhost WEB-INF]# vim web.xml [root@localhost WEB-INF]# cat web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>test</display-name> </web-app> [root@localhost WEB-INF]# cd .. [root@localhost test]# vim a.jsp [root@localhost test]# cat a.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Welcome</h1> <%="front print"%> <br> <% System.out.println("backgroud print"); %> </body> </html> [root@localhost test]# tree . ├── a.jsp └── WEB-INF └── web.xml # 编辑完后可以重启下重启 [root@localhost test]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES df51a503bd2a mytomcat9 "/bin/sh -c '$CATALI…" 33 minutes ago Up 7 minutes 0.0.0.0:9090->8080/tcp mytc9 [root@localhost test]# docker restart df5 ``` 浏览器访问 http://192.168.99.102:9090/test/a.jsp 可以在查看容器的日志 ```bash [root@localhost test]# docker logs -t --tail 5 df5 2020-03-11T09:07:34.778003518Z backgroud print 2020-03-11T09:07:34.955522519Z backgroud print 2020-03-11T09:07:35.327600149Z backgroud print 2020-03-11T09:07:35.503474753Z backgroud print 2020-03-11T09:07:35.681386449Z backgroud print ``` 映射的目录同样也可以查看到日志 ```bash [root@localhost test]# tail -n 5 /mydocker/mytomcat9/logs/catalina.out backgroud print backgroud print backgroud print backgroud print backgroud print ``` # Docker常用安装 ## Docker安装mysql ### 拉取镜像 ```bash # 搜索镜像 [root@localhost ~]# docker search --limit 3 mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation… 9216 [OK] mysql/mysql-server Optimized MySQL Server Docker images. Create… 681 [OK] circleci/mysql MySQL is a widely used, open-source relation… 19 # 拉取镜像 [root@localhost ~]# docker pull mysql:5.7 # ... Digest: sha256:f4a5f5be3d94b4f4d3aef00fbc276ce7c08e62f2e1f28867d930deb73a314c58 Status: Downloaded newer image for mysql:5.7 docker.io/library/mysql:5.7 [root@localhost ~]# docker images mysql REPOSITORY TAG IMAGE ID CREATED SIZE mysql 5.7 84164b03fa2e 6 days ago 456MB ``` ### 启动容器 ```bash [root@localhost ~]# docker run -d -p 30306:3306 -v /mydocker/mysql/conf:/etc/mysql/conf.d -v /mydocker/mysql/logs:/logs -v /mydocker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=Pa$sW0rd --name mysql mysql:5.7 0b9b4a9166d8020f272d37c7ecff991eb0bf8c0e3fa722a6f657510db2ff4f97 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0b9b4a9166d8 mysql:5.7 "docker-entrypoint.s…" About a minute ago Up About a minute 33060/tcp, 0.0.0.0:30306->3306/tcp mysql # 开启宿主机的防火墙端口 [root@localhost ~]# firewall-cmd --zone=public --add-port=30306/tcp success ``` - `-p 30306:3306`:端口映射,外部访问30306 - `-v /mydocker/mysql/conf:/etc/mysql/conf.d`:mysql配置文件 - `-v /mydocker/mysql/logs:/logs`:mysql日志文件 - `-v /mydocker/mysql/data:/var/lib/mysql`:mysql数据文件 - `-e MYSQL_ROOT_PASSWORD=Pa$sW0rd`:设置root的密码 - `--name mysql`:运行服务名字 ### 进入容器连接mysql ```bash [root@localhost ~]# docker exec -it 0b9b4a9166d8 /bin/bash root@0b9b4a9166d8:/# ps bash: ps: command not found root@0b9b4a9166d8:/# mysql -uroot -p Enter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) ``` ### 解决容器连接mysql 1045错误 解决步骤 ```bash root@0b9b4a9166d8:/# exit exit # 退出容器,在宿主机映射的mysql配置文件夹添加配置 [root@localhost ~]# vim /mydocker/mysql/conf/my.cnf [root@localhost ~]# cat /mydocker/mysql/conf/my.cnf # 添加以下内容 [mysqld] skip-grant-tables # 重启mysql容器 [root@localhost ~]# docker restart mysql mysql # 进入容器执行命令 [root@localhost ~]# docker exec -it mysql /bin/bash # 由于是本地登录可以直接输入mysql连接 root@0b9b4a9166d8:/# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.29 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> quit; Bye # 测试帐密连接 root@0b9b4a9166d8:/# mysql -uroot -p Enter password: # Pa$sW0rd Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 Server version: 5.7.29 MySQL Community Server (GPL) Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> quit; Bye ``` ### 在宿主机中连接mysql 也可以使用宿主机的IP:`mysql -h192.168.99.102 -P30306 -uroot -p` ```bash root@0b9b4a9166d8:/# exit exit [root@localhost ~]# mysql -h127.0.0.1 -P30306 -uroot -p Enter password: # Pa$sW0rd Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.29 MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> ``` ### 宿主机备份容器数据 ```bash [root@localhost ~]# docker exec -it mysql sh -c 'exec mysqldump --all-databases -uroot -pPa$sW0rd' > /mydocker/mysql/all-databases.sql [root@localhost ~]# ls /mydocker/mysql/ all-databases.sql conf data logs ``` ## Docker安装redis ### 拉取镜像 ```bash [root@localhost ~]# docker pull redis:5.0.7 [root@localhost ~]# docker images redis REPOSITORY TAG IMAGE ID CREATED SIZE redis 5.0.7 7eed8df88d3b 13 days ago 98.2MB ``` ### 启动容器 ```bash [root@localhost ~]# docker run -d -p 36079:6379 -v /mydocker/redis/data:/data --name redis redis:5.0.7 --appendonly yes 0634727a9e0a6ef82838965ee3349b8717bb1412053fa98c63de44669c978d31 [root@localhost ~]# docker ps | grep -E "IMAGE|redis" CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0634727a9e0a redis:5.0.7 "docker-entrypoint.s…" 8 seconds ago Up 8 seconds 0.0.0.0:36079->6379/tcp redis ``` - `-p 36079:6379`:端口映射,外部36079访问 - `-v /mydocker/redis/data:/data`:挂载容器`/data`目录 - `--appendonly yes`:开启aof持久化 ### 进入容器连接redis ```bash [root@localhost ~]# docker exec -it redis /bin/bash root@0634727a9e0a:/data# ls appendonly.aof # redis客户端连接 root@0634727a9e0a:/data# redis-cli 127.0.0.1:6379> set k1 1 OK 127.0.0.1:6379> get k1 "1" 127.0.0.1:6379> quit root@0634727a9e0a:/data# exit exit ``` ### 宿主机连接redis ```bash [root@localhost ~]# wget download.redis.io/releases/redis-5.0.7.tar.gz [root@localhost ~]# tar -zxf redis-5.0.7.tar.gz [root@localhost ~]# cd redis-5.0.7 [root@localhost redis-5.0.7]# make && make install # 测试连接容器内的redis [root@localhost redis-5.0.7]# redis-cli -h 192.168.99.102 -p 36079 192.168.99.102:36079> get k1 "1" 192.168.99.102:36079> quit ``` ### 自定义配置文件 由于在上面宿主机中安装redis来测试了,里面有原版的`redis.conf`文件 ```bash [root@localhost redis-5.0.7]# ls -l redis.conf -rw-rw-r--. 1 root root 61797 11月 20 01:05 redis.conf # 创建映射到宿主机的配置文件路径 [root@localhost redis-5.0.7]# mkdir -p /mydocker/redis/conf # 复制配置文件 [root@localhost redis-5.0.7]# cp redis.conf /mydocker/redis/conf [root@localhost redis-5.0.7]# cd # 查看主要的配置 [root@localhost ~]# cat /mydocker/redis/conf/redis.conf | grep -E "^bind |^daemonize |logfile |requirepass |appendonly " bind 127.0.0.1 daemonize no logfile "" # requirepass foobared appendonly no # 使用sed修改配置 [root@localhost ~]# sed -i 's/bind 127.0.0.1/# bind 127.0.0.1/' /mydocker/redis/conf/redis.conf [root@localhost ~]# sed -i 's/# requirepass foobared/requirepass redis_pass/' /mydocker/redis/conf/redis.conf # 查看已修改过的配置 [root@localhost ~]# cat /mydocker/redis/conf/redis.conf | grep -E "^bind |^daemonize |logfile |requirepass |appendonly " daemonize no logfile "" requirepass redis_pass appendonly no ``` 另外也可以通过`--appendonly yes`加参数形式启动容器。 redis.conf 中`daemonize no`。非后台模式,如果为`yes`会的导致 redis 无法启动,因为后台会导致docker无任务可做而退出。其他主要的就是`bind`、`requirepass`、`logfile`、`port`等 在`/mydocker/redis/conf`目录下已经有了已修改过的`redis.conf`配置文件,使用它来启动容器,启动时给`redis-server`添加一些参数 ```bash # 因为之前启动过同名的,将其删除 [root@localhost ~]# docker rm -f redis # 使用新配置启动容器 [root@localhost ~]# docker run -d -p 36079:6379 -v /mydocker/redis/data:/data -v /mydocker/redis/conf/redis.conf:/etc/redis/redis.conf --name redis redis:5.0.7 redis-server /etc/redis/redis.conf --appendonly yes ``` - `-v /mydocker/redis/conf/redis.conf:/etc/redis/redis.conf`:挂载配置文件,提前将`redis.conf`放在里面 宿主机连接redis ```bash [root@localhost ~]# redis-cli -h 192.168.99.102 -p 36079 # 由于没有输入密码,会提示认证失败 192.168.99.102:36079> get k1 (error) NOAUTH Authentication required. # 认证密码 192.168.99.102:36079> auth redis_pass OK # 由于redis开启了aof持久化,之前容器删除后,由于指定了-v /mydocker/redis/data:/data和--appendonly yes,则直接读取里面的值 192.168.99.102:36079> get k1 "1" 192.168.99.102:36079> quit # 也可以直接在命令上指定passwd [root@localhost ~]# redis-cli -h 192.168.99.102 -p 36079 -a redis_pass Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 192.168.99.102:36079> get k1 "1" 192.168.99.102:36079> quit [root@localhost ~]# tree /mydocker/redis/ /mydocker/redis/ ├── conf │ └── redis.conf └── data └── appendonly.aof ``` # 本地镜像发布 ## 阿里云创建仓库 1. 访问 https://cr.console.aliyun.com/cn-chengdu/new 设置Registry登录密码; 2. 创建镜像仓库,创建命名空间,设置仓库名称(可以和`docker images`中的`REPOSITORY`名称保持一致),摘要,点击下一步; 3. 选择本地仓库(您可以通过命令行推送镜像到镜像仓库。),点击创建镜像仓库; 4. 在镜像仓库中可以看到刚创建的仓库信息,点击管理,可以看到仓库详情。 ## 操作流程 在仓库详情中,可以看到操作指南 ### 推送镜像 #### 登录阿里云docker ```bash # 登录阿里云Docker Registry [root@localhost ~]# docker login --username=阿里云登录用户名 registry.cn-chengdu.aliyuncs.com Password: # 用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。以在访问凭证页面修改凭证密码。 WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded ``` #### 标记本地镜像 标记本地镜像,将其归入某一仓库 ```bash # 镜像推送到Registry [root@localhost ~]# docker images hello-world REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB [root@localhost ~]# docker tag fce289e99eb9 registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 ``` #### 推送到镜像仓库 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库 ```bash [root@localhost ~]# docker push registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 The push refers to repository [registry.cn-chengdu.aliyuncs.com/starmeow/hello-world] af0b15c8625b: Mounted from starmeow/docker 1.2: digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a size: 524 # 根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。 ``` 可以看到本地 ```bash [root@localhost ~]# docker images | grep -E "TAG|hello-world" REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB registry.cn-chengdu.aliyuncs.com/starmeow/hello-world 1.2 fce289e99eb9 14 months ago 1.84kB ``` ### 拉取镜像 ```bash # 先从本地删除 [root@localhost ~]# docker rmi registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 Untagged: registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 Untagged: registry.cn-chengdu.aliyuncs.com/starmeow/hello-world@sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a [root@localhost ~]# docker images | grep -E "TAG|hello-world" REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB # 拉取阿里云的镜像 [root@localhost ~]# docker pull registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 1.2: Pulling from starmeow/hello-world Digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a Status: Downloaded newer image for registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 registry.cn-chengdu.aliyuncs.com/starmeow/hello-world:1.2 # 查看拉取的镜像 [root@localhost ~]# docker images | grep -E "TAG|hello-world" REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB registry.cn-chengdu.aliyuncs.com/starmeow/hello-world 1.2 fce289e99eb9 14 months ago 1.84kB ``` # 私有仓库搭建 ## registry的搭建 Docker 官方提供了一个搭建私有仓库的镜像 registry ,只需把镜像下载下来,运行容器并暴露5000端口,就可以使用了 ### 拉取registry镜像 ```bash [root@localhost ~]# docker pull registry [root@localhost ~]# docker images registry REPOSITORY TAG IMAGE ID CREATED SIZE registry latest 708bc6af7e5e 6 weeks ago 25.8MB ``` ### 启动registry ```bash [root@localhost ~]# docker run -d -p 5000:5000 -v /mydocker/myregistry:/var/lib/registry --restart always --privileged=true --name myregistry registry f58c15bd63f85c7f4d0dec8f36d8a41eea8d4bce21327f311a613955f3dbcbaa [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f58c15bd63f8 registry "/entrypoint.sh /etc…" 30 seconds ago Up 30 seconds 0.0.0.0:5000->5000/tcp myregistry ``` - `-v /mydocker/myregistry:/var/lib/registry`:容器目录映射,如果容器被删除,镜像也不会删除 - `--privileged=true`:centos7中的安全模块selinux把权限禁止了,加上这行是给容器增加执行权限 - `--restart always`:自动重启 浏览器访问 http://192.168.99.102:5000/v2/ 可以得到`{}` ### 标记镜像 要通过`docker tag 指定的镜像[:TAG] 私有仓库地址/仓库名[:新TAG]`将该镜像标志为要推送到私有仓库 ```bash [root@localhost ~]# docker tag hello-world:latest 192.168.99.102:5000/hello-world:1.2 ``` ### 推送镜像 ```bash [root@localhost ~]# docker push 192.168.99.102:5000/hello-world:1.2 The push refers to repository [192.168.99.102:5000/hello-world] Get https://192.168.99.102:5000/v2/: http: server gave HTTP response to HTTPS client ``` 这是因为我们启动的registry服务不是安全可信赖的,需指定 主机的IP地址或者域名:5000。 ### 配置insecure-registries 解决办法,在docker配置文件中添加`"insecure-registries":["192.168.99.102:5000"]` ```bash [root@localhost ~]# vim /etc/docker/daemon.json [root@localhost ~]# cat /etc/docker/daemon.json { "registry-mirrors": [ "https://dockerhub.azk8s.cn", "https://hub-mirror.c.163.com" ], "insecure-registries":["192.168.99.102:5000"] } [root@localhost ~]# systemctl restart docker ``` 测试,如果重新加载也可以:**`systemctl reload docker`** 然后再次执行标签、推送 ```bash [root@localhost ~]# docker tag hello-world:latest 192.168.99.102:5000/hello-world:1.2 [root@localhost ~]# docker push 192.168.99.102:5000/hello-world:1.2 The push refers to repository [192.168.99.102:5000/hello-world] af0b15c8625b: Layer already exists 1.2: digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a size: 524 ``` 访问 http://192.168.99.102:5000/v2/_catalog 可以看到`{"repositories":["hello-world"]}` ### 拉取镜像 ```bash [root@localhost ~]# docker pull 192.168.99.102:5000/hello-world:1.2 ``` ## harbor的搭建 docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。 官网: https://goharbor.io/ ### 下载harbor 访问 https://github.com/goharbor/harbor/releases 下载harbor的离线版本 ```bash [root@localhost ~]# wget https://github.com/goharbor/harbor/releases/download/v1.10.1/harbor-offline-installer-v1.10.1.tgz ``` 安装依赖 ```bash [root@localhost harbor]# yum install docker-compose -y # docker也是必须的 ``` #### docker-compose用法 在包含 `docker-compose.yml` 的目录下执行 基本命令: - `-p` 指定项目名称 - `build` 构建项目中的服务容器 –force-rm 删除构建过程中的临时容器 - `--no-cache` 构建过程中不使用 cache - `--pull` 始终通过 pull 来获取更新版本的镜像 - `docker-compose kill` 强制停止服务容器 - `docker-compose logs` 查看容器的输出 调试必备 - `docker-compose pause` 暂停一个服务容器 - `docker-compose unpause` 恢复暂停 - `docker-compose port` 打印某个容器端口所映射的公共端口 - `docker-compose ps` 列出项目中目前的所有容器 -q 只打印容器 id - `docker-compose pull` 拉取服务依赖的镜像 - `docker-compose restart -t` 指定重启前停止容器的超时默认10秒 - `docker-compose rm` 删除所有停止状态的容器先执行 stop - `docker-compose run` 指定服务上执行一个命令 - `docker-compose start` 启动已经存在的服务容器 - `docker-compose stop` 停止已经存在的服务容器 - `docker-compose up` 自动构建、创建服务、启动服务,关联一系列,运行在前台,ctrl c 就都停止运行。如果容器已经存在,将会尝试停止容器,重新创建。如果不希望重新创建,可以 `--no-recreate` 就只启动处于停止状态的容器,如果只想重新部署某个服务,可以使用 - `docker-compose up --no-deps -d` ,不影响其所依赖的服务 - `docker-compose up -d` 后台启动运行,生产环境必备 - `docker-compose down` 停止并删除容器 ### 解压harbor ```bash [root@localhost ~]# tar -zxvf harbor-offline-installer-v1.10.1.tgz [root@localhost ~]# cd harbor [root@localhost harbor]# ls common docker-compose.clair.yml docker-compose.notary.yml docker-compose.yml ha harbor.cfg harbor.v1.10.1.tar.gz install.sh LICENSE NOTICE prepare ``` ### 修改harbor.cfg ```bash [root@localhost harbor]# vim harbor.cfg hostname = 192.168.99.102:12345 # 写你自己的网址或IP,公网访问要写公网IP,如果知名端口,默认运行在80或443 customize_crt = off # 支持http访问 ``` 如果修改了监听的默认端口,那么`docker-compose.yml`也需要修改`proxy---ports`的端口`- 12345:80` 另外还有mysql、harbor等默认密码配置或其他相关参数设置。 ### 安装 修改配置之后,进行安装 方式一:运行 `./install.sh`安装,然后`docker ps`查看运行的服务 或集成clair漏洞扫描:`./install.sh --with-clair`(该功能用于页面上进行漏洞扫描,push镜像后点击扫描后,页面提示`TypeError: Cannot set property 'scan_status' of undefined`是正常的,他会后台扫描,过一会就有结果了),[参考Harbor仓库镜像扫描原理](https://www.youendless.com/post/harbor_image_scan/) 脚本会自动解压镜像文件并运行`docker-compose` 方式二:或者运行`./prepare`文件(修改配置文件之后需要重新生成一些内置配置),再手动运行`docker-compose up -d` ```bash [root@localhost harbor]# ./install.sh [Step 0]: checking installation environment ... Note: docker version: 19.03.7 Note: docker-compose version: 1.18.0 [Step 1]: preparing environment ... Clearing the configuration file: ./common/config/adminserver/env Clearing the configuration file: ./common/config/ui/env Clearing the configuration file: ./common/config/ui/app.conf Clearing the configuration file: ./common/config/ui/private_key.pem Clearing the configuration file: ./common/config/db/env Clearing the configuration file: ./common/config/jobservice/env Clearing the configuration file: ./common/config/jobservice/config.yml Clearing the configuration file: ./common/config/registry/config.yml Clearing the configuration file: ./common/config/registry/root.crt Clearing the configuration file: ./common/config/nginx/nginx.conf Clearing the configuration file: ./common/config/log/logrotate.conf loaded secret from file: /data/secretkey Generated configuration file: ./common/config/nginx/nginx.conf Generated configuration file: ./common/config/adminserver/env Generated configuration file: ./common/config/ui/env Generated configuration file: ./common/config/registry/config.yml Generated configuration file: ./common/config/db/env Generated configuration file: ./common/config/jobservice/env Generated configuration file: ./common/config/jobservice/config.yml Generated configuration file: ./common/config/log/logrotate.conf Generated configuration file: ./common/config/jobservice/config.yml Generated configuration file: ./common/config/ui/app.conf Copied configuration file: ./common/config/uiprivate_key.pem Copied configuration file: ./common/config/registryroot.crt The configuration files are ready, please use docker-compose to start the service. [Step 2]: checking existing instance of Harbor ... Note: stopping existing Harbor instance ... Stopping harbor-jobservice ... done Stopping nginx ... done Stopping harbor-ui ... done Stopping harbor-db ... done Stopping harbor-adminserver ... done Stopping registry ... done Stopping redis ... done Stopping harbor-log ... done Removing harbor-jobservice ... done Removing nginx ... done Removing harbor-ui ... done Removing harbor-db ... done Removing harbor-adminserver ... done Removing registry ... done Creating harbor-log ... done Removing harbor-log ... done Removing network harbor_harbor Creating harbor-db ... done Creating harbor-ui ... done Creating network "harbor_harbor" with the default driver Creating nginx ... done Creating registry ... Creating harbor-adminserver ... Creating redis ... Creating harbor-db ... Creating harbor-ui ... Creating harbor-jobservice ... Creating nginx ... ✔ ----Harbor has been installed and started successfully.---- Now you should be able to visit the admin portal at http://192.168.99.102:12345. For more details, please visit https://github.com/vmware/harbor . ``` ### 查看镜像和容器 ```bash [root@localhost harbor]# docker images | grep -E "TAG|vmware" REPOSITORY TAG IMAGE ID CREATED SIZE vmware/redis-photon v1.5.0 7c03076402d9 22 months ago 207MB vmware/registry-photon v2.6.2-v1.5.0 3059f44f4b9a 22 months ago 198MB vmware/nginx-photon v1.5.0 e100456182fc 22 months ago 135MB vmware/harbor-log v1.5.0 62bb6b8350d9 22 months ago 200MB vmware/harbor-jobservice v1.5.0 aca9fd2e867f 22 months ago 194MB vmware/harbor-ui v1.5.0 1055166068d0 22 months ago 212MB vmware/harbor-adminserver v1.5.0 019bc4544829 22 months ago 183MB vmware/harbor-db v1.5.0 82354dcf564f 22 months ago 526MB ``` - `redis-photon`:redis存储 - `registry-photon`:方的Docker registry,负责保存镜像 - `nginx-photon`:负责流量转发和安全验证 - `harbor-log`:harbor的日志收集、管理服务 - `harbor-jobservice`:harbor的任务管理服务 - `harbor-ui`:harbor的web页面服务 - `harbor-adminserver`:harbor系统管理服务 - `harbor-db`:由官方mysql镜像构成的数据库容器 ```bash [root@localhost harbor]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2dc70e644f66 vmware/nginx-photon:v1.5.0 "nginx -g 'daemon of…" 28 minutes ago Up About a minute (healthy) 0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:12345->80/tcp nginx 0ec9e6ed62c8 vmware/harbor-jobservice:v1.5.0 "/harbor/start.sh" 28 minutes ago Up About a minute harbor-jobservice 6147e6c61c93 vmware/harbor-ui:v1.5.0 "/harbor/start.sh" 28 minutes ago Up About a minute (healthy) harbor-ui e47ad932ddf9 vmware/redis-photon:v1.5.0 "docker-entrypoint.s…" 28 minutes ago Up About a minute 6379/tcp redis af5110e4f9f9 vmware/registry-photon:v2.6.2-v1.5.0 "/entrypoint.sh serv…" 28 minutes ago Up About a minute (healthy) 5000/tcp registry 618a122905a6 vmware/harbor-adminserver:v1.5.0 "/harbor/start.sh" 28 minutes ago Up About a minute (healthy) harbor-adminserver b8daf49a5cc7 vmware/harbor-db:v1.5.0 "/usr/local/bin/dock…" 28 minutes ago Up About a minute (healthy) 3306/tcp harbor-db 86048aad6913 vmware/harbor-log:v1.5.0 "/bin/sh -c /usr/loc…" 28 minutes ago Up About a minute (healthy) 127.0.0.1:1514->10514/tcp harbor-log ``` ### 查看Harbor状态 ```bash [root@localhost harbor]# docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------------------------- harbor-adminserver /harbor/start.sh Up harbor-db /usr/local/bin/docker-entr ... Up 3306/tcp harbor-jobservice /harbor/start.sh Up harbor-log /bin/sh -c /usr/local/bin/ ... Up 127.0.0.1:1514->10514/tcp harbor-ui /harbor/start.sh Up nginx nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:12345->80/tcp redis docker-entrypoint.sh redis ... Up 6379/tcp registry /entrypoint.sh serve /etc/ ... Up 5000/tcp ``` ### Web访问 防火墙允许端口,外部访问 http://192.168.99.102:12345/harbor/sign-in ```bash [root@localhost harbor]# firewall-cmd --zone=public --add-port=12345/tcp success ``` 帐号密码默认是 `admin/Harbor12345`,这都可以在`harbor.cfg`配置的 ### push镜像 ```bash # 登录 [root@localhost harbor]# docker login -u admin 192.168.99.102:12345 Password: Error response from daemon: Get https://192.168.99.102:12345/v2/: http: server gave HTTP response to HTTPS client ``` #### 登录http: server gave HTTP response to HTTPS client 多次`docker login`被refuse 这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 配置来取消这个限制,或者配置能够通过 HTTPS 访问的私有仓库。 ```bash [root@localhost harbor]# vim /etc/docker/daemon.json [root@localhost harbor]# cat /etc/docker/daemon.json { "registry-mirrors": [ "https://dockerhub.azk8s.cn", "https://hub-mirror.c.163.com" ], "insecure-registries":["192.168.99.102:5000","192.168.99.102:12345"] } [root@localhost harbor]# systemctl reload docker [root@localhost harbor]# docker info # ... Insecure Registries: 192.168.99.102:12345 192.168.99.102:5000 127.0.0.0/8 # 可以看到使用reload后,添加了 # ... ``` 再次登录 ```bash [root@localhost harbor]# docker login -u admin 192.168.99.102:12345 Password: Error response from daemon: Get http://192.168.99.102:12345/v2/: unauthorized: authentication required ``` #### 登录unauthorized: authentication required 首先检查login的**用户名,密码**是否一定正确。 检查`common/templates/registry/config.yml`配置文件中`auth-token-realm`的认证地址是否有更新 ```bash [root@localhost harbor]# cat ./common/config/registry/config.yml # ... auth: token: issuer: harbor-token-issuer realm: http://192.168.99.102:12345/service/token rootcertbundle: /etc/registry/root.crt service: harbor-registry ``` 当修改过`harbor.cfg`配置文件时,需要使用`./prepare`脚本更新配置文件 ```bash [root@localhost harbor]# ./prepare ``` #### 正常登录并push ```bash [root@localhost harbor]# docker login -u admin 192.168.99.102:12345 Password: # Harbor12345 WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded ``` 访问 http://192.168.99.102:12345/harbor/projects 创建项目,例如`starmeow`,查看详情,鼠标移动到“推送镜像”上可以看到推送链接 ```bash [root@localhost harbor]# docker images | grep -E "TAG|hello-world" REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest fce289e99eb9 14 months ago 1.84kB # 标记推送的镜像 [root@localhost harbor]# docker tag hello-world:latest 192.168.99.102:12345/starmeow/hello-world:1.2 # 查看被标记的镜像 [root@localhost harbor]# docker images | grep -E "TAG|hello-world" REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.99.102:12345/starmeow/hello-world 1.2 fce289e99eb9 14 months ago 1.84kB hello-world latest fce289e99eb9 14 months ago 1.84kB # 开始推送 [root@localhost harbor]# docker push 192.168.99.102:12345/starmeow/hello-world:1.2 The push refers to repository [192.168.99.102:12345/starmeow/hello-world] af0b15c8625b: Pushed 1.2: digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a size: 524 ``` ### Harbor日志 ```bash [root@localhost harbor]# tail -n 30 /var/log/harbor/ adminserver.log clair-db.log clair.log jobservice.log mysql.log proxy.log redis.log registry.log ui.log ``` ### 启停harbor 需要进入harbor解压文件内,用到`Supported filenames: docker-compose.yml, docker-compose.yaml`这种yml文件,否则就`-f`指定yml文件。 - 停止服务: `docker-compose stop`或`docker-compose -f docker-compose.yml stop` ```bash Stopping nginx ... done Stopping harbor-jobservice ... done Stopping harbor-ui ... done Stopping redis ... done Stopping registry ... done Stopping harbor-adminserver ... done Stopping harbor-db ... done Stopping harbor-log ... done ``` - 开始服务: `docker-compose start`或`docker-compose -f docker-compose.yml start` ```bash Starting log ... done Starting registry ... done Starting mysql ... done Starting adminserver ... done Starting ui ... done Starting redis ... done Starting jobservice ... done Starting proxy ... done ```
很赞哦! (0)
相关文章
文章交流
- emoji