1.Docker基础简介
开源容器引擎,go语言编写,遵循apache2.0协议开源
Docker是微服务阶段产物,可随意伸缩。
linux系统 = 内核 + 文件系统
Docker基于linux虚拟化技术 = 复用原内核 + docker自己定制的文件系统
为什么使用docker?
- 1.部署简单灵活,有独立运行环境。
- 2.节省资源开销。
- 3.项目迁移灵活。java是一次编译,处处运行,docker是一次打包,处处部署。
先来看看什么是容器,什么是虚拟机?
docker运行时与底层系统隔离开的,分配的是系统的虚拟资源,底层系统是复用的。虚拟机项目运行时直接分配了系统资源,其他虚拟机无法占用。
显然如果APP2 不工作对于容器来说资源会分配给app1和app3,而对于VM资源无法分配给其他虚拟机。
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为MB | 一般为GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般是几十个 |
部件名称 | 描述 |
---|---|
Images | Docker镜像 用于创建Docker容器的模板 |
Container | Docker容器 运行一个或一组应用 |
Registry | DOcker仓库 保存Docker镜像 |
Host | 宿主机,一台物理或虚拟的机器,来执行Docker守护进程和容器 |
Client | Docker客户端,使用Docker API与Docker的守护进程通信。 |
Machine | 一个简化Docker安装的命令行工具,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
2.Docker基础操作
安装docker服务
更新yum
使用命令curl -fsSL https://get.docker.com/ | sh
安装Docker服务
安装完成后有一个提示 如果以非root用户登录需要执行 sudo usermod -aG docker your-user
命令,然后重新登录。
安装完成后执行docker version
命令,此时会报错
问题原因是docker守护进程没有启动,所以找不到docker进程。执行启动命令
至此docker已经启动。
Docker命令
如果repo源有问题,在这个目录下cd /etc/yum.repos.d/
删除源,换其他的。
docker -h
查看docker命令
systemctl start docker
:启动docker
systemctl enable docker
:开机自动启动
/var/lib/docker
Docker默认镜像目录
/etc/docker/daemon.json
文件配置docker守护进行信息,如果不存在可自行创建。
Registry Mirrors
镜像仓库地址 从远端拉取的地址,最好改成国内的地址
修改了配置文件后,需要执行重新加载配置,重启操作。
systemctl daemon-reload
systemctl restart docker
docker run
创建一个容器并运行命令
docker create
创建一个容器但不启动 启动使用start
docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
:启动命令
-d
: 后台运行容器,并返回容器ID;
-i
: 以交互模式运行容器,通常与 -t 同时使用;
-p
: 端口映射,格式为:主机(宿主)端口:容器端口
-t
: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name nginx-lb
: 为容器指定一个名称;
--dns 8.8.8.8
: 指定容器使用的DNS服务器,默认和宿主一致;
-m
:设置容器使用内存最大值;
--net="bridge"
: 网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]
: 添加链接到另一个容器;
--expose=[]
: 开放一个端口或一组端口;
-e MYSQL_ROOT_PASSWORD=root
:设置mysql密码
-v
挂载目录 格式为:主机(宿主)路径:容器路径
docker version
:查看版本
docker info
:查看Docker信息
docker pull hello-world
拉取helloworld镜像
docker ps -a
查看docker所有容器
docker logs containerName
查看容器日志
docker rm -fv containerName
删除指定容器(f 是强制删除 v是携带数据)
docker stop $(docker ps -a -q)
停止所有容器
docker rm $(docker ps -a -q)
删除所有容器
docker exec -it containerName /bin/bash
进入容器内部系统 有一些linux命令docker内部不支持。因为docker内是最简版本的linux
docker run -it --name test-centos centos /bin/bash
-it命令就是人机交互 /bin/bash linux系统shell环境
exit
退出容器 人机交互情况下 exit退出 会退出容器。如果要容器运行 ctrl+大写P + 大写Q 退出不关闭。
docker images
查看当前系统中存在的镜像
docker search imageName
搜索镜像
docker inspect imageName
查看指定镜像元数据信息
docker rmi imageId
删除指定镜像
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
删除id为<None>的镜像
docker rmi $(docker images -q)
删除全部镜像
docker cp containerName:/etc/nginx/conf.d/default.conf ./data
docker宿主机和docker交互,复制nginx容器中default.conf 到宿主机./data目录下
volumes-from
每一个服务配置时,各自挂载容易混乱。为了有一个好的规划,统一整个服务器的挂载。可以使用volumes-from,volumes-from就是规划整个挂载服务的。
docker run -d --name nginx2 -p 80:81 --volumes-from nginx1 nginx
创建一个nginx2容器 使用nginx1容器的挂载目录,nginx1叫做数据卷容器,一般不启动。
使用一个从来不启动的容器,来统一配置。
3.Docker容器、镜像和仓库
镜像的结构像是盖楼,一层一层定制的。
- 1.初始挂载时读写层为空。
- 2.需要修改镜像内的某个文件时,只对处于最上方的读写层进行了变动,不复写下层已有文件系统的内容,已有文件在只读层中的原始版本仍然存在,但会被读写层中的新版本文件所隐藏,当 docker commit 这个修改过的容器文件系统为一个新的镜像时,保存的内容仅为最上层读写文件系统中被更新过的文件。
docker history nginx
查看镜像的层级结构
1.生成镜像(容器commit与Dockerfile)
getenforce
查看selinux 是否关闭
setenforce 0
临时关闭
vi /etc/sysconfig/selinux
文件中 SELINUX 字段改为disabled 永久关闭
/var/lib/docker/image/overlay2/imagedb/content/sha256
镜像文件默认地址,前12位是镜像ID
打开该镜像文件后,其中
history
数组内,表示了镜像的历史记录(与history命令内容对应)
rootfs的diff_ids
中,对应了依赖使用中镜像层文件(history命令中size大于0B的层)
docker inspect imageName 查看镜像后
lowerDir
:镜像的各层文件存放的地址
UpperDir
:后拷贝进docker的文件 出现在upper层
当需要修改了lower层文件,其实是将lower层文件隐藏,在upper层创建了一个修改后的文件。这样看起来是修改了。
当有重名的文件时,上层的文件会覆盖下层的。
docker commit -a "peter" -m "mvc" test-nginx nginx:test-commit
把容器转换成镜像
-a
人员信息
-m
备注信息
当使用容器commit时,只是把图中container层加在了容器镜像上。
2.dockerfile 的使用
虽然使用容器,可以转换成镜像,但不是常规手段。一般情况下,我们使用dockerfile方式。
DOckerfile是一个文本格式的配置文件。可以用Dockerfile快速创建自定义镜像。
一个简单的Dockerfile
以上就生成了一个Dockerfile的文件。
Dockerfile内的默认路径就是Dockerfile所在的路径。
docker build -t(给镜像指定名字) tomcat:peter2 .
(.
表示当前路径,具体参数填写Dockerfile所在的路径)
Dockerfile命令结构
Dockerfile中的参数名称 | 解释 |
---|---|
FROM |
FROM {base 镜像}必须放在dockerfile的第一行,表示从哪个baseimage开始构建 |
MAINTAINER |
可选,作者信息 |
RUN |
构建镜像时执行的命令 |
CMD |
容器默认的启动命令 一个Dockerfile中只能有一个有效的CMD,当定义多个CMD的时候,只有最后一个才会起作用。 |
EXPOSE |
声明运行时提供服务端口,只是一个声明,在运行时并不会因为这个声明就会开启这个端口服务。 |
ENTRYPOINT |
同CMD ,每个dockerfile只能够包含一个entrypoint,多个entrypoint只有最后一个有效,当定义了entrypoint以后,CMD只能够作为参数进行传递。 |
ADD |
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget |
COPY |
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源 |
ENV |
用来设置环境变量,后续的 RUN 可以使用它所创建的环境变量 |
WORKDIR |
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。 |
USER |
指定运行run指令的用户 |
VOLUME |
用来创建一个在 image 之外的 mount point |
Dockerfile文件的编写一般归开发人员负责。
CMD命令和entryPoint命令的区别:
- CMD 命令可以在执行run的时候被覆盖掉
- ENTRYPOINT命令 在执行run的时候不会被覆盖,只会追加到命令后,做参数使用。
建议使用ENTRYPOINT 不是CMD。
示例:
# This my first nginx Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos
#MAINTAINER 维护者信息
MAINTAINER jack
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 文件放在当前目录下,拷过去会自动解压
ADD nginx-1.8.0.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx"]
3.使用docker发布war包流程 三步
- 1.mvn打包
- 2.docker build ----一般作为一个mvn插件来封装
- 3.docker run
docker的mvn插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<imageName>${project.artifactId}:${project.version}</imageName>
<!-- 指定 Dockerfile 路径-->
<dockerDirectory>${basedir}</dockerDirectory>
<!-- 这里是复制 jar 包到 docker 容器指定目录配置,也可以写到 Docokerfile 中 -->
<resources>
<resource>
<targetPath>/ROOT</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
mvn clean package docker:build
使用mvn自动生成docker镜像。两个命令联合执行了
代码中加入了Dockerfile mvn会按照dockerfile去生成容器。
docker仓库
docker run -d --name reg registry
运行一个仓库。
docker tag docker-demo:test-commit 127.0.0.1:5000/docker-demo:test-commit
把镜像打出一个远程版本的分支,test-commit是分支版本
docker push 127.0.0.1:5000/docker-demo:test-commit
推送到docker仓库
http://39.97.179.107:5000/v2/_catalog
查询仓库镜像列表
http://39.97.179.107:5000/v2/docker-demo/tags/list
查询镜像下版本列表
dockerfile && maven 组合 docker-maven-plugin
mvn clean package docker:build docker:push
使用mvn命令 一次打包 生成镜像 以及push到仓库.实现了一次打包,处处部署。
docker run -d --name jack 192.168.244.3:5000/dockermvc:jack
从远程镜像直接生成本地容器
客户端默认是https访问方式。而register支持http所以,加了远程仓库之后,所有的docker宿主机器都要加上insecure-registries参数
systemctl daemon-reload
systemctl rtstart docker
执行以上两个命令重新加载daemon.json
如果不配置此参数,docker客户端会报错
4.Docker网络与存储
docker 容器运行,产生一些数据、文件、日志等持久化的东西,不应该放在容器内部,应当以挂载的形式存在主机文件系统中。
- 1.镜像与容器读写层,通过联合文件系统,组成系统文件视角。
- 2.容器服务运行中,一定会生成数据。
- 3.容器只是运行态的服务器,是瞬时的,不承载数据的持久功能。
docker run -d --name test-mount -v /home/docker/:/data a628411a226b
volume参数创建容器数据卷
通过docker inspect data
查看容器元数据
在容器中创建一个文件
宿主机的目录下也出现了相同的文件
volumes-from 引用数据卷
docker run -d --volumes-from 80125886fa18 --name test-volumes-from a628411a226b
新启动一个容器,引入上一步的test-mount 容器目录,内容与test-mount容器里挂载一样。
docker rm -v test-mount
删除数据卷
5.Docker Compose 编排服务
当项目涉及容器较多时,需要一个管理容器的工具。docker服务编排工具:一次启动一组的服务。compose是在docker基础上 新增加的一个工具。
1.compose 安装
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-
uname -s-
uname -m> /usr/local/bin/docker-compose
下载compose服务
sudo chmod +x /usr/local/bin/docker-compose
(刚加进来是不可执行的权限 需要加一个执行权限)
docker-compose version
查看docker-compose版本
compose文件结构
docker-compose.yaml
每次使用compose的时候就要在使用的地方创建一个
docker-compose up -d
启动compose(启动命令执行目录下要含有docker=compose.yaml
文件)
docker-compose down
关闭工程 compose文件中所有容器都会被停掉,并且被删除.docker理念。容器是不持久的。所以用完就删。
compose不仅仅做启停,还可以做负载的
docker-compose up -d --scale tomcat=2
tomcat创建了2个。
此时会有端口映射问题,两个tomcat 无法映射端口(因为用同一个端口)。
解决方法,使用links信息 将tomcat别名链接到nginx中。
nginx 加入配置
此时多个tomcat服务就会被反向代理到nginx中
docker compose 启动时,根据配置文件会处理link中信息,加入到nginx的配置文件,替换nginx中 tom:8000 中的tomcat地址,tom会变成一个多IP的地址。doc
6.Docker Swarm使用
把多台机器整合成像一台机器一样,对外提供服务。这样的服务叫做云。
swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源。
vi /lib/systemd/system/docker.service
ExecStart参数 docker启动的时候 可以启动一个监听端口。(docker监听端口)
docker swarm init --advertise-addr 1192.168.112.129
当前机器变成主控节点,创建manager
在其他机器上执行join命令,可以被主控节点监控
docker node ls
(manager机器上可以查看)查看docker服务节点
docker swarm leave
节点离开manager管理
可以再引入一个管理节点到集群来。在leader节点上执行docker swarm join-token manager
在一台新机器上执行上图命令 加入一个管理节点
此时查看manager节点,已经加入集群
swarm 环境搭建完毕之后,整个工作节点的集群,都可以当做一个宿主机来操作。可以在manager上进行各种服务的部署管理。
1.服务管理
docker service create --name nginx-swarm --replicas 3 -p 80:80 nginx:1.7.9
创建了一个服务, 集群中创建使用--replicas 而不是 --scale (compose中启动多个相同容器使用--scale)
docker service ls
查看所有服务
docker service ps nginx-swarm
查看服务详情
访问服务,任意一台节点机 ip,都可访问
2.服务维护
服务集群运行后,会以期望的状态方式管理整个集群。如刚刚创建的三个nginx组成的集群。如果其中一台宕机,swarm会自动新建一台,来补足task数量。
在一个节点上删除一个容器
在管理节点上查询
可以看到旧的服务是shutdown状态。又新启动了一个服务。
3.滚动升级
更新原来的nginx版本为1.9.7
docker service update --image nginx:1.9.7 nginx-swarm
更新镜像版本 动态滚动更新。服务不会停。实现热更新
更新完后,查看nginx 已经升级为1.9.7
4.动态扩容
服务还可以动态地在节点集群上进行扩容
docker service scale nginx = 4
动态扩容 动态的增加一台机器
再次查看,发现服务已经扩容为4个。
docker service rm nginx
删除服务
docker swarn jon-token manager
查看manager 上的token
5.网络通讯
swarm管理的集群,内部建立一个统一的网络层,绑定的端口并非是直接绑定当宿主机,而是绑定到一个overlay网络,对于集群来说,相当于都绑在网络的一个端口上,启动负载策略来转发请求,如下图:
PS:swarm已被放弃,不好结合compose