Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离
,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为 容器 。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
Docker与传统虚拟机技术的不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核
,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便
。
Docker的优势
- 更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销
,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 - 更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核
,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 - 一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境
,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」** 这类问题。一次构建,到处运行
- 持续交付和部署
对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过Dockerfile
来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用Dockerfile
使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。 - 更轻松的迁移
由于 Docker确保了执行环境的一致性,使得应用的迁移更加容易
。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。 - 更轻松的维护和扩展
Docker 使用的分层存储以及镜像的技术
,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 | 特性 | 容器 | 虚拟机 | | —- | —- | —- | | 启动 | 秒级 | 分钟级 | | 硬盘使用 | 一般为MB
| 一般为GB
| | 性能 | 接近原生 | 弱于 | | 系统支持量 | 单机支持上千个容器 | 一般几十个 |
容器化的好处 ( 进程间隔离 ):
Docker 安装
服务器版
平台 | x86_64 / amd64 | ARM | ARM64 / AARCH64 | IBM Power (ppc64le) | IBM Z (s390x) |
---|---|---|---|---|---|
CentOS | ✔ | ✔ | |||
Debian | ✔ | ✔ | ✔ | ||
Fedora | ✔ | ✔ | |||
Ubuntu | ✔ | ✔ | ✔ | ✔ | ✔ |
- 卸载旧版本
apt-get remove docker docker-engine docker.io containerd - 使用 apt 进行安装
apt install docker.io
- 查看是否安装成功
docker version
如果在这里报错找不到 apt 源的话
执行
vi /etc/apt/sources.list
然后删除自带源,添加国内源
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multivers
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
然后
apt update
最后下载即可
apt install docker.io
Docker 镜像加速器
阿里云加速
https://cr.console.aliyun.com/cn-shanghai/instances/mirrors
- 进入阿里云控制台,搜索 容器镜像服务
- 找到专属加速服务
通过修改 daemon 配置文件
/etc/docker/daemon.json
来使用加速器
全部把xxxxxxx替换成上面那张图涂掉的那部分,然后全部 copy 然后回车tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxxx.mirror.aliyuncs.com"]
}
EOF
重启 docker :
systemctl daemon-reload
systemctl restart docker
- 验证:
docker info
体验第一个容器
基于虚拟的环境下如果想要使用 tomcat,则需要先装 jdk ,然后再装 tomcat;而基于容器化环境,则可以直接安装 tomcat 进行使用
通过下载 tomcat9.0.x 镜像的webapps目录为空。。因此可能会遇到以下巨坑,这里有两种解决方案 ( 推荐第二种 )
方案1:https://blog.csdn.net/yl405001832/article/details/104351039
方案2 https://www.cnblogs.com/canglongdao/p/12162269.html
Docker 架构
Docker 引擎
Docker 引擎是一个包含以下主要组件的客户端服务器应用程序
- 一种服务器,它是一种称为守护进程并且长时间运行的程序
- REST API 用于指定程序可以用来与守护进程通信的接口,并指示它做什么
- 一个有命令行界面 (CLI) 工具的客户端
Docker架构
- Docker 使用客户端 - 服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器
- Docker 容器通过 Docker 镜像来创建
- 容器与镜像的关系类似于面向对象编程中的对象与类,容器是镜像的示例 | Docker | 面向对象 | | —- | —- | | 容器 | 对象 | | 镜像 | 类 |
docker run 若在本地没有找到镜像,则会去仓库中找并下载该镜像,然后基于该镜像再创建一个容器
标题 | 说明 |
---|---|
镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板。 |
容器(Container) | 容器是独立运行的一个或一组应用。 |
客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker API (https://docs.docker.com/reference/api/docker_remote_api ) 与 Docker 的守护进程通信。 |
主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
仓库(Registry) | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com ) 提供了庞大的镜像集合供使用。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
Docker 操作镜像
获取镜像
docker pull [选项] [Docker Registry 地址[:端口号]]/仓库名[:标签]
EG:docker pull ubuntu:18.04
这个命令等同于:docker pull registry.hub.docker.com/ubuntu:12.04
相当于从默认注册服务器 registry.hub.docker.com 中的 ubuntu 仓库上下载了标签为 12.04 的 ubuntu 镜像
从官方下载比较慢时,可以通过 指定注册服务器 来从其他仓库进行下载
EG:docker pull dl.dockerpool.com:5000/ubuntu:18.04
列出镜像
docker images
- 显示本地已有镜像
列信息
- 来自哪个仓库
- 镜像标签
- 唯一 ID 号
- 创建时间
- 镜像大小
其中镜像的 ID
唯一标识了镜像, 具有相同的镜像 ID
的两个镜像,实际上是同一镜像。
TAG
信息用来标记来自同一个仓库的不同镜像。例如 ubuntu
仓库中有多个镜像,通过 TAG
信息来区分发行版本,例如 10.04
、12.04
、12.10
、13.04
、14.04
等。例如下面的命令指定使用镜像 ubuntu:14.04
来启动一个容器。
可以看到,上面有个 TAG 为 none 的镜像,这在镜像又被称为 虚悬镜像
显示镜像体积
docker system df
中间层镜像
为了加速镜像构建,重复利用资源,Docker 会利用 中间层镜像 ,所以在使用一段时间后,可能会看到一些依赖的中间层镜像docker image ls -a
删除镜像
移除本地镜像使用
docker rmi 镜像名:[标签] / 镜像ID
docker rm 是删除容器的
注意:在删除镜像之前要先用 docker rm 删掉依赖于这个镜像的所有容器
清除所有虚悬镜像
docker image prune
commit
docker commit -m="提交描述信息" -a="作者" 容器id 生成镜像名[:tag]
Docker 操作容器
显示容器
显示运行中的容器
docker ps
显示所有容器,包括运行的和没运行的
docker ps -a
启动容器
docker 本身形成了一个内网,因此 docker 需要网卡
docker的网卡
同时,每个容器本身又相当于一台内网中的服务器,因此也需要网卡
容器的网卡
1.新建并启动
docker run
docker本身形成了一个内网,因此想要访问 docker 内的容器,就需要指定容器端口
EG:docker run -p 8088:8080 -d tomcat
`参数 -p` 表示进行端口映射,宿主机端口 : 容器端口,用户访问宿主机的端口时,会**路由到指定的容器端口**,从而进行访问。不使用该参数则会进行默认映射 ( 如tomcat会默认进行8080的映射 )
`参数 -d` 表示后台运行该容器 ( daemon 守护态运行)
当时用 docker run 来创建容器时,Docker 在后台运行的标准操作包括
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
2.启动已停止容器
docker start 已停止运行的容器的ID
停止容器
docker stop 容器ID
删除容器
普通删除
docker rm 容器ID / 容器名
无法删除正在运行的容器
强制删除 (先停掉再删除)
docker rm -f 容器ID / 容器名
交互式操作容器
就跟操作 Linux 中的文件一样操作容器里面的文件 ( 使用 bash 操作容器 )
docker exec -it 容器ID/容器名 /bin/bash
退出容器
ctrl + d
查看容器日志
docker logs -f 容器名
清除所有处于终止状态的容器
查看所有已经创建的,包括终止状态的容器
docker container ls -a
清除所有处于终止状态的容器
docker container prune
Docker 查看日志
docker logs [OPTIONS] container_name
Options:
--details 显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)
DockerFile 定制镜像
DockFile 是一个文本文件,其中包含了一条一条的指令,每一条指令构建一层,因此每一条指令的内容就是描述该层该如何构建
- 创建DockFile
名字必须为Dockfile)
vim Dockerfile
先来看一个很简单的 DockFile 配置文件
FROM tomcat
COPY index.jsp /usr/local/tomcat/webapps/ROOT
这段代码的意思就是,继承 tomcat 镜像,然后将当前目录下的 index.jsp 文件复制到镜像的指定目录下
- 构建新镜像
docker build -t myTomcat .
这样就构建出了一个叫 myTomcat 的新镜像,具有 tomcat 的所有功能 ( 继承 ) ,但 /usr/local/tomcat/webapps/ROOT 中的 index.jsp 文件使我们指定的 copy 的 index.jsp 文件
- 查看镜像
镜像构建上下文
在第二步构建新镜像中,使用到了一个 .
,这个 . 有两个作用
- 在当前目录找到 Dockerfile 配置文件
- 指定 Dockerfile 的上下文目录打包并传递 —-> Docker Server,真正的打包过程是在 Docker Server 中进行的
因此对文件而言,应该指定的不是其在宿主机中的路径,而是在上下文中的路径 ( 指定 COPY 的文件应该和 Dockerfile 同级或同级目录下,即COPY的是相对路径 )
当构建时,用户指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将这个路径下 并且被 Dockerfile 使用的文件进行打包,然后上传给 Docker Server, 这样 Docker Server 在收到这个上下文包后,就会对相应内容进行打包并制作成镜像
Dockrfile 指令
RUN
运行 shell 指令
COPY
- 格式:
- shell格式:
COPY <源路径> <目标路径>
- exec格式:
COPY ["<源路径>" "<目标路径>"]
- shell格式:
COPY 指令将从构建上下文目录中的 <源路径> 中的文件/目录复制到新的一层镜像内的 <目标路径>
COPY package.json /usr/src/app
<源路径> 可以是多个,甚至可以是通配符,其通配符规则满足 go 的 filepath.Math 规则
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>是容器内的绝对路径,也可以是相对于工作目录的相对路径 ( 工作目录可以通过 WORKDIR 指令来指定 ),目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建确实目录
COPY 指令,会将源文件的各种元数据进行保留,比如读,写,执行权限,创建时间等
ADD
和 COPY 的格式和性质基本一样
,但是在 COPY 的基础上增加了一些功能- ADD
- ADD 的 <源路径> 可以是一个 URL 这种情况下,Docker Server 会试图去下载这个链接的文件放到 <目标路径> 去,下载后的权限自动设置为 600,如果不想要默认的权限,则需要额外加一层 RUN 指令进行调整;
- 如果下载的是个压缩包,需要解压缩,也是需要一层 RUN 指令进行解压缩,所以不如直接使用 RUN 指令,然后使用工具进行下载,因此 <源路径> 为URL的情况并不常用
- 但是,如果 <源路径> 是一个
tar 压缩文件
,压缩格式为gzip,bzip2 以及 xz
的情况下, ADD 指令会自动解压缩这个文件
到 <目标路径>
- ADD
CMD
- CMD 和 ENTRYPOINT 相似,用于执行脚本
- shell格式:
CMD <命令>
- exec格式:
CMD ["可执行文件", "参数1", "参数2"...]
- shell格式:
普通的 CMD 指令只能执行一次
命令
ENTRYPOINT
- ENTRYPOINT 的格式和 RUN 格式一样,分为 exec 格式和 shell 格式
- ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数,ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 —entrypoint 来指定
- 当指定 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令
<ENTRYPOINT> "<CMD>"
因此 ENTRYPOINT 就解决了普通 CMD 指令只能执行一次的情况
但是~,ENTRYPOINT 也只准用一次
因此,当 CMD 命令比较多时,一般会把 CMD 弄成一个 shell 文件,然后用 ENTRYPOINT 来执行这个 shell 文件
ENV
- 格式
ENV <key> <value>
ENV <key>=<value> <key2>=<value2>...
设置环境变量
ENV MYSQL_VERSION 5.7.2
VOLUME
数据卷,后面会说
EXPOSE
- 格式:
EXPOSE <端口1> [<端口2>...]
EXPOSE 指令是声明运行时容器提供服务的端口,只是一个声明。在运行时并不会因为这个声明,应用就会开启这个端口的服务。
- 在 Dockerfile 中写入这样的声明有两个好处
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
- 另一个用处则是在运行时使用端口映射时,也就是 docker run -p 时,会自动映射 EXPOSE 的端口
WORKDIR
- 格式
WORKDIR <工作目录路径>
使用 WORKDIR 指令可以指定工作目录 (又称为当前目录),就是指定哪个目录下运行后面的 shell
也是指定容器的 初始目录 (就是进入容器以后在哪)
看一个完整一点的例子
FROM tomcat
#删除ROOT目录下所有东西
RUN rm -fr /usr/local/tomcat/webapps/ROOT/*
#复制到指定目录
COPY myTest.tar.gz /usr/local/tomcat/webapps/ROOT
#指定工作目录
WORKDIR /usr/local/tomcat/webapps/ROOT
#已经指定了工作目录,因此这个解压并删除是在工作目录下进行的
RUN tar -zxvf myTesy.tar.gz \
&& rm -rf myTest.tar.gz
#暴露端口
EXPOSE 8080
这个例子也可以写成这种格式
FROM tomcat
WORKDIR /usr/local/tomcat/webapps/ROOT
RUN rm -fr *
COPY myTest.tar.gz .
RUN tar -zxvf myTest.tar.gz \
&& rm -rf myTest.tar.gz
EXPOSE 8080
镜像的定制就是对 Dockerfile 进行命令的堆叠
Docker Compose
Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排 (简化 Docker 操作
)。从功能上看,跟 OpenStack 中的 Heat 十分类似
[Docker Hub](https://hub.docker.com/orgs?overlay=create)
Compose 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig
Docker Compose安装
Compose 支持 Linux、macOS、Windows 10 三大平台。在 Linux 上的也安装十分简单,从Docker官网下载最新稳定版处直接下载编译好的二进制文件即可
下载太慢可以切换到国内源
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
下载完后执行提权
sudo chmod +x /usr/local/bin/docker-compose
最后验证
docker-compose version
Dcoker Compose 的使用
前置准备
- 克隆两台虚拟机 ,一台命名为 deploy,一套命名为 Paas
1.固定IP 地址- 修改其中一台的 IP 地址
vim /etc/netplan/50-cloud-init.yaml
生效配置network:
ethernets:
ens33:
addresses: [192.168.224.129/24]
#网关地址为VMware中虚拟网络编辑里面的网关地址
gateway4: 192.168.224.2
nameservers:
#同网关地址
addresses: [192.168.224.2]
version: 2
netplan apply
- 修改其中一台的 IP 地址
2.修改主机名
- 修改 cloud.cfg 防止重启后主机名还原
```shell vim /etc/cloud/cloud.cfg
将下面的值改为true即可
preserve_hostname: true
- 修改主机名
```shell
#修改主机名
hostnamectl set-hostname deployment
#配置 hosts
cat >> /etc/hosts << EOF
192.168.224.132 services
EOF
3.修改 DNS
vim /etc/systemd/resolved.conf
取消 DNS 行的注释,配置一个 114.114.114.114 的 DNS 服务器,然后重启
开始使用
在 /usr/local 目录下创建 /docker/tomcat/ 目录用于进行测试,并进入 tomcat 目录下
- 创建一个
yml
的配置文件
命名为 docker-compose.yml
version: '3.1'
services:
tomcat:
restart: always
image: tomcat
container_name: tomcat
ports:
- 8080:8080
分析一下这个配置文件都干了些什么
tomcat :服务名
image:使用的镜像名称
container_name:命名容器
restart:重新启动策略,填 always 时系统重启时也会重启
no
是默认的重启策略,在任何情况下都不会重启容器。 on-failure
表示发生错误时进行重启
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
- 运行
守护态运行
docker-compose up -d
如果提示无权限,则执行命令
sudo chmod +x /usr/local/bin/docker-compose
- 停止
docker-compose down
注意: yml 配置文件区分制表符和空格
,对齐必须使用空格
Docker数据卷
使用 docker-compose 指定数据卷
volumes:
- ./webapps:/usr/local/tomcat/webapps.dist
volumes
即创建数据卷,右边是容器里面的目录,左边是宿主机目录,指定了数据卷的位置为 ./webapps
,即对 docker-compose.yml 而言的当前目录下的webapps中,两个目录是同步的
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS (联合文件系统),可以提供很多有用的特性:
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新,不会影响镜像
- 卷会一直存在,直到没有容器使用
联合文件系统
联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下 (unite several directories into a single virtual filesystem)。
联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
Docker 中使用的 AUFS(AnotherUnionFS)就是一种联合文件系统。 AUFS 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限,同时 AUFS 里有一个类似分层的概念,对只读权限的分支可以逻辑上进行增量地修改 (不影响只读部分的)。
Docker 目前支持的联合文件系统种类包括 AUFS, btrfs, vfs 和 DeviceMapper。
数据卷创建
在用 docker run
命令的时候,使用 -v
标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷。
下面创建一个 web 容器,并加载一个数据卷到容器的 /webapp
目录。
docker run -d -P --name web -v /webapp training/webapp python app.py
注意:也可以在 Dockerfile 中使用
VOLUME
来添加一个或者多个新的卷到由该镜像创建的任意容器。或者是在 docker-compose 中指定 volumes 属性,左边为宿主机文件夹,右边为容器文件夹
1.挂载一个主机目录作为数据卷
使用 -v
标记也可以指定挂载一个本地主机的目录到容器中去。
run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
上面的命令加载主机的 /src/webapp
目录到容器的 /opt/webapp
目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。
注意:Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前不支持。
Docker 挂载数据卷的默认权限是读写,用户也可以通过 :ro
指定为只读。
docker run -d -P --name web -v /src/webapp:/opt/webapp:ro
training/webapp python app.py
加了 :ro
之后,就挂载为只读了。
2.挂载一个本地主机文件作为数据卷
-v
标记也可以从主机挂载单个文件到容器中
sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
这样就可以记录在容器输入过的命令了。
注意:如果直接挂载一个文件,很多文件编辑工具,包括
vi
或者sed --in-place
,可能会造成文件 inode 的改变,从 Docker 1.1 .0 起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。
部署 tomcat
docker-compose.yml
version: '3.1'
services:
tomcat:
restart: always
image: tomcat
container_name: tomcat
ports:
- 8080:8080
volumes:
- ./webapps:/usr/local/tomcat/webapps.dist
environment:
TZ: Asia/Shanghai
然后守护态启动
部署 MySQL
version: '3.1'
services:
db:
# 目前 latest 版本为 MySQL8.x
image: mysql
restart: always
environment:
#初始化密码
MYSQL_ROOT_PASSWORD: 123456
command:
#为制作的MySQL镜像指定参数
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
ports:
- 3306:3306
volumes:
- ./data:/var/lib/mysql
然后守护态启动
部署 SpringBoot 项目
需要先将 SpringBoot 项目中连接的数据库地址改为 宿主机IP:3306
然后成 jar 包
将 jar 包移动到服务器的一个目录下,在相同目录下通过 Dockerfile 制作一个镜像
FROM mysql
#内置jdk
FROM tomcat
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为app.jar
ADD demo-0.0.1-SNAPSHOT.jar app.jar
# 运行jar包
ENTRYPOINT ["java","-jar","app.jar"]
docker build -t blog .
然后制作 docker-compose.yml 方便启动
version: '3.1'
services:
blog:
restart: always
#选择刚才制作的镜像
image: blog
container_name: myblog
#右边是容器内的服务端口,即访问SpringBoot项目的端口;左边是映射到宿主机上,即外部访问的端口
ports:
- 80:8083
然后
docker-compose up -d
启动后访问 宿主机 IP : 80 端口即可
为持续集成与持续交付做准备
这里所有环境的搭建基于上面创建好的 Paas 虚拟机
Docker Compose 部署 GitLab
部署 GitLab
使用 Docker 来安装和运行 GitLab 中文版, docker-compose.yml 配置如下:
version: '3'
services:
gitlab:
image: 'twang2218/gitlab-ce-zh'
restart: always
#宿主机ip地址,或域名
hostname: '192.168.224.131'
environment:
TZ: 'Asia/Shanghai'
GITLAB_OMNIBUS_CONFIG: |
#gitlab进行拉取时的http地址
external_url 'http://192.168.224.131'
gitlab_rails['time_zone'] = 'Asia/Shanghai'
#GitLab项目中使用SSH进行拉取时的端口
gitlab_rails['gitlab_shell_ssh_port'] = 2222
unicorn['port'] = 8888
#使用nginx进行解析
nginx['listen_port'] = 80
ports:
#右边容器端口要与gitlab进行http拉取时的端口号一致,因为是80,所以上面可以不写
- '80:80'
- '443:443'
- '2222:22'
volumes:
- ./config:/etc/gitlab
- ./data:/var/opt/gitlab
- .logs:/var/log/gitlab
然后访问 192.168.224.131 ,会要求初始化密码,初始化密码后使用用户名 root 和密码
登录即可
安装 TortoiseGit
https://tortoisegit.org/download/
下载对应版本和对应汉化包
先安装第一个,可以一路默认,也可以更改安装位置
然后安装第二个进行汉化
右击任意位置
然后设置为中文,应用并重新打开
使用 TortoiseGit 提交和克隆 GitLab
- 先在 GitLab 中新建一个项目
使用这个链接,最好新建一个专门用来推送和克隆的空白文件夹
- 右击空白文件夹,选择克隆
- 克隆下来以后,把自己的项目复制进这个文件夹
- 然后右键将提交到 GitLab,注意,第一次会让你输入 GitLab 的账号和密码
SSH 的方式进行拉取和推送
在协同开发的持续集成和持续交付中,一般不采用输入账户名和密码的方式进行平台的登录,因为会导致平台的同步并阻塞,一旦有一个人没有输入账号和密码,后面登录的人就会一直排队
因此使用 SSH 进行免密登录更为常用
1.生成秘钥
前往安装 Git 的目录下:D:\Git\usr\bin
找到这个文件
在该目录下启动 cmd,输入命令
ssh-keygen -t rsa -C "you_email"
因为我已经生成过秘钥,所以这里就选了 n,到生成 key 的目录下
特别注意!!!慎重选择在生成秘钥时是否设置密码
- 如果设置了,则每次对仓库进行操作都需要输入密码进行验证 (目前没有找到持久化的方法)
- 如果没设置,就不用
打开 .pub 复制里面的内容,回到 GitLab
2.配置 GitLab
将刚才生成的 .pub 公钥的内容粘贴到
生成 SSH
回到项目中,项目变为默认使用 SSH
3.测试
删除原来拉取下来的项目,重新使用 SSH 的方式进行拉取
可能会有个报错:Disconnected no supported authentication methods available(server sent: publickey)
解决方法:修改乌龟 git 里面的 ssh 客户端为你自己的客户端
在拉取的时候可能会要你输入密码短语 ( 取决于生成秘钥时是否设置了密码 )
最后:
Docker Compose 部署 Nexus
Nexus 是强大的 Maven 仓库管理器 ( 私服 ),简化了内部仓库的维护和外部仓库的访问。
将内部使用的依赖上传到私服,提高了安全性也提高了协同开发的效率
这样 maven 进行依赖下载时,顺序如下
- 本地仓库查找
- 若没有,到指定仓库查找
- 仍然没有,到官方仓库查找
部署 Nexus
制作 docker-compose
version: '3.1'
services:
nexus:
restart: always
image: sonatype/nexus3
container_name: nexus
ports:
- 8081:8081
volumes:
- ./data:/nexus-data
启动发现报错
解决方案1
:这是由于 /data/instances 目录没有权限造成的,因此进入 data 目录,修改 instances 的权限
chmod 777 instances
解决方案2
:修改 docker-compose 为
version: '3.1'
services:
nexus:
restart: always
image: sonatype/nexus3
container_name: nexus
ports:
- 8081:8081
volumes:
- nexus-data:/nexus-data
#外部指定数据卷位置
volumes:
nexus-data:
这种方法中的数据卷位置为 /var/lib/你的nexus父目录/volumes
下,该目录下的 docker_compose的目录名_nexus-data(即自己的命名)
这个目录就是数据卷
访问一下
右上角进行登录,发现如下提示
到 data 目录下找到该文件,复制内容,回到 Nexus 进行登录,用户名为 amdin,密码即为刚才的内容。登陆后会要求设置新密码,设置后全部 next 即可
了解 Nexus 的 Maven 仓库
代理仓库 (Proxy Repository)
- 第三方仓库
- maven-central 通过设置代理来连接到第三方仓库,从第三方下载到私服,这样下次就不用再去第三方仓库找了
- nuget.org-proxy
- 版本策略
- Release:正式版
- Snapshot:快照版 (开发版),在不更改版本号的情况下进行功能变更
- Mixed:混合模式
- 布局策略 ( Layout Policy )
- Strict:严格
- Permissive:宽松
根据语义化规范,版本号蕴意如下
EG:V2.0.4
2 | 0 | 4 |
---|---|---|
改架构的次数 | 改功能的次数 | 改bug的次数 |
任意一位 +1 时,后面的所有位退回为 0
宿主仓库 (Hosted Repository)
- 存储本地上传的组件和资源
- maven-release
- maven-snapshots
- nuget-hosted
仓库组
- 一个仓库包含多个仓库的内容
- maven-public
在项目中使用 Nexus
上传规则:在 pom 中,若 0.0.1-SNAPSHOT 后面跟 SNAPSHOT 则为快照版,否则为发行版,Nexus 会根据后缀判断应该放到哪个仓库里
在中央仓库设置认证
配置节点
打开项目使用的 maven 的 settings 文件,在 中添加
<server>
<id>maven-releases</id>
<username>admin</username>
<password>123456</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>123456</password>
</server>
这里的 id 需要等下和 pom 文件中对应,username 和 passwd 即上一步设置的用户名和密码
配置
在 pom 中进行管理配置,id 要和上一步中配置的 中的 id 相同
<distributionManagement>
<repository>
<id>maven-releases</id>
<name>nexus releases repo</name>
<url>http://192.168.224.131:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-snapshots</id>
<name>nexus snapshots repo</name>
<url>http://192.168.224.131:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
配置代理仓库
在 pom.xml 中配置代理仓库
<!--依赖仓库-->
<repositories>
<repository>
<id>nexus</id>
<name>nexus respository</name>
<url>http://192.168.224.131:8081/repository/maven-public/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!--插件仓库-->
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>nexus plugin</name>
<url>http://192.168.224.131:8081/repository/maven-public/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
验证配置是否成功
找到本地的 maven 仓库,删掉一些项目中所用的依赖,重新打包一下项目
回到 nexus 查看中央仓库
上传
mvn deploy
deploy 指令包含了 install,install 指令包含了 package。因此会在本地仓库生成一个和 对应的路径,该路径下的会有一个和 同名的路径,然后进入 会有一个和 同名的路径,其中有一个 jar 包
回到 Nexus,可以看见成功上传
因为我的 pom 文件中版本为 snapshot,因此上传到了 snapshots 的仓库
Docker Compose 部署Harbor
PS:Harbor 是一个典型的分布式架构,因此在重启虚拟机后一定要去 harbor 的目录下使用 docker compose 启动没有启动的项目
Harbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器,通过添加一些企业必须的功能特性,例如安全,标识和管理等,扩展了开源 Docker Distribution。作为企业级的私有 Registy 服务器,Harbor 提供了更好的性能和安全性,提升用户使用 Registy 构建和运行环境时传输镜像的效率。Harbor 支持安装在多个 Registy 节点的镜像资源复制,镜像全部保存在私有 Registry 中,确保数据和知识产权在公司内部网络中管控,Harbor 也提供了用户管理,访问控制,活动审计的高级安全特性
Harbor 特性
- 基于角色的访问控制 (RBAC):用户和 Docker 镜像仓库通过 “项目” 进行组织管理,一个用户可以对多个镜像仓库在同一命名空间 (project) 里拥有不同权限
- 镜像赋值:镜像可以再多个 Registy 实例中复制 (同步),适合于负载均衡,高可用,混合云和多云的场景
- web界面:用户可以通过浏览器来浏览,检索当前 Docker 镜像仓库,管理项目和命名空间
- AD/LDAP支持:Harbor 可以集成企业内部已有的 AD/LDAP,进行权鉴认证管理
- 审计管理:所有针对镜像仓库的操作都可以被记录追溯,用于审计管理
- 国际化
- RESTful API:提供给管理员对 Harbor 更多的操控,使得与其它管理软件集成更容易
- 部署简单:提供在线和离线两种安装工具,也可以安装到 vSphere 平台 ( OVA方式 ) 的虚拟设备上
Harbor 组件
- Proxy:Harbor 的 registry, UI,token 等服务,通过一个前置的反向代理统一接收web,Docker 客户端的请求,并将请求转发给后端不同的服务
- Registry:负责储存 Docker 镜像,并处理 docker push/pull 命令,由于需要对用户进行访问控制,即不同用户对 Docker 镜像有不同的读写权限,Registy 会指向一个 token 服务,强制用户每次 docker pull/push 请求都要携带一个合法的 token,Registy 会通过公钥对 token 进行解密验证
- Core Service:Harbor 的核心功能,主要提供一下服务
- UI:web界面,帮助管理 registry 服务器上的镜像,并对用户进行授权 (
前后端分离
) - WebHook:registry 上配置的 webhook 或把状态变化及时传递给 UI 模块 (类似于观察者模式的
监控
) - Token:负责根据用户权限给每个 docker push/pull 命令签发 token,docker 客户端向 registry 服务发起请求,如果不含 token,则会被重定向到这里,获得token 后重新发起请求 (
授权鉴权
)
- UI:web界面,帮助管理 registry 服务器上的镜像,并对用户进行授权 (
- Database:为 core services 提供数据库服务,负责存储用户权限,审计日志,docker 镜像分组信息等数据
- Job Services:提供镜像远程复制功能,可以把本地镜像同步到其它 Harbor 实例中 (
同步复制集群
) - Log Collector:帮助监控 Harbor 运行,负责收集其他组件的 log
安装
- 上传到虚拟机上
- 解压
tar -zxvf harbor-offline-installer-v1.10.2.tgz
- 修改配置文件
vim harbor.yml
#修改为服务器 IP (即Paas的ip)
hostname: reg.mydomain.com
如果没有 https 的证书请注释掉这一块,不然安装会报错
- 执行安装脚本
./install.sh
- 安装好以后会在当前目录下自动生成一个 docker-compose,启动即可
- 访问配置文件中的 hostname : port
- 所有有关harbor的配置信息都在harbor.yml下。用户名默认为 admin,密码为 Harbor12345
配置客户端
- 让
/etc/docker/daemon.json
中内容如下
{
"registry-mirrors": ["https://9b35jrsu.mirror.aliyuncs.com"],
//harbor的hostname:port
"insecure-registries": ["192.168.224.131:9999"]
}
- 重启 docker
systemctl restart docker
- 验证
docker info
推送镜像
- 新建一个项目,进入项目
- 在推送之前需要进行登录,不然无法推送
docker login 192.168.224.131:9999
#或者使用命令
docker login 192.168.224.131:9999 -u admin -p Harbor12345
- 通过第一步中的推送命令进行推送
#先标记,tag source_image[:tag] /new_image_name[:tag]
docker tag mytest 192.168.224.131:9999/blog/mytest
#再推送
docker push 192.168.224.131:9999/blog/mytest
- 验证,回到 harbor 的 blog 项目界面
- 测试镜像拉取
复制命令
docker pull 192.168.224.131:9999/blog/nginx:latest
然后先把原来的镜像删了
然后再进行拉取
拉取成功
体验一次构建,到处运行
- 使用
mvn deploy
打包项目并上传到 Nexus
- 在 Paas 虚拟机上构建一个镜像
创建一个目录,然后上传打包好的项目的 jar 包,使用 Dockerfile 构建镜像
FROM mysql
FROM tomcat
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为app.jar
ADD demo-0.0.1-SNAPSHOT.jar app.jar
# 运行jar包
ENTRYPOINT ["java","-jar","app.jar"]
docker build -t blog .
- 使用 Docker compose 运行镜像
version: '3.1'
services:
myblog:
image: blog
container_name: blog
ports:
- 8089:8083
docker-compose up -d
- 访问
- push 镜像到 Harbor
docker tag blog 192.168.224.131:9999/blog/myblog
docker push 192.168.224.131:9999/blog/myblog
- 在 deployment 虚拟机上配置 Harbor 客户端
让 /etc/docker/daemon.json
中内容如下
{
"registry-mirrors": ["https://9b35jrsu.mirror.aliyuncs.com"],
//harbor的hostname:port
"insecure-registries": ["192.168.224.131:9999"]
}
- 在 deployment 上拉取镜像
先登录
docker login 192.168.224.131:9999 -u admin -p Harbor12345
再拉取
docker pull 192.168.224.131:9999/blog/myblog:latest
- 用 docker compose 运行
规范点,在 /usr/local/docker 目录下创建一个 myblog 的文件夹,编写一个 docker compose文件
version: '3.1'
services:
myblog:
image: 192.168.224.131:9999/blog/myblog
container_name: myblog
ports:
- 8999:8083
- 访问
运行成功
Docker Compose 网络设置
由于 docker 的隔离机制,不同的容器其实是在不同的局域网当中
默认情况下,compose 会为应用创建一个网络,服务中的每个容器都会加入该网络中。这样,溶剂就可以被该网络中的其它容器访问。同时,该容器还能以服务名称作为 Hostname 被其它容器访问
默认情况下,应用程序的默认网络名基于 compose 的工程名称,而项目名称基于 docker-compose.yml 所在目录的名称
同一个 compose 下直接互通
EG:一应用程序在名为 myapp 的目录中,并且 docker-compose.yml
如下所示
version: '3.1'
services:
web:
build: .
ports:
- 8000:8000
db:
image: postgres
当我们运行这个 docker-compose.yml
时,会执行以下几步:
- 创建一个名为
myapp default
的默认网络 - 使用 web 服务的配置创建的容器,以
web
这个名称加入网络 myapp default - 使用 db 服务的配置创建的容器,以
db
这个名称加入网络 myapp default
因此,这两个容器其实是在同一个网络中的,可使用服务名称 (web / db) 作为Hostname 相互访问。EG:web 这个服务可以使用postgres://db:5432 访问 db 容器
不同 compose 下的互通
由于不同的 compose 在启动时会在不同的网络下,因此我们可以自己创建一个网络,然后在想要互通的 compose 中指定加入的自定义网络
- 创建网络
docker network create myblog_netword
- 修改想要互通的容器的 compose ,指定要连接的网络
networks:
default:
external:
#网络名
name: myblog_netword
实战
- 在 deployment 虚拟机中进入 mysql 目录下,修改其 compose
- 在 deployment 虚拟机中进入进入 myblog 目录下,修改其 compose
- 删除 MySQL 的 compose 中的端口映射,不让其暴露在外网当中,只存在于 docker 内网
没有了端口映射,此时已经不准外网连接了
- 由于现在无法通过 IP 对 MySQL 服务进行访问了,因此 myblog 项目中就需要通过
网络中的服务名:端口号
,对另一个服务进行访问
- 重新打包项目,上传到 Paas 虚拟机的 /usr/local/docker/myblog 目录下,进入 Paas 虚拟机下对应目录,构建镜像
- 推送镜像
docker tag myblog 192.168.224.131:9999/blog/myblog
docker push 192.168.224.131:9999/blog/myblog
- 回到 deployment,拉取镜像
docker pull 192.168.224.131:9999/blog/myblog:latest
- 启动 myblog,访问界面
暴露端口给宿主机在进行开发时常用,但实际上上线的时候不应该暴露端口给宿主机,因为这样是不安全的