Docker详解


1.Docker基础简介

开源容器引擎,go语言编写,遵循apache2.0协议开源

Docker是微服务阶段产物,可随意伸缩。

linux系统 = 内核 + 文件系统
Docker基于linux虚拟化技术 = 复用原内核 + docker自己定制的文件系统

为什么使用docker?

  • 1.部署简单灵活,有独立运行环境。
  • 2.节省资源开销。
  • 3.项目迁移灵活。java是一次编译,处处运行,docker是一次打包,处处部署。

先来看看什么是容器,什么是虚拟机?

左图为容器,右图为虚拟机

docker运行时与底层系统隔离开的,分配的是系统的虚拟资源,底层系统是复用的。虚拟机项目运行时直接分配了系统资源,其他虚拟机无法占用。

显然如果APP2 不工作对于容器来说资源会分配给app1和app3,而对于VM资源无法分配给其他虚拟机。

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般是几十个
docker架构
部件名称 描述
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


yum update

使用命令curl -fsSL https://get.docker.com/ | sh安装Docker服务

curl -fsSL https://get.docker.com/ | sh

安装完成后有一个提示 如果以非root用户登录需要执行 sudo usermod -aG docker your-user 命令,然后重新登录。

操作提示

安装完成后执行docker version命令,此时会报错

错误信息

问题原因是docker守护进程没有启动,所以找不到docker进程。执行启动命令


启动命令

至此docker已经启动。

Docker命令

如果repo源有问题,在这个目录下cd /etc/yum.repos.d/删除源,换其他的。

docker -h 查看docker命令

docker命令

systemctl start docker:启动docker

systemctl enable docker:开机自动启动

/var/lib/docker Docker默认镜像目录

/etc/docker/daemon.json 文件配置docker守护进行信息,如果不存在可自行创建。

daemon.json简单示例

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容器、镜像和仓库

镜像的结构像是盖楼,一层一层定制的。


docker镜像结构
  • 1.初始挂载时读写层为空。
  • 2.需要修改镜像内的某个文件时,只对处于最上方的读写层进行了变动,不复写下层已有文件系统的内容,已有文件在只读层中的原始版本仍然存在,但会被读写层中的新版本文件所隐藏,当 docker commit 这个修改过的容器文件系统为一个新的镜像时,保存的内容仅为最上层读写文件系统中被更新过的文件。

docker history nginx 查看镜像的层级结构

docker镜像层级结构

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 备注信息

docker镜像层级结构

当使用容器commit时,只是把图中container层加在了容器镜像上。

2.dockerfile 的使用

虽然使用容器,可以转换成镜像,但不是常规手段。一般情况下,我们使用dockerfile方式。

DOckerfile是一个文本格式的配置文件。可以用Dockerfile快速创建自定义镜像。

一个简单的Dockerfile


Dockerfile文件结构

以上就生成了一个Dockerfile的文件。

Dockerfile内的默认路径就是Dockerfile所在的路径。

docker build -t(给镜像指定名字) tomcat:peter2 .(.表示当前路径,具体参数填写Dockerfile所在的路径)

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参数


daemon.json参数

systemctl daemon-reload
systemctl rtstart docker
执行以上两个命令重新加载daemon.json

如果不配置此参数,docker客户端会报错


docker报错

4.Docker网络与存储

docker 容器运行,产生一些数据、文件、日志等持久化的东西,不应该放在容器内部,应当以挂载的形式存在主机文件系统中。


联合文件系统
  • 1.镜像与容器读写层,通过联合文件系统,组成系统文件视角。
  • 2.容器服务运行中,一定会生成数据。
  • 3.容器只是运行态的服务器,是瞬时的,不承载数据的持久功能。

docker run -d --name test-mount -v /home/docker/:/data a628411a226b volume参数创建容器数据卷

通过docker inspect data查看容器元数据

docker容器元数据

在容器中创建一个文件


创建文件

宿主机的目录下也出现了相同的文件


宿主机目录

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基础上 新增加的一个工具。


compose编排服务
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文件结构


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中。


links信息

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

swarm master节点

在其他机器上执行join命令,可以被主控节点监控


swarm 加入集群

docker node ls (manager机器上可以查看)查看docker服务节点

查看服务节点

docker swarm leave 节点离开manager管理

可以再引入一个管理节点到集群来。在leader节点上执行docker swarm join-token manager

manager管理节点创建

在一台新机器上执行上图命令 加入一个管理节点


加入管理节点

此时查看manager节点,已经加入集群


加入集群后查看

swarm 环境搭建完毕之后,整个工作节点的集群,都可以当做一个宿主机来操作。可以在manager上进行各种服务的部署管理。

1.服务管理

docker service create --name nginx-swarm --replicas 3 -p 80:80 nginx:1.7.9 创建了一个服务, 集群中创建使用--replicas 而不是 --scale (compose中启动多个相同容器使用--scale)

使用swarm创建服务

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网络,对于集群来说,相当于都绑在网络的一个端口上,启动负载策略来转发请求,如下图:


docker网络架构

PS:swarm已被放弃,不好结合compose

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351