为啥要用Docker?这要从目前软件行业的痛点来讲起
1、软件更新发布及部署低效,过程繁琐且需要人工介入 2、环境一致性难以保证 3、不同环境之间迁移成本太高
有了Docker可以很大程度解决上面的问题。
- 首先,Docker的使用简单至极,从开发的角度来看就是三步走:构建,运输,运行。其中关键步骤就是构建环节,即打包镜像文件。但是从测试和运维的角度来看,那就只有两步:复制,运行。有了这个镜像,那么想复制到哪运行都可以,完全和平台无关了。同时Docker这种容器技术隔离出了独立的运行空间,不会和其他应用争用系统资源了以及还不需要考虑应用之间相互影响,想想就开心。
- 其次,因为在构建镜像的时候就处理完了服务程序对于系统的所有依赖,所以在你使用的时候,你可以忽略掉原本程序的依赖以及开发语言。对测试和运维而言,更多专注于自己的业务内容上。
- 最后,Docker于开发者而言提供了一种开发环境的管理办法,与测试人员而言保证了环境的同步,于运维人员提供了可移植的标准化部署流程。
- 构建容易分发简单
- 隔离应用解除依赖
- 快速部署测完就销
1. 本地依赖(Local Dependency)
你需要在本地系统快速尝试 Magento,或者为一个项目使用 MySQL?还是希望尝试大部分开源项目?那就使用 Docker 吧,它将帮你节省大量时间。Docker 能提升开发者的开发效率,让我们快速搭建开发环境。 开发环境的机器通常内存比较小,此前使用虚拟的时候,经常需要为开发环境的机器加内存,而通过 Docker 可以轻易的让几十个服务在 Docker 中跑起来。
2. 搭建环境(Build Environment)
如果你希望构建源码,但发现没有准备好合适的环境。 那么使用 Docker是一个值得考虑的方案。毕竟如果使用传统的方法一个一个地安装软件,一大堆软件安装下来确实十分费时间,使用容器技术省时省力,何乐而不为?它能让你将运行环境和配置放在代码中然后部署,同一个 Docker 的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。这里有一个值得一看的例子: docker golang builder。
3. 微服务(Microservices)
你在使用微服务吗?微服务架构将一个整体式的应用拆分成松耦合的单个服务。 那不妨考虑一下 Docker,你可以将每个服务打包为一个docker镜像并使用docker-compose 来模拟生产环境(checkout docker networks)。最开始实践的时候可能会比较费时费力,但长远地来看,最终将产生巨大的生产力。
4. 自动测试(Automated testing)
试想这样一个问题,如何编写自动化的集成测试用例,这些测试用例无需花很长时间来开始运行,使用者也可轻松管理。这里不是指在 Docker 中运行测试用例,而是将测试用例与镜像紧密运行在一起。当你针对一个 docker 镜像编写测试用例时会有一个很大的优势。下面简单介绍一下我的测试流程:运行两个 docker 镜像(app + db),在 MySQL 启动时加载数据,并在 app docker 上使用 API。可查看此脚本以获取快速的示例。
5. 部署过程(Deployment process)
你可以使用 docker 镜像进行自我部署。许多主流的主机提供商都支持托管 docker,如果你拥有一个具有 shell 访问权限的专用节点/vm,那么事情将变得更容易。只需要设置好docker,并在你想要的端口上运行你的镜像即可。
6. 持续部署(Continuous Deployment)
都说 Docker 天生适合持续集成/持续部署,在部署中使用Docker,持续部署将变得非常简单,并会在进入新的镜像后重新开始。关于这个部分的自动化工作,现在已经有许多方案以供选择,Kubernetes就是一个耳熟能详的名字。Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
7. 多租户环境(Multi-tenancy)
Docker 有意思的一个使用场景是在多租户的应用中,它可以避免关键应用的重写。如果你将应用程序服务公开给多个租户(租户指一组用户,例如组织),使用单租户方案设计的应用程序如果用上了 sub-domain + docker 可以快速获得提供多租户的服务。 关于这个场景的一个例子是为物联网的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于 Docker 环境的启动速度和其高效的 diff 命令。
8. 来自一台机器的多个 APP(Multiple apps from one machine)
这与上面提到的微服务有些联系,但即使你没有使用微服务,只是提供服务,Docker仍可以很好地管理单个机器上的所有服务。你应该使用文件夹挂载来为每个基于数据的 docker 镜像保留数据。
9. 扩容 QPS(Scaling QPS)
Docker 通过创建另一个容器来帮助你轻松地进行水平扩展。如果遇到巨大的高峰流量,Docker可以帮助你解决问题 —— 只需添加更多的机器并增加负载均衡器背后运行的容器数量。
特性 | 普通虚拟机 | Docker |
---|---|---|
跨平台 | 通常只能在桌面级系统运行,例如 Windows/Mac,无法在不带图形界面的服务器上运行 | 支持的系统非常多,各类 windows 和 Linux 都支持 |
性能 | 性能损耗大,内存占用高,因为是把整个完整系统都虚拟出来了 | 性能好,只虚拟软件所需运行环境,最大化减少没用的配置 |
自动化 | 需要手动安装所有东西 | 一个命令就可以自动部署好所需环境 |
稳定性 | 稳定性不高,不同系统差异大 | 稳定性好,不同系统都一样部署方式 |
打包:就是把你软件运行所需的依赖、第三方库、软件打包到一起,变成一个安装包 分发:你可以把你打包好的“安装包”上传到一个镜像仓库,其他人可以非常方便的获取和安装 部署:拿着“安装包”就可以一个命令运行起来你的应用,自动模拟出一摸一样的运行环境,不管是在 Windows/Mac/Linux。
常规应用开发部署方式:自己在 Windows 上开发、测试 --> 到 Linux 服务器配置运行环境部署。
问题:我机器上跑都没问题,怎么到服务器就各种问题了
用 Docker 开发部署流程:自己在 Windows 上开发、测试 --> 打包为 Docker 镜像(可以理解为软件安装包) --> 各种服务器上只需要一个命令部署好
优点:确保了不同机器上跑都是一致的运行环境,不会出现我机器上跑正常,你机器跑就有问题的情况。
操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。 镜像实际是由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。
比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等 。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。前面讲过镜像使用的是分层存储,容器也是如此。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此, 使用数据卷后,容器可以随意删除、重新run,数据却不会丢失。
注意:
容器在整个应用程序生命周期工作流中提供以下优点:隔离性、可移植性、灵活性、可伸缩性和可控性。 最重要的优点是可在开发和运营之间提供隔离。
镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其他服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。所以说,镜像仓库是 Docker 用来集中存放镜像文件的地方,类似于我们之前常用的代码仓库。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。
我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
这里补充一下 Docker Registry 公开服务和私有 Docker Registry 的概念:Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。最常使用的 Registry 公开服务是官方的 Docker Hub ,这也是默认的 Registry,并拥有大量的高质量的官方镜像,网址为:hub.docker.com 。
在国内访问 Docker Hub 可能会比较慢,国内也有一些云服务商提供类似于 Docker Hub 的公开服务。
除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry 。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 Docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。
需要正确的理解仓库/镜像/容器这几个概念:
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
image文件可以看作是容器的模板。Docker 根据image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
镜像文件
image 文件生成的容器实例,本身也是一个文件,称为镜像文件。
容器实例
一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器
仓库
就是放一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了。
桌面版:https://www.docker.com/products/docker-desktop 服务器版:https://docs.docker.com/engine/install/#server
目前,CentOS仅发行版本中的内核支持Docker。Docker运行在CentOS 7 (64-bit)上,要求系统为64位、Linux系统内核版本为3.8以上,这里选用Centos7.x。在Linux上运行uname
命令查看系统内核版本。
[root@yaochuang ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
[root@yaochuang ~]# uname -r
3.10.0-1160.el7.x86_64
Docker如今划分成了2个版本:
社区版并非阉割版,而是改了个名称;非常适合开发人员和运维团队构建容器APP。
企业版则提供了一些收费的高级特性。可在经过认证的操作系统和云提供商中使用。
一般都会选择Docker CE(社区版),因为CE版本是开源免费的。对于大多数企业公司都比较节约成本。
这里我们就选择第一种方式进行安装,这也是推荐的做法。
至于其他的安装方式,可自行网上学习,这里不做过多讲解。
A. CentOS7安装Docker官方文档
https://docs.docker.com/engine/install/centos/
B. 确定Linux版本必须是CentOS7及以上
[root@localhost ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
[root@localhost ~]# uname -r
3.10.0-1160.el7.x86_64
C. 卸载旧版本
旧版本的 Docker 被称为docker
或docker-engine
. 如果安装了这些,请卸载它们以及相关的依赖项。
# 第一次安装不需要执行此命令
·
D. 设置存储库
安装所需的包。 yum-utils提供yum-config-manager实用程序,devicemapper存储驱动程序需要device-mapper-persistent-data和lvm2。
yum install -y yum-utils device-mapper-persistent-data lvm2
E. 指定Docker镜像源
默认下载Docker回去国外服务器下载,速度较慢,我们可以设置为阿里云镜像源,速度更快
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
F. 安装最新版的Docker CE
yum install docker-ce
稍作等待,当命令行最终输出“Complete!
”或者“完毕!
”即表示安装完成。
G. 启动Docker
systemctl start docker
H. 验证Docker是否安装成功 最简单的验证方式,就是使用 docker version 命令,类似于JDK的 java -version 一样的道理。 Docker安装成功的话,就可以直接在命令行运行Docker的命令的。
docker version
如果出现如下信息,说明Docker以及安装成功了!
[root@yaochuang ~]# docker version
Client: Docker Engine - Community
Version: 20.10.18
API version: 1.41
Go version: go1.18.6
Git commit: b40c2f6
Built: Thu Sep 8 23:14:08 2022
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.18
API version: 1.41 (minimum version 1.12)
Go version: go1.18.6
Git commit: e42327a
Built: Thu Sep 8 23:12:21 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.8
GitCommit: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
【可选】:当然,你也可以通过运行 hello-world 映像来检验Docker是否安装成功:
docker run hello-world
上面的命令含义:下载官方提供的用于测试使用的hello-world镜像并将其运行到容器中,来检验Docker服务是否正常安装并运行。
执行上面的命令之后,Docker会自动下载hello-world镜像并自动运行到容器中,当命令行中出现“Hello from Docker!”的字样,说明已经成功运行了hello-world镜像,一切就OK了!
Docker CE安装成功之后,你可以发现 /var/lib 目录下有一个 docker 目录,你可以进入Docker目录查看Docker的一些结构,如下图所示:
其中有一个containers 目录,这个目录就是存放Docker容器的。上面我们有提及到 hello-world 镜像,如果你运行了 hello-world 镜像,那么这个镜像所生成的容器信息,就会存储在 containers 目录中。
1、通过在命令行中执行以下命令,即可实现Docker服务的启动。当服务器重启的时候,Docker服务需要手工去启动。
systemctl start docker
2、自动启动
systemctl enable docker
systemctl stop docker
yum remove docker-ce
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
登录阿里云:https://promotion.aliyun.com/ntms/act/kubernetes.html
针对Docker客户端版本大于 1.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器。
注意将https://rxxxxxx0.mirror.aliyuncs.com
修改为自己的地址。
# 分步骤执行
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://rxxxxxx0.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开机启动: systemctl enable docker
查看docker概要信息: docker info
查看docker总体帮助文档: docker --help
查看docker命令帮助文档: docker 具体命令--help
docker [OPTIONS] images
OPTIONS说明:
[root@yaochuang ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 12 months ago 13.3kB
选项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
docker search redis
OPTIONS说明:
[root@yaochuang ~]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
2b55860d4c66: Pull complete
Digest: sha256:20fa2d7bb4de7723f542be5923b06c4d704370f0390e4ae9e1c833544c1
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
[root@yaochuang ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 2dc39ba059dc 3 weeks ago 77.8MB
hello-world latest feb5d9fea6a5 12 months ago 13.3kB
[root@yaochuang ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 1 77.85MB 77.83MB (99%)
Containers 2 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
# 删除镜像
docker rmi -f 镜像ID
# 删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
# 删除全部
docker rmi -f $(docker images -qa)
构建和删除镜像时出现错误,导致仓库名(REPOSITORY)、标签(TAG)都是的镜像,俗称虚悬镜像dangling image。
# 删除虚悬镜像
docker image prune
本次演示用ubuntu演示
有镜像才能创建容器, 这是根本前提(下载一个CentOS或者ubuntu镜像演示)
docker pull centos
docker pull ubuntu
运行容器需要指定具体镜像,如果镜像不存在,会直接下载
# 简单操作
docker run 镜像的标识|镜像名称[:tag]
# 常用的参数
docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像的标识|镜像名称[:tag]
docker run -d -p 8081:8080 --name tomcat b8
OPTIONS说明:
--name="容器新名字"为容器指定一个名称;
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
# 使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
docker run -it centos /bin/bash
参数说明:
centos : centos 镜像。
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
要退出终端,直接输入exit
注意:有镜像才能创建容器,这是根本前提(下载一个Redis6.0.8镜像演示)
在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的后台运行模式。
docker run -d 容器名
#使用镜像centos:latest以后台模式启动一个容器
docker run -d centos
问题:然后docker ps -a 进行查看, 会发现容器已经退出。 注意:Docker容器后台运行,就必须有一个前台进程。 容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start。但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀因为他觉得他没事可做了,所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有交互操作,别中断。
# 前台交互式启动
[root@dk ~]# docker run -it redis:6.0.8
# 后台守护式启动
[root@dk ~]# docker run -d redis:6.0.8
# 查看容器日志
[root@dk ~]# docker logs 容器ID
# 查看容器内运行的进程
[root@dk ~]# docker top 容器ID
# 查看容器内部细节
[root@dk ~]# docker inspect 容器ID
docker ps [OPTIONS]
OPTIONS说明:
方式 | 结果 | 再次启动 |
---|---|---|
exit(命令) | 退出后,这个容器也就消失了,容器销毁ps查不到 | docker start 容器名/容器ID |
Ctrl + D(快捷方式) | 退出后,这个容器也就消失了,容器销毁ps查不到 | docker start 容器名/容器ID |
先按Ctrl + P,再按Ctrl + Q(快捷方式) | 退出容器,ps能查到,还在后台运行 | docker attach 容器名/容器ID |
# 重新启动容器
docker restart 容器ID或者容器名 # 启动停止运行的容器
docker stop 容器ID或者容器名 # 停止指定容器
docker rm 容器ID或者容器名 # 删除全部容器docker rm $(docker ps -qa)
docker kill 容器ID或容器名 # 强制停止容器
docker rm -f $(docker ps -qa) # 一次性删除多个容器实例
docker ps -a -q | xargs docker rm
首先启动容器:
# 以交互式模式在后台运行ubuntu
[root@dk ~]# docker run -itd ubuntu /bin/bash
659360a3583c2aa96dc420307af704c8efdf59723f4014704ed9f4c1431fc954
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
[root@dk ~]# docker attach 659360a3583c
# 进入正在运行的容器并以命令行交互,只有容器正在运行才能执行成功!
[root@dk ~]# docker exec -it 659360a3583c /bin/bash
总结:一般用-d后台启动的程序,再用exec进入对应容器实例
语法格式如下:
docker cp 容器ID:容器内路径 目的主机路径
# 1. 运行ubuntu
[root@dk ~]# docker run -itd ubuntu /bin/bash
61eb9ff76e82442175c128018eda7958f278b742adf3fb9e98b5d68039f34c52
# 2. 查看正在运行的容器
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
61eb9ff76e82 ubuntu "/bin/bash" 6 seconds ago Up 3 seconds my_shk
# 3. 重新进去容器
[root@dk ~]# docker exec -it 61eb9ff76e82 /bin/bash
# 4. 进入ubuntu容器后创建文件
root@61eb9ff76e82:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@61eb9ff76e82:/# cd home
root@61eb9ff76e82:/home# echo hello ubuntu >> ubuntu.txt
root@61eb9ff76e82:/home# cat ubuntu.txt
hello ubuntu
# 5. 退出ubuntu容器,此操作并不会真正退出容器。容器会继续在后台运行
root@61eb9ff76e82:/home# exit
exit
# 6. 执行复制的操作
[root@dk ~]# docker cp 61eb9ff76e82:/home/ubuntu.txt /home
# 7. 查看结果
[root@dk ~]# cat /home/ubuntu.txt
hello ubuntu
示例:
#将物理主机中的/data/index.html拷贝到容器bd96d72ed9c7:/web/目录下
[root@dk ~]# docker cp /data/index.html bd96d72ed9c7:/web/
#将物理主机中的/data/index.html拷贝到容器bd96d72ed9c7:/web/目录下并改名为index.php
[root@dk ~]# docker cp /data/index.html bd96d72ed9c7:/web/index.php
#拷贝容器bd96d72ed9c7:/web/目录到物理主机中的/data/目录下
[root@dk ~]# docker cp bd96d72ed9c7:/web /data/
# 语法格式如下:
[root@dk ~]# docker export 容器ID > 文件名.tar
# 案例
# 1. 运行镜像创建容器
[root@dk ~]# docker run -itd ubuntu /bin/bash
450d0315404c5042a4f7ebad233b9ce5235897c6069e234e5c5b4cfaa816c025
# 2. 查看正在运行的容器
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
450d0315404c ubuntu "/bin/bash" 5 seconds ago Up 3 seconds gallant_raman
# 3. 导出容器
[root@dk ~]# docker export 450d0315404c > ubuntu.tar
# 4. 查看导出文件
[root@dk ~]# ls
anaconda-ks.cfg ubuntu.tar
# 语法格式如下:
[root@dk ~]# cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
# 案例
# 1. 可以先删除ubuntu镜像,也可以不删除。因为后面导入时重新设置了版本不冲突
[root@dk ~]# docker rmi -f ubuntu
# 2. 导入镜像
[root@dk ~]# cat /root/ubuntu.tar | docker import - test/ubuntu:v1
sha256:ede897f1dc208a1f738d4afd1639ebcfc34f91e49845f2ac5dc4f94a0a8ddfc9
# 3. 查看导入的镜像
[root@dk ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu v1 ede897f1dc20 6 seconds ago 77.8MB
tomcat latest ab37a470285a 27 hours ago 474MB
mysql 5.7 eef0fab001e8 3 days ago 495MB
mysql latest 2a04bf34fdf0 3 days ago 535MB
ubuntu latest a8780b506fa4 6 days ago 77.8MB
hello-world latest feb5d9fea6a5 13 months ago 13.3kB
centos latest 5d0da3dc9764 13 months ago 231MB
attach Attach to a running container # 当前 shell 下 attach 连接指定运行容器
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container's filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值
镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M?
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
docker commit提交容器副本使之成为一个新的镜像
# 语法格式为:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
# 案例演示ubuntu安装vim
# 1. 从Hub上下载ubuntu镜像到本地并成功运行,原始的默认Ubuntu镜像是不带着vim命令的
[root@dk ~]# docker run -itd ubuntu /bin/bash
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ad2545ddc9f ubuntu "/bin/bash" 8 seconds ago Up 5 seconds laughing_wilson
# 2. 外网连通的情况下,安装vim
[root@dk ~]# docker exec -it 5ad2545ddc9f /bin/bash
# 3. 更新包管理工具
root@5ad2545ddc9f:/# apt-get update
# 4. 安装vim
root@5ad2545ddc9f:/# apt-get -y install vim
# 5. 安装完成后commit我们自己的新镜像
[root@dk ~]# docker commit -m="add my images" -a="yaochuang" 5ad2545ddc9f yao/myubuntu:1.1
# 6. 查看自己的镜像,可以看到yao/myubuntu已经发布成功了
[root@dk ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yao/myubuntu 1.1 5ea55b97dc36 5 seconds ago 177MB
test/ubuntu v1 ede897f1dc20 2 hours ago 77.8MB
tomcat latest ab37a470285a 29 hours ago 474MB
mysql 5.7 eef0fab001e8 4 days ago 495MB
mysql latest 2a04bf34fdf0 4 days ago 535MB
ubuntu latest a8780b506fa4 6 days ago 77.8MB
hello-world latest feb5d9fea6a5 13 months ago 13.3kB
centos latest 5d0da3dc9764 13 months ago 231MB
# 7. 重新运行自己发布的镜像文件
[root@dk ~]# docker run -itd yao/mybubuntu:1.1 /bin/bash
668079fcda31acaddd39396b6e013ac8fad90591ad9047f1b3df61d363d12717
# 8. 进入自己发布的容器
[root@dk ~]# docker exec -it 668079fcda31 /bin/bash
# 9. 此时再使用vim编辑器
root@668079fcda31:/# vim a
官网是默认下载的Ubuntu没有vim命令
我们自己commit构建的镜像,新增加了vim功能,可以成功使用。
总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
Docker 容器经历以下阶段:
(1)打开链接:https://promotion.aliyun.com/ntms/act/kubernetes.html,登录阿里云开发者平台
(1)登录阿里云
(2)选择容器镜像服务
(3)创建命名空间
(4)创建镜像仓库
(5)选择管理
获取脚本信息
$ docker login --username=no***@live.com registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/noyao/myubuntu:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/noyao/myubuntu:[镜像版本号]
具体运行效果如下图所示:
检查阿里云上的镜像仓库
# 先删除本地已存在的镜像
[root@dk ~]# docker rmi -f 5ea55b97dc36
Untagged: yao/mybubuntu:1.1
Untagged: registry.cn-hangzhou.aliyuncs.com/noyao/myubuntu:1.1
Untagged: registry.cn-hangzhou.aliyuncs.com/noyao/myubuntu@sha256:102746278de36b7c9093a5b2b56abd6ffa66f656192127e912c7d4f070b46e2a
Deleted: sha256:5ea55b97dc36e138a84efaea893ab904c7c36e7963114eedb7ddeafb512c88a9
[root@dk ~]# docker pull registry.cn-hangzhou.aliyuncs.com/noyao/myubuntu:1.1
[root@dk ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
213ec9aee27d: Pull complete
4583459ba037: Pull complete
6f6a6c5733af: Pull complete
b136d5c19b1d: Pull complete
fd4a5435f342: Pull complete
Digest: sha256:de4b7d974220231c29828d2a643b7dac3186746eb91f4d688438680bf0ebaf60
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
# 此命令现在暂时无需了解,后面第7章再做说明
[root@dk ~]# docker run -d -p 5000:5000 -v /noyao/myregistry/:/tmp/registry --privileged=true registry
8756168da5688dbe17c61fcfed5f72b9e084ba404e872024d0201bcadce92e0d
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
ifconfig(接口配置)是一个网络管理工具。它用于在Linux操作系统中配置和查看网络接口的状态。使用ifconfig可以分配IP地址、启用或禁用接口、管理ARP缓存、路由等。
[root@dk ~]# docker run -it ubuntu /bin/bash
root@605767afd7aa:/# ipconfig
bash: ipconfig: command not found
root@605767afd7aa:/# apt-get update
root@605767afd7aa:/# apt-get install net-tools
root@605767afd7aa:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 9878 bytes 25245740 (25.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8793 bytes 480864 (480.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 退出容器,不记得命令请回顾3.4章节
# 公式:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
# 命令:在容器外执行,记得
[root@dk ~]# docker commit -m="添加ifconfig命令" -a="yaochuang" abdef7cbf113 ycubuntu:1.2
官网是默认下载的Ubuntu没有ifconfig命令
我们自己commit构建的新镜像,新增加了ifconfig功能,可以成功使用。
[root@dk ~]# docker images
[root@dk ~]# docker run -it ycubuntu:1.2 /bin/bash
root@6fbe42982759:/# ifconfig
curl命令 是一个利用URL规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称curl为下载工具。作为一款强力工具,curl支持包括HTTP、HTTPS、ftp等众多协议,还支持POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。做网页处理流程和数据检索自动化,curl可以助你一臂之力。
# -X:(HTTP)指定与服务器通信使用的请求方法,如:GET、PUT、POST、DELETE等,默认GET
[root@dk ~]# curl -XGET http://192.168.170.151:5000/v2/_catalog
{"repositories":[]}
可以看到目前私服库没有任何镜像上传过,继续看下面的步骤!
# 公式:
docker tag 镜像:Tag Host:Port/Repository:Tag
# 自己host主机IP地址,填写同学你们自己的,不要粘贴错误
# 使用命令 docker tag 将ycubuntu:1.2 这个镜像修改为192.168.170.151:5000/ycubuntu:1.2
[root@dk ~]# docker tag ycubuntu:1.2 192.168.170.151:5000/ycubuntu:1.2
# registry-mirrors 配置的是国内阿里提供的镜像加速地址,不用加速的话访问官网的会很慢。
# 2个配置中间有个逗号 ','别漏了,这个配置是json格式的。
[root@dk ~]# cat /etc/docker/daemon.json
{
"registry-mirrors":["https://aa25jngu.mirror.aliyuncs.com"],
"insecure-registries":["192.168.170.151:5000"]
}
上述理由:docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。 修改完后重启docker。
# 重启docker
[root@dk ~]# systemctl restart docker
# 运行私有库
[root@dk ~]# docker run -d -p 5000:5000 -v /noyao/myregistry/:/tmp/registry --privileged=true registry
[root@dk ~]# docker push 192.168.170.151:5000/ycubuntu:1.2
The push refers to repository [192.168.170.151:5000/ycubuntu]
d2126fedd4bd: Pushed
f4a670ac65b6: Pushed
1.2: digest: sha256:7cd62eb5e172572d793a343834adeaa722d2fa0f1990da54e9e7ceddfd04312c size: 741
[root@dk ~]# curl -XGET http://192.168.170.151:5000/v2/_catalog
{"repositories":["ycubuntu"]}
[root@dk ~]# docker pull 192.168.170.151:5000/ycubuntu:1.2
# 语法如下:
[root@dk ~]# docker run -it 镜像ID /bin/bash
# 镜像ID记得更换为自己的
[root@dk ~]# docker run -it 466572ffe865 /bin/bash
# 输入ifconfig查看信息
root@8097570fad7a:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 8 bytes 656 (656.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 删除仓库容器/var/lib/registry/docker/registry/v2/repositories/下面的镜像目录
docker exec 容器仓库ID rm -rf /var/lib/registry/docker/registry/v2/repositories/镜像名称
# 垃圾回收
docker exec 容器仓库ID bin/registry garbage-collect /etc/docker/registry/config.yml
# 重启仓库
docker restart 容器仓库ID
# 查看镜像
--privileged=true
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true
参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用--privileged=true
命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
[root@dk ~]# docker run -d -p 5000:5000 -v /noyao/myregistry/:/tmp/registry --privileged=true registry
8756168da5688dbe17c61fcfed5f72b9e084ba404e872024d0201bcadce92e0d
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便与宿主机联调。
卷(volume)就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性;卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
将docker容器内的数据保存进宿主机的磁盘中
运行一个带有容器卷存储功能的容器实例
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的。Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。为了能保存数据在docker中我们使用卷。举个生活中例子帮助理解:假设我们有一台笔记本电脑,现在我需要备份笔记本电脑中的数据,那么我可以将数据保存外外置硬盘或U盘中,还可以备份到百度云盘或者阿里云盘。假设我现在有一台docker容器,里面有一些重要的数据,突然有一天有个人执行了docker stop或者docker rm -f,容器一旦被删除则里面的数据也会消失,这时候我们就需要用容器数据卷的方式完成数据持久化(备份重要的数据),docker可以实现容器的目录和主机的目录做一个映射,可以把容器内的数据备份+持久化到本地主机目录,这样就形成了对重要数据的保护,不容易丢失。
特点:
数据卷可在容器之间共享或重用数据
卷中的更改可以直接实时生效
数据卷中的更改不会包含在镜像的更新中
数据卷的生命周期一直持续到没有容器使用它为止
案例1:匿名卷
# 直接指定容器内的路径,会随机生成一个宿主机目录地址
docker run -d --name nx1 -p 80:80 -v /nginx/dir --privileged=true nginx
案例2:具名卷
# 指定数据卷的名称,本地卷在/var/lib/docker/volumes/数据卷的名称/_data
docker run -d -p 8080:80 --name nx2 --privileged=true -v nginx:/nginx/dir nginx
# 1. 运行镜像并添加数据卷
[root@dk ~]# docker run -it --name yaoge --privileged=true -v /yc/myData:/tmp/ubuntu ubuntu /bin/bash
# 2. 在ubuntu中创建文件并写入内容
root@21cd326d8bfa:/# cd /tmp/ubuntu
root@21cd326d8bfa:/tmp/ubuntu# echo 'hello ubuntu' >> test.txt
# 3. 写入完毕后退出ubuntu
# 4. 在宿主机CentOS中查看/yc/myData/test.txt的文件内容
[root@dk ~]# cd /yc/myData/
[root@dk myData]# cat test.txt
hello ubuntu
# 5. 重写追加文字到test.txt文件中
[root@dk myData]# echo 'hello docker!!' >> test.txt
# 6. 查看运行的容器
[root@dk myData]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
21cd326d8bfa ubuntu "/bin/bash" About a minute ago Up About a minute yaoge
d5d543121c4b registry "/entrypoint.sh /etc…" 30 hours ago Up 30 hours 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp keen_ramanujan
# 7. 重新进去容器,并查看文件内容
[root@dk myData]# docker exec -it 21cd326d8bfa /bin/bash
root@21cd326d8bfa:/# cd /tmp/ubuntu
root@21cd326d8bfa:/tmp/ubuntu# cat test.txt
hello ubuntu
hello docker!!
# 8. 可以看到在宿主机中添加的内容也能够在ubuntu容器中看到了
查看数据卷是否挂载成功
# 查看运行的容器
[root@dk ~]# docker ps
[root@dk ~]# docker inspect d5d543121c4b
"Mounts": [
{
"Type": "bind",
"Source": "/noyao/myregistry",
"Destination": "/tmp/registry",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
docker修改,主机同步获得
主机修改,docker同步获得
docker容器stop,主机修改,docker容器重启看数据是否同步
总结:
读写规则分为读写和只读两种,在默认情况下,就是容器可以读和写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录-镜像名
下面我们进行只读的限制:容器实例内部被限制,容器只能读取不能写
# 此时如果宿主机写入内容,可以同步给容器内,容器可以读取到,但是不能写入。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
我们在上一个容器yaoge的基础上进行配置,对于卷的继承,就是相当于使用原来的容器生成了一个新的一样的容器实例。
语法:
docker run -it --privileged=true --volumes-from 父类 --name yaoge ubuntu
容器yaoge2继承容器yaoge的卷规则
docker run -it --name=yaoge2 --privileged=true --volumes-from yaoge ubuntu bash
[root@localhost ~]# docker run -d -p 6603:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
[root@localhost ~]# docker run -d -p 6604:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器为止。
但是一旦持久化到了本地,本地的数据是不会删除的!
[root@dk ~]# docker search tomcat
[root@dk ~]# docker pull tomcat
[root@dk ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ycubuntu 1.2 466572ffe865 2 days ago 119MB
test/ubuntu v1 ede897f1dc20 5 days ago 77.8MB
ubuntu latest a8780b506fa4 11 days ago 77.8MB
registry latest dcb3d42c1744 5 weeks ago 24.1MB
tomcat latest fb5657adc892 10 months ago 680MB
hello-world latest feb5d9fea6a5 13 months ago 13.3kB
centos latest 5d0da3dc9764 14 months ago 231MB
# -p 小写,主机端口:docker容器端口
# -P 大写,随机分配端口
# i:交互
# t:终端
# d:后台
[root@dk ~]# docker run -it -p 8080:8080 tomcat
# 1. 查看容器ID
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2432606c447f tomcat "catalina.sh run" 2 hours ago Up 2 hours 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp zen_gagarin
# 2. 重新进入容器
[root@dk ~]# docker exec -it 2432606c447f /bin/bash
# 3. 查看webapps文件夹
root@2432606c447f:/usr/local/tomcat# ls -l
total 132
-rw-r--r--. 1 root root 18994 Dec 2 2021 BUILDING.txt
-rw-r--r--. 1 root root 6210 Dec 2 2021 CONTRIBUTING.md
-rw-r--r--. 1 root root 60269 Dec 2 2021 LICENSE
-rw-r--r--. 1 root root 2333 Dec 2 2021 NOTICE
-rw-r--r--. 1 root root 3378 Dec 2 2021 README.md
-rw-r--r--. 1 root root 6905 Dec 2 2021 RELEASE-NOTES
-rw-r--r--. 1 root root 16517 Dec 2 2021 RUNNING.txt
drwxr-xr-x. 2 root root 4096 Dec 22 2021 bin
drwxr-xr-x. 1 root root 22 Nov 14 09:25 conf
drwxr-xr-x. 2 root root 4096 Dec 22 2021 lib
drwxrwxrwx. 1 root root 80 Nov 14 09:25 logs
drwxr-xr-x. 2 root root 159 Dec 22 2021 native-jni-lib
drwxrwxrwx. 2 root root 30 Dec 22 2021 temp
drwxr-xr-x. 2 root root 6 Dec 22 2021 webapps
drwxr-xr-x. 7 root root 81 Dec 2 2021 webapps.dist
drwxrwxrwx. 2 root root 6 Dec 2 2021 work
# 4. 删除webapps文件夹
root@2432606c447f:/usr/local/tomcat# rm -r webapps
# 5. 将webapps.dist文件夹改名为webapps
root@2432606c447f:/usr/local/tomcat# mv webapps.dist webapps
重新刷新浏览器,可以看到Tomcat可以正常访问了!
[root@dk ~]# docker pull billygoo/tomcat8-jdk8
[root@dk ~]# docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
[root@dk ~]# docker search mysql
[root@dk ~]# docker pull mysql:5.7
[root@dk ~]# docker images
# 1. 运行镜像方式1
[root@dk ~]# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 运行镜像方式2
[root@dk ~]# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 2. 查看有docker运行了哪些容器
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe02e9067ea2 mysql:5.7 "docker-entrypoint.s…" 5 seconds ago Up 3 seconds 3306/tcp, 33060/tcp some-mysql
# 3. 重新进入容器
[root@dk ~]# docker exec -it fe02e9067ea2 /bin/bash
root@fe02e9067ea2:/# mysql -uroot -p
Enter password: (输入MYSQL_ROOT_PASSWORD上定义的密码)
登录成功后,建库建表插入数据。
mysql> create database studentDB;
Query OK, 1 row affected (0.00 sec)
mysql> use studentDB;
Database changed
mysql> create table student(id int primary key auto_increment,name varchar(50));
Query OK, 0 rows affected (0.05 sec)
mysql> insert into student values(0,'aaa');
Query OK, 1 row affected (0.07 sec)
mysql> select * from student;
+----+------+
| id | name |
+----+------+
| 1 | aaa |
+----+------+
1 row in set (0.00 sec)
Win10使用外部工具SQLyog也可以连接MySQL,如果连接不上记得防火墙端口放行,或者在运行时使用的是默认端口,注意使用docker ps
查看容器运行的端口是多少!
插入中文数据时会有乱码问题,如下图:
为什么报错?
docker里面的mysql容器实例查看,内容如下:
SHOW VARIABLES LIKE 'character%'
删除此容器重新开始配置!
重新新建容器:
[root@dk ~]# docker run -d -p 3306:3306 --privileged=true -v /yaochuang/mysql/log:/var/log/mysql -v /yaochuang/mysql/data:/var/lib/mysql -v /yaochuang/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
1d25eb44bf8f77d63508bc086249b0b67b3df2f014757f7403f9c885ae2e8c3e
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d25eb44bf8f mysql:5.7 "docker-entrypoint.s…" 7 seconds ago Up 4 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
[root@dk ~]# cd /yaochuang/mysql/conf/
[root@dk conf]# vi my.cnf
[root@dk conf]# cat my.cnf
[mysqld]
# 添加此配置跳过登录
skip-grant-tables
collation_server=utf8_general_ci
character-set-server=utf8
[client]
default-character-set=utf8
[root@dk conf]# docker restart mysql
# 重新进入mysql
[root@dk ~]# docker exec -it mysql bash
# 不用输入密码,直接回车登录
root@23c664f57c61:/# mysql -uroot
# 注意:接下来的代码都是MySQL
mysql> use mysql;
# 必须先刷新权限
mysql> flush privileges;
# 修改密码
mysql> alter user 'root'@localhost identified by '123456';
# 修改完成后退出MySQL,退出容器
mysql> exit
root@23c664f57c61:/# exit
# 重新打开my.cnf文件,删除skip-grant-tables,然后重启mysql
# 测试:使用SQLyog连接MySQL,插入中文试试是否成功!
总结:
docker安装完MySQL并run出容器后,建议先修改字符集编码后再新建库-表-插数据。
问题:假如将当前容器实例删除,再重新来一次,之前建的studentDB实例还有吗?
[root@dk ~]# docker stop fe02e9067ea2
[root@dk ~]# docker rm -f fe02e9067ea2
[root@dk ~]# docker rmi -f mysql:5.7
Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 的 NoSQL 数据库,并提供多种语言的 API。
第1步:新建主服务器容器实例3307
# 注意:以下命令是整段,\为换行。此处应也应该要注意MYSQL_ROOT_PASSWORD设置密码时,可能后面会多一个空格
[root@dk ~]# docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
c1648630914c mysql:5.7 "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp
[root@dk ~]# docker exec -it mysql-master bash
# 检查 MYSQL_ROOT_PASSWORD 是否设置正确
root@c1648630914c:/# echo $MYSQL_ROOT_PASSWORD
# 尝试是否能够登陆成功
root@c1648630914c:/# mysql -uroot -p
第2步:进入/mydata/mysql-master/conf目录下新建my.cnf
[root@dk ~]# cd /mydata/mysql-master/conf
[root@dk conf]# cat my.cnf
[mysqld]
# 设置server_id,同一局域网中需要唯一
server-id=101
# 指定不需要同步的数据库名称
binlog-ignore-db=mysql
# 开启二进制日志功能
log-bin=mall-mysql-bin
# 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
# 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
# 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
# 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
# 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
第3步:修改完配置后重启master实例
[root@dk conf]# docker restart mysql-master
第4步:重新进入mysql-master容器
[root@dk conf]# docker exec -it mysql-master bash
root@c1648630914c:/# mysql -uroot -p
第5步:master容器实例内创建数据同步用户
mysql> CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
第6步:新建从服务器容器实例3308
[root@dk ~]# docker run -p 3308:3306 --name mysql-slave \
-v /mydata/mysql-slave/log:/var/log/mysql \
-v /mydata/mysql-slave/data:/var/lib/mysql \
-v /mydata/mysql-slave/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.7
第7步:进入/mydata/mysql-slave/conf目录下新建my.cnf
[root@dk ~]# cd /mydata/mysql-slave/conf
[root@dk ~]# cat my.cnf
[mysqld]
# 设置server_id,同一局域网中需要唯一
server-id=102
# 指定不需要同步的数据库名称
binlog-ignore-db=mysql
# 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin
# 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
# 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
# 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
# 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
# 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
# relay_log配置中继日志
relay_log=mall-mysql-relay-bin
# log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
# slave设置为只读(具有super权限的用户除外)
read-only=1
第8步:修改完配置后重启slave实例
# 重启完成后记得查看后台是否重启成功
[root@dk conf]# docker restart mysql-slave
第9步:在主数据库中查看主从同步状态
# 此处应当重新进入主库容器,重新进入数据库
mysql> show master status;
+-----------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------------+----------+--------------+------------------+-------------------+
| mall-mysql-bin.000001 | 617 | | mysql | |
+-----------------------+----------+--------------+------------------+-------------------
第10步:进入mysql-slave容器
[root@dk ~]# docker exec -it mysql-slave bash
root@75c733a68748:/# mysql -uroot -p
第11步:在从数据库中配置主从复制
参数说明:
mysql> change master to master_host='192.168.170.148',master_user='slave',master_password='123456',master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=1821, master_connect_retry=30;
第12步:在从数据库中开启主从同步
mysql> start slave;
第13步:在从数据库中查看主从同步状态
mysql> show slave status \G;
第14步:查看从数据库状态发现已经同步
第15步:主从复制测试
主机新建库—使用库—新建表—插入数据
从机使用库—查看记录
一个主机 m1 用于处理所有写请求,它的从机 s1 和另一台主机 m2 还有它的从机 s2 负责所有读请求。当 m1 主机宕机后,m2 主机负责写请求,m1 和 m2 互为备机,架构图如下:
首先会创建一个自定义网络 mysql ,然后会启动 4 台 MySQL 容器实例,其中 2 台作为主机,2 台作为从机。
编号 | 主机名 | 备注 |
---|---|---|
1 | m1 | 主机 |
2 | s1 | 从 |
3 | m2 | 主机(备) |
4 | s2 | 从机(备) |
创建自定义网络,以便容器之间可以通过主机名和端口互相通信:
docker network create mysql
新建 4 台 MySQL 容器实例,2 台容器实例为 MySQL 的主机,2 台容器实例为 MySQL 的从机:
docker run -d -p 3306:3306 --network mysql \
--name m1 \
-v m1:/etc/mysql/conf.d \
-v /var/m1/logs:/var/log/mysql \
-v /var/m1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
--restart=always mysql:8.0.26 \
--lower_case_table_names=1 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_general_ci \
--default-authentication-plugin=mysql_native_password
docker run -d -p 3307:3306 --network mysql \
--name s1 \
-v s1:/etc/mysql \
-v /var/s1/logs:/var/log/mysql \
-v /var/s1/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
--restart=always mysql:8.0.26 \
--lower_case_table_names=1 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_general_ci \
--default-authentication-plugin=mysql_native_password
docker run -d -p 3308:3306 --network mysql \
--name m2 \
-v m2:/etc/mysql \
-v /var/m2/logs:/var/log/mysql \
-v /var/m2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
--restart=always mysql:8.0.26 \
--lower_case_table_names=1 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_general_ci \
--default-authentication-plugin=mysql_native_password
docker run -d -p 3309:3306 --network mysql \
--name s2 \
-v s2:/etc/mysql \
-v /var/s2/logs:/var/log/mysql \
-v /var/s2/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e TZ=Asia/Shanghai \
--restart=always mysql:8.0.26 \
--lower_case_table_names=1 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_general_ci \
--default-authentication-plugin=mysql_native_password
查看自定义网络是否有 MySQL 的主机和从机:
docker network ls
docker network inspect mysql
列出所有卷:
docker volume ls
查看卷的详情:
docker volume inspect m1
cd /var/lib/docker/volumes/m1/_data
其余信息,以此类推即可。
修改主机 m1 容器实例的配置文件,并重启主机容器 m1 实例:
vim my.cnf
[mysqld]
# 以下是增加的配置
# [必须] 主服务器唯一ID,保证整个集群环境中唯一,取值范围在 1 - 2^32 -1 ,默认为 1
server-id=1
# 在作为从库的时候,有写入操作也需要更新二进制日志文件
log-slave-updates
重启容器:docker restart m1
修改主机 m2 容器实例的配置文件,并重启主机容器 m2 实例:
vim my.cnf
[mysqld]
# 以下是增加的配置
# [必须] 主服务器唯一ID,保证整个集群环境中唯一,取值范围在 1 - 2^32 -1 ,默认为 1
server-id=3
# 在作为从库的时候,有写入操作也需要更新二进制日志文件
log-slave-updates
重启容器:docker restart m2
修改从机 s1 容器实例的配置文件,并重启从机容器 s1 实例:
vim my.cnf
[mysqld]
# 以下是增加的配置
# [必须] 从服务器唯一ID
server-id=2
# [可选] 启用中继日志
relay-log=mysql-relay
重启容器:docker restart s1
修改从机 s2 容器实例的配置文件,并重启从机容器 s2 实例:
vim my.cnf
[mysqld]
# 以下是增加的配置
# [必须] 从服务器唯一ID
server-id=4
# [可选] 启用中继日志
relay-log=mysql-relay
重启容器:docker restart s2
MySQL 主机(m1)创建账号并授权:
CREATE USER 'slave1'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';
ALTER USER 'slave1'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH PRIVILEGES;
MySQL 主机(m2)创建账号并授权:
CREATE USER 'slave1'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';
ALTER USER 'slave1'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH PRIVILEGES;
查看 MySQL 主机(m1)的状态,并记录 File 和 Position 的值:
SHOW MASTER STATUS;
查看 MySQL 主机(m2)的状态,并记录 File 和 Position 的值:
SHOW MASTER STATUS;
步骤 ①:从机上复制主机的命令
CHANGE MASTER TO
MASTER_HOST='主机的IP地址',
MASTER_USER='主机用户名',
MASTER_PORT='主机的端口号',
MASTER_PASSWORD='主机用户名的密码',
MASTER_LOG_FILE='binlog.具体数字',
MASTER_LOG_POS=具体值;
步骤②:配置从库1(s1),指定主机m1
步骤③:配置从库2(s2),指定主机m2
步骤④:启动从库1和从库2的主从同步
start slave;
步骤⑤:查看同步状态
到此为止,我们只是配置了两台主从复制,还没有配置主主复制,请看下面的操作。
步骤 ① :查看 Master 的状态,并记录 File 和 Position 的值:
SHOW MASTER STATUS;
之所以再次执行,是为了防止 File 和 Position 有变化。
步骤 ②:m2 复制 m1,m1 复制 m2。
CHANGE MASTER TO
MASTER_HOST='主机的IP地址',
MASTER_USER='主机用户名',
MASTER_PORT='主机的端口号',
MASTER_PASSWORD='主机用户名的密码',
MASTER_LOG_FILE='binlog.具体数字',
MASTER_LOG_POS=具体值;
示例:m1
CHANGE MASTER TO
MASTER_HOST='m2',
MASTER_USER='slave1',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='binlog.000003',
MASTER_LOG_POS=1114;
示例:m2
CHANGE MASTER TO
MASTER_HOST='m1',
MASTER_USER='slave1',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='binlog.000003',
MASTER_LOG_POS=1114;
步骤 ③:启动 Master 同步
两个主库都要执行!
START SLAVE;
步骤④:查看同步状态
在 m1 和 m2 上执行 DDL 和 DML 语句,查看涉及到的数据库服务器的数据同步情况。
示例:m1
# 执行 DDL 操作
CREATE DATABASE IF NOT EXISTS dbtest CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';
USE dbtest;
CREATE TABLE student(id INT,`name` VARCHAR(16));
示例:m2
# 执行 DML 操作
USE dbtest;
INSERT INTO student VALUES(1, 'xx');
INSERT INTO student VALUES(2, 'yy');
示例:m1
# 查看数据
USE dbtest;
SELECT * FROM student;
示例:m2
# 查看数据
USE dbtest;
SELECT * FROM student;
示例:s1
# 查看数据
USE dbtest;
SELECT * FROM student;
示例:s2
# 查看数据
USE dbtest;
SELECT * FROM student;
此处内容不做讲解
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
概念:
官网:
构建三步骤:
Dockerfile内容基础知识
Docker执行Dockerfile的大致流程
总结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段:
Dockerfile是软件的原材料
Docker镜像是软件的交付品
Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
1)Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2)Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
3)Docker容器,容器是直接提供服务的。
https://github.com/docker-library/tomcat
基础镜像信息
、维护者信息
、镜像操作指令
、启动时执行指令
。基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
推荐使用 alpine
或 slim
之类的基础小镜像。
scratch
镜像是一个空镜像,常常用于多阶段构建。
『问』:如何确定我们需要的基础镜像?
『答』:
镜像维护者的姓名和邮箱地址,已过期;可以使用 LABEL xxx=yyy 来代替。
LABEL 用来标注镜像的一些说明信息,常常用来指定维护者的信息。
# 下面的这种格式是可以的
LABEL multi.label1="value1" multi.label2="value2" other="value3"
# 下面的这种格式也是可以的
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
RUN 指令在当前镜像层顶部的新层执行任何命令,并提交结果,生成新的镜像层。
生成的提交镜像将用于 Dockerfile 中的下一步,分层运行 RUN 指令并生成提交符合 Docker 的核心概念,就像 Git 管理源代码一样。
注意
:多个 RUN 指令并没有上下文的关系,换言之,多个 RUN 指令都是在同一个目录操作的。
容器构建时需要运行的命令,有两种格式
Shell格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的shell名。
RUN yum -y install vim
exec格式
RUN["可执行文件","参数1","参数2"]
# 例如:
# RUN["./test.sh","dev","offline"] 等价于 RUN ./test.sh dev offline
RUN 是在docker build 时运行
\
将一条 RUN 指令继续到下一行。RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
# 等同于
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
[root@dk ~]# vim Dockerfile
# 测试案例
FROM alpine
LABEL maintainer=yaoge
ENV msg='hello Docker'
RUN echo $msg
RUN ["echo","$msg"]
RUN /bin/sh -c 'echo $msg'
RUN ["/bin/sh","-c","echo $msg"]
CMD sleep 1000
运行
docker build -t test --force-rm --no-cache .
[]
不是 shell 形式,所以不能输出变量信息,而是输出 $msg
。其他任何 /bin/sh -c
的形式都可以输出变量信息。RUN /bin/sh -c <command>
的方式,RUN ["/bin/sh","-c",command]
的 exec 方式等同于 shell 方式,而 RUN ["/bin/sh",command]
的 exec 默认不会进行变量替换。构建期是指使用 Dockerfile 构建镜像的整个过程时期,如:docker build 等。
运行期是指使用之前构建的镜像启动容器的过程,如:docker start 、docker run 等。
语法:
ARG name=defaultValue
ARG 指令定义了一个变量,用户可以在构建的时候使用 --build-arg name=value
传递,docker build 命令会将其传递给构建器。
--build-arg
指定参数会覆盖 Dockerfile 中指定的同名参数。
如果用户指定了 未在 Dockerfile 中定义的构建参数
,则构建会输出 警告
。
ARG 只在构建时期有效,运行时期无效。
不建议使用构建时变量来传递注入 github 密码、用户凭据等机密,因为构建时变量的值可以通过 docker history 来观察到。
ARG 变量定义从 Dockerfile 定义的行开始生效。
使用 ENV 指定定义的环境变量始终会覆盖同名的 ARG 指令。
案例:
[root@dk ~]# vim Dockerfile
# 选择基础镜像
FROM alpine
# 维护者信息
LABEL maintainer="yaoge"
# ARG 指令定义了一个变量,用户可以在构建的时候使用 `--build-arg name=value` 传递,docker build 命令会将其传递给构建器。
# `--build-arg` 指定参数会覆盖 Dockerfile 中指定的同名参数。
# 如果用户指定了 `未在 Dockerfile 中定义的构建参数` ,则构建会输出 `警告` 。
# ARG 只在构建时期有效,运行时期无效。
# 不建议使用构建时变量来传递注入 github 密码、用户凭据等机密,因为构建时变量的值可以通过 docker history 来观察到。
# ARG 变量定义从 Dockerfile 定义的行开始生效。
ARG param="Hi Docker"
# 在构建时期会运行的指令(根据 Dockerfile 创建一个镜像的整个过程时期)
RUN echo 1111
RUN echo ${param}
# 在运行时候会执行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)
# docker start 或 docker run
CMD ["/bin/sh","-c","echo 2222;echo $param"]
运行:
docker build -t test01 --force-rm --no-cache .
# 或者
docker build -t test02 --force-rm --no-cache --build-arg param=test .
语法:
ENV name=value
ENV 和 ARG 很类似,但是 ENV 在构建期和运行期都有效,并且使用 ENV 指定定义的环境变量始终会覆盖同名的 ARG 指令。
可以使用 docker run -e name=value
修改 ENV 定义的环境变量。
示例:
[root@dk ~]# vim Dockerfile
# 选择基础镜像
FROM alpine
# 维护者信息
LABEL maintainer="姚大哥"
# ARG 指令定义了一个变量,用户可以在构建的时候使用 `--build-arg name=value` 传递,docker build 命令会将其传递给构建器。
# `--build-arg` 指定参数会覆盖 Dockerfile 中指定的同名参数。
# 如果用户指定了 `未在 Dockerfile 中定义的构建参数` ,则构建会输出 `警告` 。
# ARG 只在构建时期有效,运行时期无效。
# 不建议使用构建时变量来传递注入 github 密码、用户凭据等机密,因为构建时变量的值可以通过 docker history 来观察到。
# ARG 变量定义从 Dockerfile 定义的行开始生效。
ARG param="Hi Docker"
# ENV 在构建期和运行期都有效,但是只能在运行期进行修改,修改通过 docker run -e name=value 命令。
ENV app=taobao
# 在构建时期会运行的指令(根据 Dockerfile 创建一个镜像的整个过程时期)
RUN echo 1111
RUN echo ${param}
RUN echo ${app}
# 在运行时候会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令)
# docker start 或 docker run
CMD ["/bin/sh","-c","echo 2222;echo $param;echo app_$app"]
运行:
docker build -t test --force-rm --no-cache .
# 或者
docker run -it test
坑
:ENV 在构建期就会被解析并持久化,可以通过 docker inspect image 查看。[root@dk ~]# vim Dockerfile
# ENV 的坑
FROM alpine
LABEL maintainer="姚哥"
ENV msg1="hello"
ENV msg2=${msg1}
RUN echo ${msg1}
RUN echo ${msg2}
# 如果运行期修改了 msg1=666,那么 msg1 和 msg2 的值是 666 和 hello ,因为 ENV 在构建期就会被解析并持久化。
CMD ["/bin/sh","-c","echo $msg1;echo $msg2;"]
运行:
docker build -t test --force-rm --no-cache .
# 或者
docker run -it -e msg1=666 test
ADD 并没有自动下载远程压缩文件并解压的功能
。语法:
ADD src dest
注意
:
../../xxx
这种方式,因为 Docker 构建的第一步是将上下文目录(包括子目录)发送给 Docker 的守护进程。/
结尾,那么就会从 URL 下载文件并将其复制为 dest(名称)。/
结尾,会自动推断出文件的名称(URL 的最后一部分)并保存到 dest(目录)中。示例1:
[root@dk ~]# vim Dockerfile
FROM alpine
LABEL maintainer="姚哥"
# 如果是远程文件,自动下载
# 如果是压缩文件,自动解压
# 注意:ADD 并没有自动下载远程压缩文件并解压的功能
# 将当前内容复制到 alpine 中,并且以dest为文件名称
ADD https://download.redis.io/releases/redis-6.2.6.tar.gz /dest
# 注意,RUN 指令上下并没有上下文的关系。
RUN ls -l
运行:
docker build -t test --force-rm --no-cache .
示例2:
[root@dk ~]# vim Dockerfile
FROM alpine
LABEL maintainer="姚哥"
# 如果是远程文件,自动下载
# 如果是压缩文件,自动解压
# 注意:ADD 并没有自动下载远程压缩文件并解压的功能
ADD https://download.redis.io/releases/redis-6.2.6.tar.gz /dest/
# 注意,RUN 指令上下并没有上下文的关系。
RUN ls -l
RUN cd /dest && ls -l
运行:
docker build -t test --force-rm --no-cache .
示例3:
# 先下载文件,放入与Dockerfile同目录下
[root@dk ~]# wget https://download.redis.io/releases/redis-6.2.6.tar.gz
[root@dk ~]# vim Dockerfile
FROM alpine
LABEL maintainer="姚哥"
# 如果是远程文件,自动下载
# 如果是压缩文件,自动解压
# 注意:ADD 并没有自动下载远程压缩文件并解压的功能
ADD redis-6.2.6.tar.gz /dest/
# 注意,RUN 指令上下并没有上下文的关系。
RUN ls -l
RUN cd /dest && ls -l
运行:
docker build -t test --force-rm --no-cache .
语法:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
# <src源路径>:源文件或者源目录
# <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
COPY 和 ADD 类似,都有将上下文指定的内容添加(复制)到镜像中的功能,只不过 ADD 有自动下载或解压压缩文件的功能。
--chown
功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,而在 Windows 容器上不起作用。
案例:省略,根据自己的理解复制文件到容器内;
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
语法:
USER <user>[:<group>]
USER <UID>[:<GID>]
USER 指令和 WORKDIR 指令类似,都是改变环境状态并影响以后的层,WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN 、CMD 、以及 ENTRYPOINT 这类命令的身份。
注意
:USER 只是帮助我们切换到指定的用户而已,这个用户必须事先建立好的,否则无法切换。
示例:
[root@dk ~]# touch user.txt
[root@dk ~]# vim Dockerfile
FROM alpine
LABEL maintainer="姚哥"
# 创建用户和组
RUN addgroup -S test && adduser -S test -G test -h /home/test
# USER 只是帮准我们切换到指定的用户而已,这个用户必须事先建立好的,否则无法切换。USER 则是改变之后层的执行 RUN、CMD、以及 ENTRYPOINT 这类命令的身份。
USER test:test
COPY *.txt /test/
# 注意:一旦声明了 USER 之后,USER 后面的 RUN、CMD、ENTRYPOINT 的身份就是 test ,而 a.txt 是主机生成的,身份是 root ,必然会报错,权限不对。
RUN cd /test && ls -l && echo 1111 > user.txt
运行:
docker build -t test --force-rm --no-cache .
报错信息如下:
示例:使用 USER + COPY 解决上面示例的权限等问题
[root@dk ~]# touch user.txt
[root@dk ~]# vim Dockerfile
FROM alpine
LABEL maintainer="姚哥"
# 创建用户和组
RUN addgroup -S test && adduser -S test -G test -h /home/test
# USER 只是帮准我们切换到指定的用户而已,这个用户必须事先建立好的,否则无法切换。USER 则是改变之后层的执行 RUN、CMD、以及 ENTRYPOINT 这类命令的身份。
USER test:test
# 通过 COPY 指定的 chown 功能改变复制文件的权限
COPY --chown=test:test *.txt /test/
# 注意:一旦声明了 USER 之后,USER 后面的 RUN、CMD、ENTRYPOINT 的身份就是 test ,而 a.txt 是主机生成的,身份是 root ,但是,因为使用了 COPY --chown=test:test ,所以文件的权限是 test
RUN cd /test && ls -l && echo 1111 > user.txt
运行:
docker build -t test --force-rm --no-cache .
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点。(类似于cd命令)
语法:
WORKDIR /a/b/c
WORKDIR 指令为 Dockerfile 中跟随它后面的 RUN 、CMD 、ENTRYPOINT、 COPY、ADD 指令设置工作目录。
WORKDIR 指令可在 Dockerfile 中多次使用。 如果提供了相对路径,则它将相对于上一个 WORKDIR 指令的路径,如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 效果:/a/b/c
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
# 效果:/path/$DIRNAME
示例:
[root@dk ~]# touch user.txt
[root@dk ~]# vim Dockerfile
FROM alpine
RUN pwd && ls -l
WORKDIR /app
RUN pwd && ls -l
COPY *.txt ./
RUN ls -l
运行:
docker build -t test --force-rm --no-cache .
执行完进入容器后。能够看到进入了目录/app
,并且复制了txt文件到此目录下
语法:
#可以是JSON数组
VOLUME ["/var/log/","/var/db"]
#可以直接写
VOLUME /var/log
#可以空格分割多个
VOLUME /var/log /var/db
用 VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,所以,一定要在 volume 声明之前修改内容 。
示例:
[root@dk ~]# vim Dockerfile
FROM alpine
# 挂载 容器指定的文件夹,如果不存在,会自动创建。
# 指定了 VOLUME 指令后,即使启动容器的时候没有指定 -v 参数,也会自动进行匿名卷挂载。
VOLUME [ "/demo","/app" ]
CMD ping www.baidu.com
运行:
# 此命令运行完后,会以匿名卷的方式在容器内创建/demo和/app文件夹,主机映射地址使用inspect查看
docker build -t test --force-rm --no-cache .
示例:用 VOLUME 声明了卷,那么以后对于卷内容的修改会被丢弃,所以,一定要在 volume 声明之前修改内容
[root@dk ~]# vim Dockerfile
FROM alpine
RUN mkdir /demo && mkdir /app
RUN echo 111 > /demo/a.txt
RUN echo 222 > /app/b.txt
# 挂载 容器指定的文件夹,如果不存在,会自动创建。
# 指定了 VOLUME 指令后,即使启动容器的时候没有指定 -v 参数,也会自动进行匿名卷挂载。容器内的 /demo 和 /app ,需要在启动容器的时候,需要使用 -v 参数进行挂载。
# VOLUME 挂载出去的东西,容器改变也不会最终在 docker commit 的时候生效。
# -v 和 VOLUME 挂载出去的目录,主机变,容器里面也会发生变化,但是
# ① docker commit 提交当前容器的所有变化为镜像,就会丢弃。
# ② VOLUME [ "/demo","/app" ] 容器会自动挂载,在之后对这些目录所操作的变化,也会丢弃
# ③ 挂载仅仅是为了将外边的数据同步到容器里面
# VOLUME 的最佳实践是写在 CMD 或 ENTRYPOINT 前面
VOLUME [ "/demo","/app" ]
# 下面的 2 个 RUN 指令没有生效,因为 VOLUME 指定的挂载目录是固化配置,当执行到 VOLUME 的时候就已经写入到容器中了,即使后面容器怎么变,也不会改变。
RUN echo 333 > /demo/a.txt
RUN echo 444 > /app/b.txt
CMD ping www.baidu.com
运行:
# 运行完后自行做测试
docker build -t test --force-rm --no-cache .
当前容器对外暴露出的端口
语法:
EXPOSE <port> [<port>/<protocol>...]
EXPOSE [80,443]
EXPOSE 80/tcp
EXPOSE 80/udp
EXPOSE 指令通知 Docker 容器在运行的时候在指定的网络端口上进行侦听,可以指定端口是侦听 TCP 还是 UDP ,如果没有指定,默认就是 TCP 。
EXPOSE 指令实际上不会发布端口,它充当了构建镜像人员和运行容器人员之间的一种文档,即打算发布那些端口的信息,要在运行容器时映射端口,需要使用 docker run -p xxx:xxx
或 docker run -P
的命令。
示例:省略
CMD语法:
# exec 方式, 首选方式
CMD ["executable","param1","param2"]
# 为 ENTRYPOINT 提供默认参数
CMD ["param1","param2"]
# shell 形式
CMD command param1 param2
ENTRYPOINT 的语法:
# exec 方式, 首选方式
ENTRYPOINT ["executable", "param1", "param2"]
# shell 形式
ENTRYPOINT command param1 param2
注意
:
① 如果 Dockerfile 文件中,使用多个 CMD 或 ENTRYPOINT 作为唯一的入口,即写多个 CMD 或 ENTRYPOINT ,则会产生覆盖现象,只有最后一个生效。
② shell 方式是可以读取环境变量的值的(如:
${xxx}
),默认情况下,exec 的方式是读取不了环境变量值的,但是 exec 方式的[“/bin/sh”,”-c”,”xxx”]
等同于 shell 方式,也是可以读取环境变量值。③ 官方推荐使用 RUN 、CMD 以及 ENTRYPOINT 使用 exec 的方式。
④ 如果既有 CMD 的 exec 方式,又有 ENTRYPOINT 的 exec 方式,那么 CMD 是作为 ENTRYPOINT 的参数的(最佳实践)。
⑤ 使用
docker run -d xxx CMD
命令是可以覆盖 Dockerfile 中的 CMD 指令的,不是覆盖 exec 方式数组中的一个,而是全部。
示例:证明注意 ①
[root@dk ~]# vim Dockerfile
FROM alpine
# CMD 和 ENTRYPOINT 作为唯一入口,写多个,只有最后一个生效
CMD ping baidu.com
CMD ping bing.com
运行:
docker build -t test --force-rm --no-cache .
# --rm 表示容器退出,自动删除
docker run -it --rm test
示例:证明注意 ④
[root@dk ~]# vim Dockerfile
FROM alpine
# java -jar xxx.jar --spring.profile.active=dev --server.port=8888
# CMD [ "-jar","xxx.jar","--spring.profile.active=dev","--server.port=8888"]
# ENTRYPOINT [ "java" ]
CMD ["baidu.com"]
ENTRYPOINT ["ping"]
运行:
docker build -t test --force-rm --no-cache .
# --rm 表示容器退出,自动删除
docker run -it --rm test
示例:证明注意 ⑤
[root@dk ~]# vim Dockerfile
FROM alpine
# java -jar xxx.jar --spring.profile.active=dev --server.port=8888
# CMD [ "-jar","xxx.jar","--spring.profile.active=dev","--server.port=8888"]
# ENTRYPOINT [ "java" ]
CMD ["baidu.com"]
ENTRYPOINT ["ping"]
运行:
docker build -t test --force-rm --no-cache .
# --rm 表示容器退出,自动删除
docker run -it --rm test bing.com
CMD和RUN命令的区别
CMD是在docker run 时运行。RUN是在 docker build时运行。
ENTRYPOINT:也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
命令格式:ENTRYPOINT ["<executeable>","param1","param2",......]
ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。
当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成:
<ENTRYPOINT> <CMD>
案例如下:假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx","-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] #变参
是否传参 | 按照dockerfile编写执行 | 传参运行 |
---|---|---|
Docker命令 | docker run nginx:test | docker run nginx:test -c /etc/nginx/new.conf |
衍生出的实际命令 | nginx -c /etc/nginx/nginx.conf | nginx -c /etc/nginx/new.conf |
**优点:**在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
**注意:**如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
JDK下载地址:https://www.oracle.com/java/technologies/downloads/#java8
或者也可以安装之前我给你们的jdk-8u333-linux-x64.tar.gz
,这里演示案例为8u333
第1步:创建文件夹/mywork,在此目录下创建文件Dockerfile
[root@dk ~]# mkdir /myfile
[root@dk ~]# touch /myfile/Dockerfile
[root@dk ~]# ll /myfile
总用量 144540
-rw-r--r-- 1 root root 791 11月 01 22:14 Dockerfile
-rw-r--r-- 1 root root 148003421 6月 10 07:52 jdk-8u333-linux-x64.tar.gz
第2步:编辑Dockerfile文件,文件内容如下:
注意:如果默认安装的是centos8,则会报一下错误:
解决方法1:将系统改为centos7,如FROM centos:7
解决方法2:百度、谷歌
[root@dk myfile]# cat Dockerfile
FROM centos:7
MAINTAINER yaochuang<2788459@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 安装vim编辑器
RUN yum -y install vim
# 安装ifconfig命令查看网络IP
RUN yum -y install net-tools
# 安装java8及lib库,类似于gcc依赖包,不安装会有问题
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
# ADD 是相对路径jar,把jdk-8u333-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u333-linux-x64.tar.gz /usr/local/java/
# 配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_333
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
CMD echo $MYPATH
CMD echo "安装成功......"
CMD /bin/bash
第3步:执行安装命令,注意,myos:1.5后面有个空格,空格后有个点
# docker build --no-cache --force-rm -t 镜像名称:TAG .
[root@dk myfile]# docker build -t myos:1.5 .
说明:
--no-cache
: 表示构建的时候不使用之前的缓存。
--force-rm
:删除构建过程中的中间容器层。
.
:表示构建环境的上下文,通常而言是 .
,表示以 Dockerfile 所在的目录作为构建的起点。
安装成功,结果如下:
第4步:测试
[root@dk ~]# docker run -it 93c5a653993f /bin/bash
接下来,我们通过构建一个Tomcat镜像,来演示Dockerfile的使用方法
步骤①:准备jdk.tar.gz和tomcat.tar.gz两个文件
步骤②:编写Dockerfile文件
[root@dk df]# vim Dockerfile
#config file start#
FROM centos
LABEL maintainer="yaoge"
#添加并解压压缩包
ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.31.tar.gz /usr/local/
ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/
#配置环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
#设置tomcat监听端口
EXPOSE 8080
#设置运行时执行的启动命令
CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run
步骤③:构建镜像
docker build -t tomcat-web .
步骤④:运行容器测试
仓库名、标签都是<none>
的镜像,俗称dangling image。通俗点讲就是在删除镜像时出了点错误导致删除失败,这时导致镜像仓库名、标签等都是<none>
。
案例:
1.新建一个Dockerfile文件
[root@dk ~]# cat Dockerfile
from ubuntu
CMD echo 'action is success'
2.docker build
3.查看
[root@dk ~]# docker image ls -f dangling=true
4.删除,虚悬镜像已经失去存在价值,可以删除
[root@dk ~]# docker image prune
使用Dockerfile构建myubuntu
# 开发期间,逐层验证正确的
RUN xxx
RUN xxx
RUN aaa \
aaa \
vvv \
# 生产环境
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion \
&& rm -rf /var/lib/apt/lists/*
使用 .dockerignore
文件,排除上下文中无需参与构建的资源。
合理使用多阶段构建。
合理使用构建缓存加速构建,但是有时也会有坑,开发的时候建议还是 docker build -t xxx --no-cache --force-rm .
来构建镜像。
回顾UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
docker微服务指的是使用一套小服务来开发单个应用的方式;每个服务运行在独立的进程中,一般采用轻量级的通讯机制互联,并且他们可以通过自动化的方式部署;微服务思想是将传统的单体系统按照业务拆分成多个职责单一并且可独立运行的接口服务。
建Module:docker_boot
改POM,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/>
</parent>
<groupId>com.atguigu.docker</groupId>
<artifactId>docker_boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mapper.version>4.1.5</mapper.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
</project>
server.port=6001
package com.atguigu.docker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DockerBootApplication
{
public static void main(String[] args)
{
SpringApplication.run(DockerBootApplication.class, args);
}
}
package com.atguigu.docker.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
/**
* @auther zzyy
* @create 2021-10-25 17:43
*/
@RestController
public class OrderController
{
@Value("${server.port}")
private String port;
@RequestMapping("/order/docker")
public String helloDocker()
{
return "hello docker"+"\t"+port+"\t"+ UUID.randomUUID().toString();
}
@RequestMapping(value ="/order/index",method = RequestMethod.GET)
public String index()
{
return "服务端口号: "+"\t"+port+"\t"+UUID.randomUUID().toString();
}
}
docker_boot-编写Dockerfile0.0.1-SNAPSHOT.jar
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER yao
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为yao_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar yao_docker.jar
# 运行jar包
RUN bash -c 'touch /yao_docker.jar'
ENTRYPOINT ["java","-jar","/yao_docker.jar"]
# 暴露6001端口作为微服务
EXPOSE 6001
将docker_boot-0.0.1-SNAPSHOT.jar和Dockerfile文件放在同一个目录下,然后执行
[root@dk ~]# docker build -t yao_docker:1.6 .
[root@dk ~]# docker run -d -p 6001:6001 yao_docker:1.6
# 先安装ifconfig命令
[root@dk ~]# yum install net-tools
docker不启动,默认网络情况
桥接、NAT、仅主机、用户自定义。这里就不重复地说这些有啥区别了,但是咱们这节要说的docker网络模式与之有一定的相似之处。
[root@dk ~]# docker images
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
# 先关闭服务
[root@dk ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.170.151 netmask 255.255.255.0 broadcast 192.168.170.255
inet6 fe80::deb2:feb0:9aa9:1e4d prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:f1:1f:ed txqueuelen 1000 (Ethernet)
RX packets 150627 bytes 118946590 (113.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 102470 bytes 18277759 (17.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 1113 bytes 97944 (95.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1113 bytes 97944 (95.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33不用多说了,lo为回环。这里可能还会有一个virbr0,在CentOS7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥的使用的,其作用是为连接其上的虚机网卡提供 NAT访问外网的功能。当然你也可以选择把它删了,命令如下:
[root@dk ~]# yum remove libvirt-libs.x86_64
# 这时候docker0这个虚拟网桥就冒出来了。
[root@dk ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:63ff:fe46:2803 prefixlen 64 scopeid 0x20<link>
ether 02:42:63:46:28:03 txqueuelen 0 (Ethernet)
RX packets 6845 bytes 8204943 (7.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9832 bytes 14104901 (13.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@dk ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
8d40433c88ed bridge bridge local
99c28be75fe0 host host local
913260e62b5d none null local
[root@dk ~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
[root@dk ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
8d40433c88ed bridge bridge local
99c28be75fe0 host host local
913260e62b5d none null local
[root@dk ~]# docker network ls --no-trunc
NETWORK ID NAME DRIVER SCOPE
9f8332ff0fffc6a393867d71f12ed003a2762a7ae378 bridge bridge local
d50ebcc074d6dd570bdbec9bf958ffc6c7d6184d4866 cig_default bridge local
29aaf2bf1e84d0963445706d2001ab4e6fda4f97314e composetest_atguigu_net bridge local
bebc5090e899abfc864356bc7f4192cd14ba51376143 composetest_default bridge local
99c28be75fe0e242f93bb254ab674912794f6b281d2b host host local
b8d9199e67fe7dc5457e1a427ecc0cb62fffd8d67b37 mywp_default bridge local
d16438fc94795de2770878dc2a66ba33c027dbcebda8 mywp_mywordpress bridge local
913260e62b5d22b0a2f2e01c1e6ab802c4e63525306a none null local
[root@dk ~]# docker network ls --filter driver=bridge
NETWORK ID NAME DRIVER SCOPE
9f8332ff0fff bridge bridge local
d50ebcc074d6 cig_default bridge local
29aaf2bf1e84 composetest_atguigu_net bridge local
bebc5090e899 composetest_default bridge local
b8d9199e67fe mywp_default bridge local
d16438fc9479 mywp_mywordpress bridge local
[root@dk ~]# docker network ls --filter id=9f8332ff0fffc6a393867d71f12ed003a2762a7ae378544973eeada72e884921
NETWORK ID NAME DRIVER SCOPE
9f8332ff0fff bridge bridge local
[root@dk ~]# docker network ls --format "{{.ID}}: {{.Driver}}"
9f8332ff0fff: bridge
d50ebcc074d6: bridge
29aaf2bf1e84: bridge
bebc5090e899: bridge
99c28be75fe0: host
b8d9199e67fe: bridge
d16438fc9479: bridge
913260e62b5d: null
[root@dk ~]# docker network inspect XXX网络名字
[root@dk ~]# docker network rm XXX网络名字
# 创建网络
[root@dk ~]# docker network create yao_network
ab0e49bb367fad508703d56a3ebf64e62891e18099fda65979696404cf5956b2
# 查看网络
[root@dk ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9f8332ff0fff bridge bridge local
d50ebcc074d6 cig_default bridge local
29aaf2bf1e84 composetest_atguigu_net bridge local
bebc5090e899 composetest_default bridge local
99c28be75fe0 host host local
b8d9199e67fe mywp_default bridge local
d16438fc9479 mywp_mywordpress bridge local
913260e62b5d none null local
ab0e49bb367f yao_network bridge local
# 删除网络
[root@dk ~]# docker network rm yao_network
yao_network
# 重新查看网络
[root@dk ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9f8332ff0fff bridge bridge local
d50ebcc074d6 cig_default bridge local
29aaf2bf1e84 composetest_atguigu_net bridge local
bebc5090e899 composetest_default bridge local
99c28be75fe0 host host local
b8d9199e67fe mywp_default bridge local
d16438fc9479 mywp_mywordpress bridge local
913260e62b5d none null local
网络模式 | 简介 |
---|---|
bridge | 为每一个容器分配、设置IP等,并将容器连接到一个docker0;虚拟网桥,默认为该模式 |
host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 |
none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网络桥连接、IP等 |
container | 新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围等 |
容器实例内默认网络IP生产规则:
第1步:先运行两个ubuntu容器实例
[root@dk ~]# docker run -it --name u1 ubuntu bash
[root@dk ~]# docker run -it --name u2 ubuntu bash
如果安装此命令报此错误—>WARNING: IPv4 forwarding is disabled. Networking will not work
# 第一步:在宿主机上执行
[root@dk ~]# echo "net.ipv4.ip_forward=1" >>/usr/lib/sysctl.d/00-system.conf
# 第二步:重启network和docker服务
[root@dk ~]# systemctl restart network && systemctl restart docker
第2步:docker inspect 容器ID 或者 容器名字
[root@dk ~]# docker inspect u1 | tail -n 20
第3步:关闭u2实例,新建u3,查看ip变化
总结:docker容器内部的ip是有可能会发生改变的
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
# 查看 bridge 网络的详细信息,并通过 grep 获取名称项
[root@dk ~]# docker network inspect bridge | grep name
"com.docker.network.bridge.name": "docker0",
[root@dk ~]# ifconfig | grep docker
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
说明
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
代码:
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
两两匹配验证:
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
说明:
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
案例:
[root@dk ~]# docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
WARNING: Published ports are discarded when using host network mode
db97ce1707f8d602db16108ee75fc57503a0cf4e4b0b6b8f1b8e2009d67edc88
**问题:**docker启动时总是遇见标题中的警告
**原因:**docker启动时指定--network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
**解决:**使用docker的其他网络模式,例如--network=bridge,这样就可以解决问题,或者直接无视。
[root@dk ~]# docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
无之前的配对显示了,看容器实例内部
没有设置-p的端口映射了,如何访问启动的tomcat83??
在CentOS里面用默认的火狐浏览器访问容器内的tomcat83看到访问成功,因为此时容器的IP借用主机的,所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。
在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo。需要我们自己为Docker容器添加网卡、配置IP等。
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
案例:
[root@dk ~]# docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
3af3372d8a3140b6436548bf0cb6adb5b9abff3a6b49962b354754497cbc74da
# 进入容器内部查看
[root@dk ~]# docker exec -it tomcat84 bash
root@3af3372d8a31:/usr/local/tomcat# ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
# 在容器外部查看
[root@dk ~]# docker inspect tomcat84 | tail -n 20
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
案例1:
[root@dk ~]# docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
2cef03f7fe8020d19877708e1ae3ec69d0c9eeeac7cd72f37431e69854add531
[root@dk ~]# docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
See 'docker run --help'.
相当于tomcat86和tomcat85公用同一个ip同一个端口,导致端口冲突。本案例用tomcat演示有坑,换其他镜像。
案例2:
Alpine操作系统是一个面向安全的轻型 Linux发行版,是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。
[root@dk ~]# docker run -it --name alpine1 alpine /bin/sh
[root@dk ~]# docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
运行结果,验证共用搭桥
假如此时关闭alpine1,再看看alpine2,会发现38: eth0@if39: 消失了
docker官网不建议使用此网络,最终将会被移除,所以这里不做讲解!
从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。
Docker-Compose是Docker官方的开源项目, 负责实现对Docker容器集群的快速编排。
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
https://docs.docker.com/compose/compose-file/compose-file-v3/
https://docs.docker.com/compose/install/
# 下载链接1
[root@dk ~]# curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 下载链接2
[root@dk ~]# curl -L https://get.daocloud.io/docker/compose/releases/download/v2.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
[root@dk ~]# chmod +x /usr/local/bin/docker-compose
[root@dk ~]# docker-compose --version
[root@dk ~]# sudo rm /usr/local/bin/docker-compose
一个文件:docker-compose.yml
两个要素:
一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
忽略,待整理,直接看5.8
什么是YAML
YAML 是 "YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。
YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
YAML 的配置文件后缀为 .yml,如:docker-compose.yml 。
案例1:使用Compose部署Tomcat + MySQL
第1步:准备镜像tomcat和mysql,如果已经有此镜像请忽略
[root@dk ~]# docker pull tomcat
[root@dk ~]# docker pull mysql:5.7
第2步:创建文件夹/composetest,并在该目录下创建文件docker-compose.yml。
[root@dk ~]# mkdir /composetest
[root@dk ~]# cd /composetest
[root@dk composetest]# cat docker-compose.yml
version: '3.1'
services:
tomcat:
restart: always
image: tomcat
container_name: tomcat
ports:
- 8080:8080
volumes:
- /usr/local/docker/tomcat/webapps:/usr/local/tomcat/webapps
environment:
TZ: Asia/Shanghai
mysql:
restart: always
image: mysql:5.7
container_name: mysql
ports:
- 3306:3306
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123456
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
--sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
volumes:
- /usr/local/docker/mysql:/var/lib/mysql
[root@dk composetest]# docker-compose up -d
# 如果出现done、done则表示成功!
第3步:访问tomcat地址
注意:此步骤会出现404错误,8.2章节的内容不再适合修改,因为删除webapps时已经有容器数据卷,所以删除webapps文件夹时会报错,应当把webapps.dist里的内容拷贝到webapps目录下。
第4步:检查MySQL是否可以正常登陆
第1步:准备镜像mysql5.7和wordpress,不提供代码,代码自行编写。
[root@dk ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 10 months ago 141MB
wordpress latest c3c92cc3dcb1 11 months ago 616MB
mysql 5.7 c20987f18b13 11 months ago 448MB
第2步:创建yml文件
[root@dk mywp]# cat docker-compose.yml
version: '3.1' #compose文件版本
services:
mysql: # 服务1:mysql
image: mysql:5.7 # 使用镜像 mysql:5.7版本
volumes:
- /use/local/docker/mysql:/var/lib/mysql # 数据持久化
restart: always # 容器服务宕机后总是重启
ports:
- "3307:3306"
environment: # 环境配置
MYSQL_ROOT_PASSWORD: root12345 #数据库root用户密码
MYSQL_DATABASE: wordpress #wordpress数据库名称
MYSQL_USER: wordpress #数据库用户名
MYSQL_PASSWORD: 123456 #数据库密码
wordpress: # 服务2:wordpress
depends_on: # wordpress服务启动时依赖mysql服务,所以会自动先启动mysql服务
- mysql
image: wordpress:latest # 使用镜像 wordpress:latest最新版
ports:
- "8080:80" #端口映射8000:80
restart: always
environment: # 环境
WORDPRESS_DB_HOST: mysql:3306 # wordpress连接db的3306端口
WORDPRESS_DB_USER: wordpress # 数据库用户为wordpress
WORDPRESS_DB_PASSWORD: 123456 # 数据库密码是123456
WORDPRESS_DB_NAME: wordpress # 数据库名字是wordpress
第3步:执行
[root@dk mywp]# docker-compose up -d
第4步:访问地址看结果
JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域。
分为以下x个步骤:
1、先下载两个jar包,放入libs下
2、mysql、jira用于存放配置文件、日志文件、数据文件
3、编写docker-compose.yml文件
4、创建数据库
4、测试运行
[root@dk jira]# tree ./
./
├── docker-compose.yml
├── jira
├── libs
│ ├── atlassian-agent.jar
│ └── mysql-connector-java-5.7.36.jar
└── mysql
3 directories, 3 files
编写docker-compose.yml文件:
[root@dk jira]# cat docker-compose.yml
version: '3.1'
services:
mysql:
container_name: mysql
image: mysql
restart: always
ports:
- 3308:3306
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./mysql/conf:/etc/mysql/conf.d
- ./mysql/logs:/var/log/mysql
- ./mysql/data:/var/lib/mysql
command:
--character-set-server=utf8mb4
jira:
container_name: jira
image: atlassian/jira-software:latest
restart: "no"
ports:
- 8080:8080
environment:
CATALINA_OPTS: -javaagent:/opt/atlassian/jira/atlassian-agent.jar
volumes:
- ./jira/data:/var/atlassian/application-data/jira
- ./libs/atlassian-agent.jar:/opt/atlassian/jira/atlassian-agent.jar
- ./libs/mysql-connector-java-8.0.27.jar:/opt/atlassian/jira/lib/mysql-connector-java.jar
启动容器:
[root@dk jira]# docker-compose up -d
创建数据库:
CREATE DATABASE jiradb;
create user 'jira'@'%' identified by 'jira';
grant all privileges on jiradb.* to 'jira'@'%';
flush privileges;
设置Jira:
在浏览器上打开:http://IP:8080
1、点击右上角Language,设置中文
2、选择我将设置它自己
,点击下一步
3、数据库设置,选择其它数据库,根据文本提示填入相应内容,点击测试连接,通过后点击下一步
4、设置应用程序的属性,采用默认值就行,直接点击下一步
5、设置许可证,如果本地有Java环境,可以在本地生成许可证,或者进入jira容器生成
执行命令,带上服务器ID,服务器ID写自己电脑上的,生成许可证:
root@61bf39400f8a:/opt/atlassian/jira# java -jar atlassian-agent.jar -d -m test@test.com -n BAT -p jira -o lewis2951 -s 服务器ID
6、设置管理员账户,根据自己的需求设置,设置Email地址
7、设置电子邮件通知,可以选择以后再说
8、完成部署
9、查看许可证
大体步骤分为以下四步
1、下载所需的文件tomcat,jdk 2、编写dockerfile来布署tomcat与java环境,生成镜像文件 3、编写docker-compose.yml配置文件,启动所有容器服务 4、测试负载均衡
[root@localhost java]# tree ./
./
├── docker-compose.yml
├── nginx
│ └── nginx.conf
├── tomcat
│ ├── apache-tomcat-8.5.79.tar.gz
│ ├── Dockerfile
│ └── jdk-8u333-linux-x64.tar.gz
└── webserver
├── tomcatA
│ └── index.jsp
└── tomcatB
└── index.jsp
5 directories, 7 files
[root@localhost java]# cat webserver/tomcatA/index.jsp
welcome to Tomcat-A server
[root@localhost java]# cat webserver/tomcatB/index.jsp
welcome to Tomcat-B server
# 编写docker-compose.yml文件
[root@master java]# cat docker-compose.yml
version: "3"
services:
nginx:
image: nginx:1.14
restart: always
ports:
- 80:80
links:
- tomcat1:tomcat1
- tomcat2:tomcat2
volumes:
- ./webserver:/webserver
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
environment:
TZ: Asia/Shanghai
depends_on:
- tomcat1
- tomcat2
tomcat1:
hostname: tomcat1
build: ./tomcat
volumes:
- ./webserver/tomcatA:/usr/local/apache-tomcat-8.5.79/webapps/ROOT
environment:
TZ: Asia/Shanghai
tomcat2:
hostname: tomcat2
build: ./tomcat
volumes:
- ./webserver/tomcatB:/usr/local/apache-tomcat-8.5.79/webapps/ROOT
environment:
TZ: Asia/Shanghai
#安装JAVA环境
[root@localhost java]# cat tomcat/Dockerfile
FROM centos
ADD jdk-8u333-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_333
ADD apache-tomcat-8.5.79.tar.gz /usr/local
EXPOSE 8080
ENTRYPOINT ["/usr/local/apache-tomcat-8.5.31/bin/catalina.sh", "run"]
编写nginx配置文件
[root@localhost java]# cat ./nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
client_max_body_size 10m;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
upstream tomcat_client {
server tomcat1:8080 weight=1;
server tomcat2:8080 weight=1;
}
server {
server_name "";
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
location / {
proxy_pass http://tomcat_client;
proxy_redirect default;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
启动所有容器服务
[root@localhost java]# docker-compose up -d
查看启动情况
[root@localhost java]# docker-compose ps
检测负载均衡
[root@localhost java]# curl http://localhost
welcome to tomcat-A server
[root@localhost java]# curl http://localhost
welcome to tomcat-B server
[root@localhost java]# curl http://localhost
welcome to tomcat-A server
[root@localhost java]# curl http://localhost
welcome to tomcat-B server
浏览器访问测试负载均衡
在浏览器上输入服务器地址就可以测试了,多刷新几次试试!!
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
[root@dk ~]# docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
设置admin用户和密码后首次登陆(设置密码为12345678,以防忘记)
选择local选项卡后本地docker详细信息展示
上一步的图形展示,能想得起对应命令吗?
[root@dk ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 10 10 3.185GB 77.79MB (2%)
Containers 49 1 202.7MB 202.7MB (100%)
Local Volumes 13 9 1.094GB 828MB (75%)
Build Cache 0 0 0B 0B
点击镜像看效果,这里的删除、新建、导入导出都很明确。
咱们再回去看看刚刚首页上的Stack(左侧列表中):
可以看到这里是用来存放咱们compose编排的界面,继续点开看看:
常规操作
# 先docker ps看一眼有什么正在运行:
[root@dk ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
13fbca891039 mysql:5.7 "docker-entrypoint.s…" 6 seconds ago Up 4 seconds 3306/tcp, 33060/tcp serene_gauss
9dc6e689c519 portainer/portainer "/portainer" 27 minutes ago Up 26 minutes 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp portainer
演示Logs操作、演示监控信息、演示命令行(Exec Console)
添加一个容器实例,内容随便填写一下发布即可。
还可以配置容器数据卷
通过docker stats
命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据。docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能。
容器监控3剑客:CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
CAdvisor是一个非常好用的容器监控工具,还可以和Prometheus整合,安装和使用都很简单。CAdvisor是一个容器资源监控工具,包括容器的内存CPU,网络IO,磁盘I0等监控,同时提供了一个WEB页面用于查看容器的实时运行状态。CAdvisor默认存储2分钟的数据, 而且只是针对单物理机。不过,CAdvisor提供了很多数据集成接口,支持InfluxDB,Redis,Kafka,Elasticsearch等集成,可以加上对应配置将监控数据发往这些数据库存储起来。
CAdvisor功能主要有两点:
- 展示Host和容器两个层次的监控数据
- 展示历史变化数据
InfluxDB是用Go语言编写的一个开源分布式时序、事件和指标数据库,无序外部依赖。
CADvisor默认只在本机保存最近2分钟的数据,为了持久化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合存储CADvisor的数据,而且,CADvisor本身已经提供了InfluxDB的集成方法,启动容器时指定配置即可。
主要功能:
Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置和丰富的插件及模板功能,支持图表权限控制和报警。
主要功能:
第1步:新建目录
[root@dk ~]# mkdir /cig && cd /cig
第2步:新建docker-compose.yml文件,内容如下:
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
第3步:输入网址测试,第一次加载较慢
http://192.168.170.151:8080/containers/
第4步:
cadvisor也有基础的图形展现功能,这里主要用它来作数据采集
ip+3000端口的方式访问,默认帐户密码(admin/admin)
第5步:配置数据源—>选择influxdb数据源
点击Save & test,出现Data source is working
则表示成功!
第6步:配置面板panel
到这里CAdvisor + InfluxDB + Grafana容器监控系统就部署完成了
步骤1:拷贝o2server.zip文件,或者在Linux里使用wget命令下载压缩包,下载地址为:
https://download.o2oa.net/download/o2server-7.2.6-linux-x64.zip
步骤2:使用unzip命令解压安装包
步骤3:制作Dockerfile文件
FROM tomcat:8.5
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asiz/Shanghai' > /etc/timezone
RUN groupadd yaoge
RUN useradd yaoge -g yaoge -u 1000
RUN mkdir -p /data/o2server
COPY o2server /data/o2server/
RUN chown -R yaoge:yaoge /data
ENTRYPOINT ["/bin/sh","-c","/data/o2server/start_linux.sh && tailf /etc/localtime"]
步骤4:docker build 制作镜像,镜像名为oa
步骤5:镜像制作完毕后将镜像存储为tar包进行保存,gzip没有请先安装,保存命令:
docker save oa | gzip > oa.tar
步骤6:docker run检查镜像是否能够正常启动
执行 systemctl stop docker
后提示“Warning: Stopping docker.service, but it can still be activated by: docker.socket”
解释: 这是docker在关闭状态下被访问自动唤醒机制,很人性化,即这时再执行任意docker命令会直接启动
注:如果真的不希望docker被访问自动唤醒,执行 systemctl stop docker
后再执行systemctl stop docker.socket
即可
echo "net.ipv4.ip_forward=1" >>/usr/lib/sysctl.d/00-system.conf
# 重启网卡、docker
systemctl restart network && systemctl restart docker
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。