目录
Docker的介绍
2010年几个年轻人成立了一个做PAAS平台的公司dotCloud.起初公司发展的不错,不但拿到过一些融资,还获得了美国著名孵化器YCombinator的支持,后来微软谷歌亚马逊这样的大厂商也纷纷加入PAAS平台,竞争十分激烈,dotCloud举步维艰.
2013年可能是公司发展的不是很好,工程师又不想自己的努力付之东流,于是他们决定将他们的核心技术开源.这项技术就是docker.当时docker的功能就是将linux容器中的应用代码打包,可以轻松的在服务器之间进行迁移.
无心插柳柳成荫,docker技术风靡全球,于是dotCloud公司改名为docker Inc,并全面投入到docker的开发之中.
2014.6 Docker发布了第一个版本 Docker1.0
2014.7 获得C轮融资 $4000W
2015.4 获得D轮融资 $9500W
至今已经发布到docker
docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书,可以把hello word放在docker中,可以把网站放入docker中,可以把任何想得到的程序放在docker中.
Docker的思想
集装箱
没有集装箱之前运输货物,东西零散容易丢失,有了集装箱之后货物不容易丢失,我们可以把货物想象成程序,目前我们要把程序部署到一台新的机器上,可能会启动不起来,比如少一些配置文件什么的或者少了什么数据,有了docker的集装箱可以保证我们的程序不管运行在哪不会缺东西.
标准化
运输方式
docker运输东西有一个超级码头,任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去.对应的技术来说,比如我们要把台式机的应用部署到笔记本上,我们可能选择用QQ发过去或者用U盘拷过去,docker就标准化了这个过程,我们只需在台式机上执行一个docker命令,把鲸鱼派过来,把程序送到超级码头去,再在笔记本上执行一个docker命令,然后由鲸鱼把程序从超级码头送到笔记本上去.
存储方式
当我们把程序存储到笔记本上时,我们需要一个目录,且我们要记住这个目录,因为下次我们可能还要修改,有了docker之后我们就不用记住了程序在哪里了,我们使用的时候只需要一条命令就行了.
API接口
docker提供了一系列rest api的接口,包含了对docker也就是对我们的应用的一个启动停止查看删除等等,如当我们要启动tomcat时我们要执行startup命令,当我们要停止时要执行shutdown命令,如果不是tomcat,我们可能还需要一些别的命令.有了docker我们记docker的命令就可以对其进行操作.
隔离
我们在使用虚拟机时有自己的cpu,硬盘,内存,完全感觉不到外面主机的存在,docker也差不多,不过它更轻量,我们创建虚拟机可能要几分钟,但是docker只需要一秒.最底层的技术时linux一种内核的限制机制,叫做LXC,LXC是一种轻量级的容器虚拟化技术.最大效率的隔离了进程和资源.通过cgroup,namespace等限制,隔离进程组所使用的物理资源,比如CPU,MEMORY等等,这个机制在7,8年前已经加入到linux内核了,直到2013年docker出世的时候才火起来,大家可能奇怪为什么这么好的技术埋没这么多年都没人发现呢?英雄造时势,时势造英雄,如果没有云计算,敏捷开发,高频度的弹性伸缩需求,没有IT行业这么多年长足的发展,也就没有docker.
Docker的组成
镜像就像是集装箱,仓库就是超级码头,容器就是我们运行程序的地方.docker运行程序的过程就是去仓库把镜像拉到本地,然后用一条命令把镜像运行起来变成容器.
build:构建,就是构建镜像.
ship:运输,运输镜像,从仓库和主机运输.
run:运行的镜像就是一个容器.
build,ship,run和镜像,仓库,容器是一一对应的.
镜像
镜像的英文名交image.前面我们讲到了集装箱,鲸鱼拖着的所有集装箱就是一个镜像.
从本质上来说镜像就是一系列文件,可以包括我们应用程序的文件,也可以包括我们应用的运行环境的文件,既然是文件,那么是以什么样的格式在本地保存的呢?
说到存储格式,就要提到linux的一个存储技术,叫做联合文件系统,是一种分层的文件系统,可以将不同的目录挂到同一个虚拟文件系统下.
比如test1下有三个文件夹,test2下有两个文件夹,还有一个readme文件.联合文件系统就是可以在一个文件夹(test)中看到多个文件夹(test1,test2)中的内容.
通过这种方式可以实现文件的分层,test1可以把它看作第一层,test2可以把它看作第二层,每一层有每一层自己的文件,docker就是利用了这种分层的概念实现了镜像存储.
下图就是镜像的存储格式,这张图是分层的,最下面一层,上面也是一层层的好像集装箱罗列在一起.这就是镜像最直观的存储方式.下面是操作系统的引导,上面是linux操作系统,再上面是一些相关的软件,如果是我们自己的程序,就可以是tomcat,jdk,再往上是应用代码,每一层是我们自己都可以控制得,最上面一层先忽略不看,因为这是和容器有关的.注意一点,docker镜像系统的每一层都是只读的,然后把每一层加载完成之后这些文件都会被看成是同一个目录,相当于只有一个文件系统.docker的这种文件系统被称之为镜像.
容器
为了便于理解,大家可以把容器想象成虚拟机,每个虚拟机都有自己的文件系统,可以把图1整个一部分看成是文件系统,与虚拟机系统的区别是这里面的文件系统是一层一层的,并且最下面的n层都是只读的,只有上面一层是可写的.为什么要有可写的这层呢?大家的程序运行起来,势必会要写一些日志,写一些文件,或者对系统的某一些文件做一些修改,所以容器在最上面一层创建了可读可写的文件系统.
在程序的运行过程中,如果要写镜像文件时,因为镜像的每一层都是只读的,它会把文件的每一层拷到文件的最上层,然后再对它进行修改,修改之后,当我们的应用读一个文件时会从顶层进行查找,如果没有才会找下一层.
由于容器的最上一层是可以修改的,镜像是不能修改的,这样就能保证镜像可以生成多个容器独立运行,没有任何干扰.
仓库
我们的镜像是要在其它机器上运行,如何进行传输呢?
这就用到了docker仓库,我们要先把我们的镜像传到docker仓库中,再由目的地把docker仓库拉过去,这就完成了这样的一次传输过程.
谁提供了这样的仓库呢?docker自己提供了,hub.docker.com,但是非常慢,为了解决这个问题,国内很多公司也在做自己的仓库.比较知名的是由网易蜂巢提供的 https://c.163yun.com/hub#/m/home/
Docker的运行机制
拉取镜像的执行流程
docker pull 执行过程:
- 客户端将指令发送给docker daemon
- docker daemon 先检查本地images中有没有相关的镜像
- 如果本地没有相关的镜像,则向镜像服务器请求,将远程镜像下载到本地
启动容器的执行流程
docker run 执行过程:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系(简版linux系统),并在只读的镜像层外面挂载一层可读写层
- 从宿主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
Docker运行镜像的流程
- Docker Host是我们的docker宿主机(就是安装了docker的操作系统)
- Registry是docker拉取镜像的远程仓库,提供大量的镜像供下载,下载完成之后保存在Images中
- Docker Daemon是docker的服务线程,处理Docker客户端命令。
- Images 是Docker本地的镜像仓库,可以通过docker images查看镜像文件。
Docker常用命令
镜像的操作命令
# 1. 拉取镜像到本地
docker pull 镜像名称[:tag]
# 举个例子 tomcat
docker pull daocloud.io/library/tomcat:8.5.15-jre8
# 2. 查看全部本地的镜像
docker images
# 3. 删除本地镜像
docker rmi 镜像的标识
# 4. 镜像的导入导出(不规范)
# 将本地的镜像导出
docker save -o 导出的路径 镜像id
# 加载本地的镜像文件
docker load -i 镜像文件
# 修改镜像名称
docker tag 镜像id 新镜像名称:版本
容器的操作命令
# 1. 运行容器
# 简单操作
docker run 镜像的标识|镜像名称[tag]
# 常用的参数
docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像的标识|镜像名称[tag]
# -d: 代表后台运行容器
# -p: 宿主机端口:容器端口: 为了映射当前Linux的端口和容器的端口
# --name 容器名称: 指定容器的名称
# 2. 查看正在运行的容器
docker ps [OPTIONS]
# OPTIONS说明:
# -a: 代表查看全部的容器,包括没有运行
# -q: 只查看容器的标识
# -f: 根据条件过滤显示的内容
# --format: 指定返回值的模板文件
# -l: 显示最近创建的容器
# -n: 列出最近创建的n个容器
# --no-trunc: 不截断输出
# -s: 显示总的文件大小
# 3. 查看容器的日志
docker logs -f 容器id
# -f: 可以滚动查看日志的最后几行
# 4. 进入到容器内部
docker exec -it 容器id bash
# 5. 删除容器(删除容器前,需要先停止容器)
docker stop 容器id
# 停止指定的容器
docker stop $(docker ps -qa)
# 停止全部容器
docker rm 镜像id
# 删除指定容器
docker rm $(docker ps -qa)
# 删除全部容器
#6. 启动容器
docker start 容器id
数据卷的操作命令
数据卷介绍:将宿主机的一个目录映射到容器的一个目录中。
数据卷作用:可以在宿主机中操作目录中的内容,那么容器内部映射的文件,也会跟着一起改变。
# 1. 创建数据卷
docker volume create 数据卷名称
# 创建数据卷之后默认会存放在一个目录下 /var/lib/docker/volumes/数据卷名称/_data
# 2. 查看数据卷的详细信息
docker volume inspect 数据卷名称
# 3. 查看全部数据卷
docker volume ls
# 4. 删除数据卷
docker volume rm 数据卷名称
# 5. 应用数据卷
# 当你映射数据卷时,如果数据卷不存在。Docker会帮你自动创建
docker run -v 数据卷名称:容器内部路径 镜像id
# 直接指定一个路径作为数据卷的存放位置。这个路径下是空的。
docker run -v 路径:容器内部的路径 镜像id
Docker自定义镜像
中央仓库上的镜像,也是Docker的用户自己上传过去的。所以我们完全可以自己创建一个镜像.
# 1. 创建一个Dockerfile文件,并且指定自定义镜像信息。
# Dockerfile文件中常用的内容
from: 指定当前自定义镜像依赖的环境
copy: 将相对路径下的内容复制到自定义镜像中
workdir: 声明镜像的默认工作目录
cmd: 需要执行的命令(在workdir下执行的,cmd可以写多个,只以最后一个为准)
# 举个例子,自定义一个tomcat镜像,并且将ssm.war部署到tomcat中
from daocloud.io/library/tomcat:8.5.15-jre8
copy ssm.war /usr/local/tomcat/webapps
Docker镜像安装实践
安装MySQL数据库
拉取MySQL镜像
一种方法是在hub.docker.com上搜索mysql镜像,拉取指定版本的mysql,也可以指定拉取版本,如:
docker pull mysql:8.0.23
然后慢慢等待拉取下载完成,因为是从官网拉取,所以有点慢.
另一种方法是:事先获取到了mysql的压缩文件如 mysql.tar.gz,然后将它拖拉到相应目录下(我的目录是/root/setup/images/) ,然后然后进入该目录下使用如下命令也可以很快达到效果.我使用的是这种方法.
docker load -i mysql.tar.gz
查看镜像
然后可以查看一下mysql镜像,使用如下命令:
docker images
可以看到镜像已经存在了.
运行镜像
启动运行mysql镜像(docker run 用于启动一个容器),命令如下:
sudo docker run -p 3306:3306 --name mysql \
-v /usr/local/docker/mysql/mysql-files:/var/lib/mysql-files \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:8.0.23
假如安装过程中失败了,则可通过docker ps -a 查看以前的容器,假如已存在,则通过docker rm 镜像id 删除再重新安装即可。
登录MySQL服务
进入MySQL容器
进入容器的命令如下:
docker exec -it mysql bash #mysql是容器名
登录MySQL
登录mysql(密码是root),前提是进入了mysql容器.
mysql -uroot -proot
操作MySQL服务
停止服务
停止mysql服务命令:
docker stop mysql
启动服务
启动mysql服务命令:
docker start mysql
查看MySQL启动时日志
假如希望查看mysql启动时的日志,可以执行下面这个指令。
docker container logs mysql
设置MySQL开机自启动
如果需要设置mysql开机自动启动,可使用如下命令:
docker update mysql --restart=always
安装Redis数据库
拉取镜像文件
同拉取mysql数据库步骤一样,我这儿是在conf目录下拉取的,其实在哪儿无所谓,不用在意和我的不一样.
准备配置文件
需先准备一个目录,配置文件就放在这个目录下.创建目录如下:
mkdir -p /usr/local/docker/redis01/conf
然后在该目录下创建redis.conf配置文件 ,这个配置文件必须要创建,否在我们进行目录挂载时默认生成的是一个目录.
touch /usr/local/docker/redis01/conf/redis.conf
创建Redis实例并启动
命令如下:
sudo docker run -p 6379:6379 --name redis01 \
-v /usr/local/docker/redis01/data:/data \
-v /usr/local/docker/redis01/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
访问Redis服务
进入容器
进入容器命令:
docker exec -it redis01 bash
检查Redis版本
命令如下:
redis-server -v
或者:
redis-cli -v
登录Redis
登录redis,不需要使用密码:
redis-cli
安装Ngnix代理
拉取镜像
就不废话了.
创建数据卷
创建数据卷(这个对象会在宿主机直接创建一个目录)
docker volume create nginx-vol
查看目录
查看数据卷对应的宿主机目录,可以通过如下指令:
docker inspect nginx-vol
启动Nginx服务
使用以下命令启动服务:
docker run --name nginx -p 80:80 -v nginx-vol:/etc/nginx -d nginx
其中:/etc/nginx 为nginx容器启动时,nginx镜像文件默认的解压目录
说明:假如以后想修改nginx配置,可以直接去nginx-vol数据卷对应的目录去修改.
访问Nginx服务
访问http://192.168.126.128/这个ip地址(我的ip是这个)
安装Nacos组件
拉取镜像
执行nacos的sql脚本
先进入mysql容器(得先保证mysql服务是启动的):
docker exec -it mysql bash
切换到mysql容器目录(/etc/mysql)并登录mysql :
mysql -uroot -p
通过source指令运行容器目录下的sql文件.
注意这个sql文件是提取准备好了的,然后拖拉到宿主机的相应目录下面(目录是:/usr/local/docker/mysql/conf/).
source /容器目录/nacos-mysql.sql #容器目录是etc/mysql
创建并启动nacos容器
回到宿主机,使用以下命令创建并同时启动nacos容器:
docker run \
-e TZ="Asia/Shanghai" \
-e MODE=standalone \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_DATABASE_NUM=1 \
-e MYSQL_SERVICE_HOST=192.168.126.128 \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=root \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-p 8848:8848 \
--name nacos \
--restart=always \
-d nacos/nacos-server:1.4.1
注意更改为自己的端口号和mysql的用户名和密码.
参数说明
单节点模式
- MODE=standalone
数据库地址
- MYSQL_SERVICE_HOST
数据库用户名
- MYSQL_SERVICE_USER
数据库密码
- MYSQL_SERVICE_PASSWORD
需连接的数据库名称
- MYSQL_SERVICE_DB_NAME
端口映射
- -p 8848:8848
访问nacos服务
访问 http://ip:port/nacos 这个地址,根据自身的ip和端口号访问:
用户名和密码都是nacos.