容器时代Docker
1.1 Docker容器
1.1.4 组成
两个进程:
Docker 使用客户端-服务器 (C/S) 架构模式。Docker 客户端会与 Docker 守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布你的 Docker 容器。Docker 客户端和守护进程可以运行在同一个系统上,当然你也可以使用 Docker 客户端去连接一个远程的 Docker 守护进程。Docker 客户端和守护进程之间通过 socket 或者 RESTful API 进行通信。
1.1.5 Docker核心概念
VM虚拟机的出现可以让服务器资源可以充分利用,一台服务器上可以安装多个VM,而每个VM又形成资源隔离,使不同的VM可以使用同一台服务器,却互相不干扰。Docker同理,它也是将硬件资源抽象。
Docker两个最重要的概念是镜像和容器。镜像类似虚拟机的快照,但更轻量,非常非常轻量。举例来说,VM相当于绿皮火车,Docker就相当于劳斯莱斯小汽车。VM的快照通常2~3G,而Docker只有100~300M。
1.1.5.1 镜像image
简单说,镜像就是一个只读模板。
创建Docker镜像有几种方式,多数是在一个现有镜像基础上创建新镜像,因为几乎你需要的任何东西都有了公共镜像,包括所有主流Linux发行版,你应该不会找不到你需要的镜像。不过就算你想从头构建一个镜像也有好几种方式。
实现的方式有两种:在一个文件Dockerfile中指定一个基础镜像及需要完成的修改;或通过“运行”一个镜像,对其进行修改并提交。不同方式各有优点,不过一般会使用文件Dockerfile来指定所做的变化。
镜像拥有唯一ID,以及一个供人阅读的名字和标签对。镜像可以命名为类似ubuntu:latest、ubuntu:precise、django:1.6、django:1.7等等。
1.1.5.2 容器container
每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
可以从镜像中创建容器,这等同于从快照中创建虚拟机,不过更轻量。应用是由容器运行的。容器与虚拟机一样,是隔离的。它们也拥有一个唯一ID和唯一的供人阅读的名字。容器有必要对外暴露服务,因此Docker允许暴露容器的特定端口。
容器启动时,将被分配一个随机的私有IP,其它容器可以使用这个IP地址与其进行通讯。这点非常重要,原因有二:一是它提供了容器间相互通信的渠道,二是容器将共享一个本地网络。
要开启容器间通讯,Docker允许你在创建一个新容器时引用其它现存容器,在你刚创建的容器里被引用的容器将获得一个(你指定的)别名。我们就说,这两个容器链接在了一起。
因此,如果DB容器已经在运行,我可以创建web服务器容器,并在创建时引用这个DB容器,给它一个别名,比如dbapp。在这个新建的web服务器容器里,我可以在任何时候使用主机名dbapp与DB容器进行通讯。
1.1.5.3 数据卷volume
Docker是只读的,那就产生一个问题,例如mysql,用户有自己的数据,那这部分数据怎么保存呢?Docker提供了数据卷就用来保存持久的数据。
卷是针对容器的,你可以使用同一个镜像创建多个容器并定义不同的卷。卷保存在运行Docker的宿主文件系统上,你可以指定卷存放的目录,或让Docker保存在默认位置。
注意:定义了数据卷,Docker迁移就可能失败,可能新的机器没有对应目录。另外,如果数据量非常大,Tb级别的,docker镜像才几百兆。所以并不推荐使用数据卷方式,最好就是只读的,运行时只产生临时数据,不产生业务数据,退出、删除无需额外处理。
1.1.5.4 仓库repository
Docker有一个类似版本管理仓库(Repositry)的东西,有docker.io提供的官方仓库(index.docker.io,相当于github),也可以自建(叫docker-registry,相当于自己搭建一个小型github)。
Git | Docker |
GitHub | DockerHub |
用户 User Account | 用户 User Account |
仓库 Repository | 仓库 Repository |
分支 Branch | 镜像 Image |
标签 Tag | 标签 Tag |
Push 推送,上传 | Push 推送,上传 |
Pull/Clone 拉取/克隆 | Pull 拉取 |
Commit 提交 | Commit 提交 |
Merge 合并 | N/A |
1.1.6 包洋葱
简单来说docker是利用AUFS文件系统的支持,反复包裹形成无数的镜像,公用相同的部分(Image),又可以形成自己独有的内容(Container)。镜像支持使之可以站在巨人的肩膀上(已经实现的内容),又变化无穷(独有的内容)。
Container和Image 在Docker的世界里,Image是指一个只读的层(Layer),这里的层是AUFS里的概念,最直观的方式就是看一下docker官方给出的图:
AUFS的文件系统可以让你一层一层地叠加修改你的文件,最底下的文件系统是只读的,如果需要修改文件,AUFS会增加一个可写的层(Layer),这样有很多好处。例如,不同的Container可以共享底层的只读文件系统(同一个Kernel),使得你可以跑N多个Container而不至于你的硬盘被挤爆了,复用了相同的内容(本地镜像库中的镜像),大大减小了存储空间。
1.1.7 那Image和Container的区别是什么?
很简单,它们的区别仅仅是一个是只读的层,一个是可写的层。你可以使用docker commit 命令,将你的Container变成一个Image,也就是提交你所运行的Container的修改内容,变成一个新的只读的Image,这非常类似于git commit命令。
1.1.8 Docker的特征
序号 | 特征 | 说明 |
1. | 更高效的利用系统资源 | 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 |
2. | 更快速的启动时间 | 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 |
3. | 一致的运行环境 | 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现“这段代码在我机器上没问题啊”这类问题。 |
4. | 持续交付和部署 | 对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。 |
5. | 更轻松的迁移 | 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。 |
6. | 更轻松的维护和扩展 | Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 |
7. | 敏捷开发 | 有了Docker的支持,部署速度快捷,三大环境的统一(开发、测试、生产环境),支持敏捷开发。 |
1.1.9 面试:Docker与VM虚拟机的不同点
1. 虚拟化技术依赖物理CPU和内存,是硬件级别的;而docker构建在操作系统上,利用操作系统的containerization容器技术,所以docker甚至可以在虚拟机上运行。
2. 启动速度快,比VM快太多了,启动、停止、开始、重启都是秒级甚至毫秒级。
3. 轻量级虚拟化,在一台服务器上可以部署100~1000个Container容器。而VM一台服务器能部署10到20就很不错了。
4. *Docker是单线程,Docker设计者极力推崇“一个容器一个进程的方式”。无法很好地模拟一个完整的环境(详细参加LXC)。
5. *当停止一个虚拟机时,可能除了一些临时文件,没有文件会被删除(业务产生的文件);但当停止一个Docker容器,对初始状态(创建容器所用的镜像的状态)做的所有变化都会丢失。这是使用Docker时必须做出的最大思维变化之一:容器是短暂和一次性的。所以有种说法,例如mysql这样的数据库还是不要用Docker的好,因为数据库在使用过程中会有很多业务数据。
6. Docker的安全性目前比VM要差。VM做到资源完全隔离,而Docker会共享资源,这就带来了安全的风险。
1.2 Centos7下安装Docker
1.2.1 配置虚拟机
docker官方文档要求必须运行在Linux kernel 3.8以上,所以需要安装在Centos7或者Ubantu系统上。
yum install lrzsz #安装上传下载组件
uname –a #检查当前Linux内核版本
查询结果:
Linux tdocker 3.10.0-327.el7.x86_64 #1 SMP Thu Nov19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
1.2.2 VM配置NAT模式网络上网
修改配置文件
cd /etc/sysconfig/network-scripts #进入网络配置目录
dir ifcfg* #找到网卡配置文件
ifcfg-eno16777736 ifcfg-lo
vi ifcfg-eno16777736
配置文件内容
TYPE=Ethernet
BOOTPROTO=static #改成static,针对NAT
NAME=eno16777736
UUID=4cc9c89b-cf9e-4847-b9ea-ac713baf4cc8
DEVICE=eno16777736
ONBOOT=yes #开机启动此网卡
IPADDR=192.168.163.30 #固定IP地址
NETMASK=255.255.255.0 #子网掩码
GATEWAY=192.168.163.2 #网关和NAT自动配置的相同,不同则无法登录
DNS1=192.168.163.2 #和网关相同
测试
centos7 命令发生巨大变化
ip addr #查看IP地址 ip add
service network restart #重启网络
systemctl restart network.service #重启网络centos7
vi /etc/hosts #127.0.0.1 dredis
hostname dreids #注意必须修改机器名hostname
ping www.baidu.com #如果出现baidu的ip地址则表示网络连通
1.2.3 安装Docker
1.2.3.1 第一步:安装工具包
$ sudo yum install -y yum-utils #安装工具包,缺少这些依赖将无法完成
执行结果:
Loaded plugins: fastestmirror, langpacks
base |3.6 kB 00:00:00
epel | 4.3 kB 00:00:00
extras | 3.4kB 00:00:00
update | 3.4 kB 00:00:00
(1/3): epel/7/x86_64/updateinfo | 797 kB 00:00:00
(2/3): epel/7/x86_64/primary_db | 4.7 MB 00:00:00
(3/3): update/7/x86_64/primary_db | 4.8 MB 00:00:00
Loading mirror speeds from cached hostfile
Package yum-utils-1.1.31-40.el7.noarch alreadyinstalled and latest version
Nothing to do
1.2.3.2 第二步:设置远程仓库
$sudo yum-config-manager --add-repohttps://download.docker.com/linux/centos/docker-ce.repo
执行结果:
Loaded plugins: fastestmirror, langpacks
adding repo from:https://download.docker.com/linux/centos/docker-ce.repo
grabbing filehttps://download.docker.com/linux/centos/docker-ce.repo to/etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
1.2.3.3 第三步:安装
$ sudo yum install docker-ce
执行结果:
1.2.3.4 第四步:启动
$ sudo systemctl start docker
或者
$ sudo service docker start
service docker start #启动docker
chkconfig docker on #加入开机启动
1.2.3.5 第五步:查看版本
$ sudo docker version
执行结果:
Client:
Version: 17.03.1-ce
APIversion: 1.27
Goversion: go1.7.5
Gitcommit: c6d412e
Built: Mon Mar 27 17:05:44 2017
OS/Arch: linux/amd64
1.2.3.6 第六步:校验
$ sudo docker run hello-world
执行结果:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
78445dd45222: Pull complete
Digest:sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears tobe working correctly.
To generate this message, Docker took the followingsteps:
1. The Dockerclient contacted the Docker daemon.
2. The Dockerdaemon pulled the "hello-world" image from the Docker Hub.
3. The Dockerdaemon created a new container from that image which runs the
executablethat produces the output you are currently reading.
4. The Dockerdaemon streamed that output to the Docker client, which sent it
to yourterminal.
To try something more ambitious, you can run anUbuntu container with:
$ docker run-it ubuntu bash
Share images, automate workflows, and more with afree Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
1.2.4 查看Docker版本
docker --help #帮助
docker –v #简单查看版本
docker version #查看版本
Client version: 1.7.1
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 786b29d/1.7.1
OS/Arch (client): linux/amd64
Server version: 1.7.1
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 786b29d/1.7.1
OS/Arch (server): linux/amd64
docker info #查看信息
Containers: 0
Images: 2
Storage Driver: devicemapper
Pool Name:docker-253:0-34097258-pool
PoolBlocksize: 65.54 kB
BackingFilesystem: xfs
Data file:/dev/loop0
Metadatafile: /dev/loop1
Data SpaceUsed: 308.3 MB
Data SpaceTotal: 107.4 GB
Data SpaceAvailable: 16.08 GB
MetadataSpace Used: 782.3 kB
MetadataSpace Total: 2.147 GB
MetadataSpace Available: 2.147 GB
Udev SyncSupported: true
DeferredRemoval Enabled: false
Data loopfile: /var/lib/docker/devicemapper/devicemapper/data
Metadataloop file: /var/lib/docker/devicemapper/devicemapper/metadata
LibraryVersion: 1.02.107-RHEL7 (2015-10-14)
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.10.0-327.el7.x86_64
Operating System: CentOS Linux 7 (Core)
CPUs: 4
Total Memory: 985.6 MiB
Name: localhost.localdomain
ID:B5ZW:FJXF:FNUD:OLH7:FCNI:56DJ:XEQY:I6J4:PPHQ:OKRW:CIJK:Y26P
1.2.5 安装其它产品的两种方式
docker安装其它产品有两种方式
方式一:通过拉取事先做好的镜像,例如下面redis的安装方式
方式二:通过Dockerfile来构建新的镜像,例如下面tomcat的安装方式
1.2.6 组成结构
docker会自动给docker容器配置一个vip虚拟ip地址
bash-4.1#提示符就代表进入docker容器内部
1.3 Redis
1.3.1 拉取Redis镜像
docker search redis #镜像库提供的多个镜像
docker pull redis #拉取最后版本的docker-redis镜像
docker pull redis:3.2.8 #拉取指定版本的redis镜像
注意:拉取速度会很慢,因为docker中央仓库在国外,中国虽然有镜像仓库,如阿里、网易蜂巢等,但速度也不理想。好在,docker文件可以反复拉取,拉取失败,重新拉取即可。
拉取完成提示:
Digest:sha256:f4751caa521d05db548a3190fb87f92cd7cc2f1612b7ef8b84218864d2c45577
Status: Downloaded newer image for redis:latest
1.3.2 查看镜像
dockerimages #查看已经拉取的镜像
执行结果:
REPOSITORYTAG IMAGE ID CREATED VIRTUAL SIZE
redis latest8f41ae49db402 weeks ago 183.6 MB
1.3.3 启动第一个Redis实例
启动redis实例,映射程序访问端口为7000,实例名称为redis7000
docker run -d --name redis7000 -p 7000:6379 redis
参数说明:
-d,则containter将会运行在后台模式(Detachedmode)
--name 实例名称
-p 对外程序访问端口7000,宿主机映射的redis端口6379
最后的redis为镜像的名称
1.3.4 单个节点测试
@Test //完成单实例链接
publicvoid jedis(){
Jedisjedis = new Jedis("192.168.163.30", 7000);
//jedis.auth("123456");
jedis.set("name","tony"); //调用redis命令set
Strings = jedis.get("name");
System.out.println(s);
jedis.close();
}
1.3.5 启动Redis实例
docker run -d --name redis7001 -p 7001:6379 redis
docker run -d --name redis7002 -p 7002:6379 redis
1.3.6 查看docker的实例
docker ps #查看当前运行的dockerid
docker ps -a #查看已有的可能状态是停止
docker start b193fbe1e400 #开启实例,如重启可能实例被关闭
docker stop b193fbe1e400 #停止实例
docker rm –f 0cfc4932b9a0 #删除运行的docker,-f强制删除
docker rmi xcfc4932b9a0 #删除镜像
查看结果:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6567870ec0ae redis "docker-entrypoint.s 17minutes ago Up 16 minutes 0.0.0.0:7002->6379/tcp redis7002
a071867d6233 redis "docker-entrypoint.s 18minutes ago Up 18 minutes 0.0.0.0:7001->6379/tcp redis7001
c3ce36dc147c redis "docker-entrypoint.s 19minutes ago Up 19 minutes 0.0.0.0:7000->6379/tcp redis7000
1.3.7 端口的映射关系
1.3.8 关闭防火墙
systemctl stop firewalld.service #关闭防火墙服务
disable firewalld.service #禁止防火墙开启启动
systemctl restart iptables.service #重启防火墙使配置生效
systemctl enable iptables.service #设置防火墙开机启动
systemctl restart docker #重启docker服务
1.3.9 进入docker内部
docker exec -it 0cfc4932b9a0 bash #进入docker内部,-it输入输出,展示信息在控制台
root@a071867d6233:/data# ps -ef |grep redis
redis 1 0 1 08:45 ? 00:00:08 redis-server *:6379
root 26 20 0 08:58 ? 00:00:00 grep redis
redis-cli #根据最后映射的端口执行redis命令
exit #退出docker中的redis环境
1.3.10 Shard分片测试类
package jedis;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
public class TestJedis {
@Test //分片
publicvoid shard(){
//构造各个节点链接信息,host和port
List<JedisShardInfo>infoList = new ArrayList<JedisShardInfo>();
JedisShardInfoinfo1 = new JedisShardInfo("192.168.163.200",6379);
//info1.setPassword("123456");
infoList.add(info1);
JedisShardInfoinfo2 = new JedisShardInfo("192.168.163.200",6380);
infoList.add(info2);
JedisShardInfoinfo3 = new JedisShardInfo("192.168.163.200",6381);
infoList.add(info3);
//分片jedis
JedisPoolConfigconfig = new JedisPoolConfig();
config.setMaxTotal(500); //最大链接数
ShardedJedisPoolpool = new ShardedJedisPool(config, infoList);
//ShardedJedisjedis = new ShardedJedis(infoList);
ShardedJedisjedis = pool.getResource(); //从pool中获取
for(inti=0;i<10;i++){
jedis.set("n"+i,"t"+i);
}
System.out.println(jedis.get("n9"));
jedis.close();
}
}
1.4 Dockerfile
Dockerfile通过逐层layer叠加,使资源得到重复利用,同时变化无穷。
注意:FROM指定的镜像,本地如果有直接使用,无需网上下载。
1.4.1 关键字及含义
序号 | 关键字 | 说明 |
1. | FROM | 指定基础镜像的来源 |
2. | MAINTAINER | 作者 |
3. | ADD | 复制文件,会自动解压 |
4. | WORKDIR | 设置当前工作目录 cd |
5. | VOLUME | 设置数据卷,挂载主机目录 |
6. | EXPOSE | 指定对外暴漏的端口 |
7. | RUN | 执行命令 sh |
8. | CMD | 执行命令 exec,一个Dockerfile只能一个 |
9. | COPY | 复制文件 |
10. | ENTRYPOINT | docker run时参数可以覆盖,指定参数值 |
1.5 基础镜像centos
1.5.1 centos
mkdir /usr/local/src/docker #创建目录
1.5.2 配置Dockerfile
FROM index.alauda.cn/tutum/centos:6.5
FROM registry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
1.5.3 创建镜像build
docker build -t jt-centos6:0.0.1 .
参数-t标识TAG名称,注意最后有一个.代表当前路径
执行结果:
Sending build context to Docker daemon
Step 0 : FROMregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
0.0.1: Pulling fromregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos
3690474eb5b4: Pull complete
0a444b299d5a: Pull complete
a04895de1996: Pull complete
d4350798c2ee: Already exists
Digest:sha256:6573e33c14607402068620507e450b65f637023f43fd1223269447c9532da292
Status: Downloaded newer image forregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
--->d4350798c2ee
Successfully built d4350798c2ee
1.5.4 重命名镜像
小技巧:只写FROM相当于对现有镜像重命名
docker build -t jt-centos6:0.0.1 .
1.5.5 查看镜像images
docker images
执行结果:
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
registry.cn-hangzhou.aliyuncs.com/repos_zyl/centos 0.0.1 d4350798c2ee 5 months ago 191.8 MB
jt-centos6 0.0.1 d4350798c2ee 5 months ago 191.8 MB
1.5.6 删除镜像rmi
docker rmiregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
1.5.7 导出镜像save
docker save -o jt-centos6.tar jt-centos6:0.0.1 #按镜像名称导出
docker save 9610cfc68e8d > jt-centos6.tar #按镜像id导出,但导入时没名称
1.5.8 导入镜像load
docker load -i jt-centos6.tar
1.6 JDK
1.6.1 jdk
mkdir /usr/local/src/docker #创建目录
jdk-7u51-linux-x64.tar.gz #上传jdk文件
1.6.2 配置Dockerfile
FROM index.alauda.cn/tutum/centos:6.5
或者
FROM registry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
# install jdk1.7
ADD jdk-7u51-linux-x64.tar.gz /usr/local/src
ENV JAVA_HOME=/usr/local/src/jdk1.7.0_51
ENV PATH=$JAVA_HOME/bin:$PATH
ENVCLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
1.6.3 制作镜像
docker build --no-cache -t jt-jdk:0.0.1 . #-t添加tag .代表当前路径
创建日志
[root@localhost docker]# docker build -tjt-jdk:0.0.2 .
Sending build context to Docker daemon 138.2 MB
Sending build context to Docker daemon
Step 0 : FROMregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
0.0.1: Pulling fromregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos
3690474eb5b4: Pull complete
0a444b299d5a: Pull complete
a04895de1996: Pull complete
d4350798c2ee: Already exists
Digest:sha256:6573e33c14607402068620507e450b65f637023f43fd1223269447c9532da292
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
--->d4350798c2ee
Step 1 : ADD jdk-7u51-linux-x64.tar.gz/usr/local/src
--->f7e506cbd4b5
Removing intermediate container c25330765fe5
Step 2 : ENV JAVA_HOME /usr/local/src/jdk1.7.0_51
--->Running in e1c9a1a018fb
--->312f6aeadb84
Removing intermediate container e1c9a1a018fb
Step 3 : ENV PATH $JAVA_HOME/bin:$PATH
--->Running in 194844ddd65d
--->2e6b9a3557a7
Removing intermediate container 194844ddd65d
Step 4 : ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
--->Running in 4979a414305a
--->e0dade7b259b
Removing intermediate container 4979a414305a
Successfully built e0dade7b259b
[root@localhost docker]#
1.6.4 运行镜像
docker run -d jt-jdk:0.0.1
1.6.5 进入容器,检查jdk是否安装成功
[root@localhost ~]# docker exec -i -t 8fd3e511b3a4bash
bash-4.1# java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build24.51-b03, mixed mode)
bash-4.1#
1.6.6 退出容器,但是容器不关闭
[root@docker jdk]# docker exec -i -t 0905440611ccbash
bash-4.1# java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build24.51-b03, mixed mode)
bash-4.1# exit #退出容器,但是容器不关闭
1.7 Tomcat
1.7.1 准备文件
mkdir /usr/local/src/docker #创建目录
jdk-7u51-linux-x64.tar.gz #上传jdk文件
apache-tomcat-7.0.55.tar.gz #上传tomcat文件
1.7.2 配置Dockerfile
FROMregistry.cn-hangzhou.aliyuncs.com/repos_zyl/centos:0.0.1
# install jdk1.7
ADD jdk-7u51-linux-x64.tar.gz /usr/local/src #ADD复制文件并解压
ENV JAVA_HOME=/usr/local/src/jdk1.7.0_51 #ENV配置环境
ENV PATH=$JAVA_HOME/bin:$PATH
ENVCLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# install tomcat7
ADD apache-tomcat-7.0.55.tar.gz /usr/local/src
ENV CATALINA_HOME/usr/local/src/apache-tomcat-7.0.55
ENV PATH=$PATH:$CATALINA_HOME/bin
EXPOSE 8080 #对外访问的端口
#执行命令
CMD["/usr/local/src/apache-tomcat-7.0.55/bin/catalina.sh","run"]
1.7.3 制作镜像
docker build -t jt-tomcat:0.0.1 .
docker images
1.7.4 运行
docker run -d -p 8001:8080 --name jt-tomcatjt-tomcat:0.0.1
cc6c7460029232f787d195df5648e85dec0e7b2e7bbf6bb86ccc53898fc47764
[root@localhost docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc6c74600292 jt-tomcat:0.0.1 "/usr/local/src/apac 12seconds ago Up 9 seconds 0.0.0.0:8001->8080/tcp jt-tomcat
[root@localhost docker]#
1.7.5 打开端口
iptables -A INPUT -p tcp --dport 8001 -j ACCEPT
1.7.6 测试
http://192.168.163.8:8001/
展示tomcat页面就表示成功了
1.8 MySQL============
1.9 部署war包
1.9.1 准备文件
上传war,修改好jdbc.properties文件
1.9.2 配置Dockerfile
FROM jt-centos6:0.0.1
#install jdk1.7
ADD jdk-7u51-linux-x64.tar.gz /usr/local/src
ENV JAVA_HOME=/usr/local/src/jdk1.7.0_51
ENV PATH=$JAVA_HOME/bin:$PATH
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
#install tomcat7
ADD apache-tomcat-7.0.55.tar.gz /usr/local/src
ENV CATALINA_HOME/usr/local/src/apache-tomcat-7.0.55
ENV PATH=$PATH:$CATALINA_HOME/bin
RUN rm -rf $CATALINA_HOME/webapps/*
#deploy the war
COPY ROOT.war $CATALINA_HOME/webapps/ROOT/ROOT.war
WORKDIR $CATALINA_HOME/webapps/ROOT
RUN jar xvf ROOT.war
RUN rm -rf ROOT.war
EXPOSE 8080
CMD["/usr/local/src/apache-tomcat-7.0.55/bin/catalina.sh","run"]
1.9.3 制作镜像
docker build -t jt-manage-war:0.0.1 .
docker images
执行日志:
Sending build context to Docker daemon
Step 0 : FROM jt-centos6:0.0.1
--->d4350798c2ee
Step 1 : ADD jdk-7u51-linux-x64.tar.gz/usr/local/src
--->Using cache
--->9a792e3fab6f
Step 2 : ENV JAVA_HOME /usr/local/src/jdk1.7.0_51
--->Using cache
--->79571eb304c3
Step 3 : ENV PATH $JAVA_HOME/bin:$PATH
--->Using cache
--->35dff4e4df85
Step 4 : ENV CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
--->Using cache
--->f3e681348b2f
Step 5 : ADD apache-tomcat-7.0.55.tar.gz/usr/local/src
--->Using cache
--->262f103f08af
Step 6 : ENV CATALINA_HOME/usr/local/src/apache-tomcat-7.0.55
--->Using cache
--->aecd8888daff
Step 7 : ENV PATH $PATH:$CATALINA_HOME/bin
--->Using cache
--->eff7fa41fea2
Step 8 : RUN rm -rf $CATALINA_HOME/webapps/*
--->Using cache
--->22bc88155a21
Step 9 : COPY ROOT.war$CATALINA_HOME/webapps/ROOT/ROOT.war
inflated:WEB-INF/views/login.jsp
inflated:WEB-INF/web.xml
created:META-INF/maven/
created:META-INF/maven/com.jt/
created:META-INF/maven/com.jt/jt-manage-web/
inflated:META-INF/maven/com.jt/jt-manage-web/pom.xml
inflated:META-INF/maven/com.jt/jt-manage-web/pom.properties
--->7f09fcdeb256
Removing intermediate container 0037f2032ef2
Step 12 : RUN rm -rf ROOT.war
--->Running in 333872bb469c
--->40d0fcfc3717
Removing intermediate container 333872bb469c
Step 13 : EXPOSE 8080
--->Running in c702f140c7bf
--->c36982676589
Removing intermediate container c702f140c7bf
Step 14 : CMD /usr/local/src/apache-tomcat-7.0.55/bin/catalina.shrun
--->Running in 8f2f5e3a9f2c
--->bc2cc8c59ee0
Removing intermediate container 8f2f5e3a9f2c
Successfully built bc2cc8c59ee0
[root@localhost docker]#
1.9.4 运行
docker run -d -p 8001:8080 --name jt-tomcatjt-tomcat:0.0.1
cc6c7460029232f787d195df5648e85dec0e7b2e7bbf6bb86ccc53898fc47764
[root@localhost docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc6c74600292 jt-tomcat:0.0.1 "/usr/local/src/apac 12 seconds ago Up 9 seconds 0.0.0.0:8001->8080/tcp jt-tomcat
[root@localhost docker]#
1.9.5 打开端口
iptables -A INPUT -p tcp --dport 8001 -j ACCEPT #打开8001端口
systemctl stop firewalld #关闭防火墙
1.9.6 测试
http://192.168.163.8:8001/
1.9.7 查看tomcat日志
docker logs -f -t --tail="10"892718f559d0
参数说明:
l -f 跟踪容器日志的最近更新
l -t 显示容器日志的时间戳
l --tail="10" 仅列出最新10条容器日志
1.9.8 出错后重建
docker stop d58ab377493b #运行中的实例不能直接删除,先停止运行的实例
docker rm d58ab377493b #再删除实例
docker build -t jt-manage-war:0.0.2 . #制作镜像
docker run -d -p 8001:8080 --name jt8001jt-tomcat:0.0.2 #运行
1.10 docker-compose实现ZK集群
compose是用来在Docker中定义和运行复杂应用的小工具,比如在一个文件中定义多个容器,只用一行命令就可以让一切就绪并运行。fig是compose的前身。
1.10.1 YML文件
docker-compose批量执行的内容放在YML格式文件中配置。
YML文件格式是YAML (YAML AintMarkup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。
1.10.2 安装配置
上传文件docker-compose-Linux-x86_64到/usr/local/bin目录下
mv docker-compose-Linux-x86_64docker-compose #修改名称
chmod +x /usr/local/bin/docker-compose #设置文件访问权限
docker-compose -version #查看版本
docker-compose up -d #后台模式被启动
1.10.3 编写docker-compose.yml
配置zk的yml文件,默认找docker-compose.yml,分为两个版本1和2。 image:zookeeper为基础镜像,如果没有下载会自动下载。也可以单独的拉取。docker pull zookeeer。
version: '2'
services:
dzk1:
image: zookeeper
restart: always
container_name: dzk1
ports:
- "2181:2181"
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=dzk1:2888:3888 server.2=dzk2:2888:3888server.3=dzk3:2888:3888
dzk2:
image: zookeeper
restart: always
container_name: dzk2
ports:
- "2182:2181"
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=dzk1:2888:3888 server.2=dzk2:2888:3888server.3=dzk3:2888:3888
dzk3:
image: zookeeper
restart: always
container_name: dzk3
ports:
- "2183:2181"
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=dzk1:2888:3888 server.2=dzk2:2888:3888server.3=dzk3:2888:3888
1.10.4 启动
COMPOSE_PROJECT_NAME=myzk docker-compose up –d #设置环境变量
执行结果:
Creating network "myzk_default" with the default driver
Creating dzk3 ...
Creating dzk2 ...
Creating dzk1 ...
Creating dzk3
Creating dzk2
Creating dzk1 ... done
注意:成功后会自动匹配一个网络连接myzk_default
1.10.5 查看
COMPOSE_PROJECT_NAME=myzk docker-compose ps #查看版本
COMPOSE_PROJECT_NAME=myzk docker-compose stop #先停止
COMPOSE_PROJECT_NAME=myzk docker-compose rm #后删除
执行结果:
Name Command State Ports
------------------------------------------------------------------------------------------
dzk1 /docker-entrypoint.sh zkSe ... Up 0.0.0.0:2181->2181/tcp,2888/tcp, 3888/tcp
dzk2 /docker-entrypoint.sh zkSe ... Up 0.0.0.0:2182->2181/tcp,2888/tcp, 3888/tcp
dzk3 /docker-entrypoint.sh zkSe ... Up 0.0.0.0:2183->2181/tcp,2888/tcp, 3888/tcp
1.10.6 运行
docker run -it --rm \
--link z1:dzk1 \
--link z2:dzk2 \
--link z3:dzk3 \
--net myzk_default \
zookeeper zkCli.sh -server dzk1:2181,dzk2:2181,dzk3:2181
检查zk是否正常
上面就批处理实现了同时启动3个docker容器
docker ps #查看容器
docker exec -it 30389ad3865f bash #进入容器
cd bin #进入目录
ls #看看内容
./zkServer.sh status #查看zk节点的状态
exit #退出
cd bin
./zkCli.sh -server localhost:2181 #客户端连接
[zk: localhost:2181(CONNECTED) 0] ls / #查看根目录
[zookeeper, myapp]
[zk: localhost:2181(CONNECTED) 1] create /jtjt-web #创建节点
Created /jt
[zk: localhost:2181(CONNECTED) 2] ls /jt #查看节点
[]
[zk: localhost:2181(CONNECTED) 3] ls / #查看根目录
[jt, zookeeper, myapp]
[zk: localhost:2181(CONNECTED) 4] get /jt #获取新节点内容
jt-web
cZxid = 0x200000002
ctime = Fri May 26 09:15:11 GMT 2017
mZxid = 0x200000002
mtime = Fri May 26 09:15:11 GMT 2017
pZxid = 0x200000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
[zk: localhost:2181(CONNECTED) 5] set /jtjt-manage #修改信息
cZxid = 0x200000002
ctime = Fri May 26 09:15:11 GMT 2017
mZxid = 0x200000003
mtime = Fri May 26 09:15:52 GMT 2017
pZxid = 0x200000002
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: localhost:2181(CONNECTED) 6] get /jt #获取信息
jt-manage
cZxid = 0x200000002
ctime = Fri May 26 09:15:11 GMT 2017
mZxid = 0x200000003
mtime = Fri May 26 09:15:52 GMT 2017
pZxid = 0x200000002
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 9
numChildren = 0
[zk: localhost:2181(CONNECTED) 7] delete /jt #删除节点
[zk: localhost:2181(CONNECTED) 8] ls /
[zookeeper, myapp]
Ctrl+C #退出
1.10.7 测试
1.10.7.1 命令行
ls 查看指定节点中包含的子节点(如:ls / 或 ls/app1/server1)
create 创建节点并赋值
get 读取节点内容
set 改变节点内容
delete 删除节点
1.10.7.2 Maven依赖
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
或者
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.7</version>
</dependency>
1.10.7.3 测试类
package zk;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.I0Itec.zkclient.DataUpdater;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.IZkStateListener;
import org.I0Itec.zkclient.ZkClient;
importorg.apache.zookeeper.Watcher.Event.KeeperState;
/**
* ZkClient的使用测试
*/
public class ZkClientTest {
publicstatic void main(String[] args) {
ZkClient zkClient = newZkClient("192.168.163.135:2181,192.168.163.135:2182,192.168.163.135:2183");
String node = "/jt";
// 订阅监听事件
childChangesListener(zkClient, node);
dataChangesListener(zkClient, node);
stateChangesListener(zkClient);
if(!zkClient.exists(node)) {
//创建节点
zkClient.createPersistent(node, "jt zk");
}
System.out.println(zkClient.readData(node));
zkClient.updateDataSerialized(node, new DataUpdater<String>() {
//修改信息
public String update(String currentData) {
return currentData + "-new";
}
});
System.out.println(zkClient.readData(node));
try{
TimeUnit.SECONDS.sleep(3);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 订阅children变化
*/
publicstatic void childChangesListener(ZkClient zkClient, final String path) {
zkClient.subscribeChildChanges(path, new IZkChildListener() {
public void handleChildChange(String parentPath, List<String>currentChilds) throws Exception {
System.out.println("clildren of path " + parentPath +":" + currentChilds);
}
});
}
/**
* 订阅节点数据变化
*/
publicstatic void dataChangesListener(ZkClient zkClient, final String path){
zkClient.subscribeDataChanges(path, new IZkDataListener(){
public void handleDataChange(String dataPath, Object data) throwsException {
System.out.println("Data of " + dataPath + " haschanged.");
}
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("Data of " + dataPath + " haschanged.");
}
});
}
/**
* 订阅状态变化
*/
publicstatic void stateChangesListener(ZkClient zkClient){
zkClient.subscribeStateChanges(new IZkStateListener() {
public void handleStateChanged(KeeperState state) throws Exception {
System.out.println("handleStateChanged");
}
public void handleSessionEstablishmentError(Throwable error) throwsException {
System.out.println("handleSessionEstablishmentError");
}
public void handleNewSession() throws Exception {
System.out.println("handleNewSession");
}
});
}
}
1.11 x最简私服Registry
安装必要的软件
$ sudo apt-get install build-essential python-dev libevent-devpython-pip liblzma-dev
配置 docker-registry
sudo pip install docker-registry
或者使用 github clone 手动安装
$ git clone https://github.com/dotcloud/docker-registry.git
$ cd docker-registry/
$ cp config/config_sample.yml config/config.yml
$ mkdir /data/registry -p
$ pip install .
运行
docker-registry
高级启动方式 [不推荐]
使用gunicorn控制:
gunicorn -c contrib/gunicorn_config.py docker_registry.wsgi:application
或者对外监听开放
gunicorn --access-logfile - --error-logfile - -k gevent -b 0.0.0.0:5000-w 4 --max-requests 100 docker_registry.wsgi:application
10.3 提交指定容器到私有库
$ docker tag ubuntu:12.04 私有库IP:5000/ubuntu:12.04
$ docker push 私有库IP:5000/ubuntu
更多的配置选项推荐阅读官方文档:
Docker-Registry README
Docker-Registry advanced use
和Mavan的管理一样,Dockers不仅提供了一个中央仓库,同时也允许我们使用registry搭建本地私有仓库。使用私有仓库有许多优点:
l 节省网络带宽,针对于每个镜像不用每个人都去中央仓库上面去下载,只需要从私有仓库中下载即可;
l 提供镜像资源利用,针对于公司内部使用的镜像,推送到本地的私有仓库中,以供公司内部相关人员使用。
1.11.1 拉取私服镜像
[root@localhost docker]# docker pull registry
执行结果:
latest: Pulling from registry
1486fe9a5f49: Already exists
afb46c69edc0: Already exists
31e1a4cc7f43: Already exists
4d027e0583ff: Already exists
b62848d85f39: Already exists
f187d1ddc533: Already exists
67439767c005: Already exists
155885d4df5f: Already exists
98959b7d32cc: Already exists
Digest:sha256:1fd7f060074f8279ad001d5b24b612167a89c5eab42998eac7490d7b4ab3418a
Status: Image is up to date for registry:latest
[root@localhost docker]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
registry latest bb682e0824bd 6 daysago 33.17 MB
[root@localhost docker]#
1.11.2 启动容器
docker run -d -p 5000:5000 -v/opt/data/registry:/var/lib/registry --restart=always registry
执行结果:
17d73ca512b738d48c75ca2a879354a4f11f00c701da81c3721cc373bb571223
[root@localhost docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17d73ca512b7 registry "/entrypoint.sh /etc 12seconds ago Up 10 seconds 0.0.0.0:5000->5000/tcp loving_poitras
1.12 常见错误
1.12.1 docker Tag latest not found inrepository redis
docker Image for redis
docker pull redis
有时下载不完断掉,再次执行即可。如果仍然上面提示,让使用docker –d查看,直接reboot重启linux,然后重新执行。
1.12.2 Build a new image from thesource code at PATH
[root@bogon docker]# docker build -tjt-jdk:0.0.1
docker: "build" requires 1argument.
See 'docker build --help'.
Usage: docker build [OPTIONS] PATH | URL |-
Build a new image from the source code atPATH
执行命令少了最后的路径,加个.代表当前路径
docker build -t jt-jdk:0.0.1 .
1.12.3 docker-compose: 权限不够
/usr/local/bin/docker-compose: 权限不够
[root@localhost bin]# chmod +x/usr/local/bin/docker-compose