写在前面的话:
由于最近公司开始着手做云计算,自己有幸参与整个项目的全过程,所以呢,准备在blog中记录整个项目从无到有,从测试到生产的全过程,希望对自己的每一步进行一个记录以及在项目中遇到的坑和如何解决。希望大家能够在此找到一点点借鉴。
==华丽分割线====================================================================
什么是docker?
docker的字面意思是码头工人,与集装箱有关,那么docker就可以理解为是一个集装箱(容器)。
详细的说:
dockers是dockers.inc 公司开源的一个基于LXC技术之上构建的container容器引擎(说个题外话 openstack基于KVM ,docker基于LXC),源代码托管在GITHUB上,基于GO 语言并遵从apache2.0 协议开源。(可以商业,改吧改吧就可以卖钱了)。
docker是通过内核虚拟化技术((namespaces及cgroups等),KVM呢是通过硬件虚拟化技术,CPU支持的。)来提供容器的资源隔离与 安全保障等。
在非linux平台是没法使用docker的,因为他是基于内核技术来实现资源隔离和安全保障的。
由于dockers通过操作系统层的虚拟化实现隔离,所以docker容器在运行的时候,不需要类似虚拟机(VM)额外的操作系统开销,提高了资源的利用率。
docker官网在此 https://www.docker.com/,截个图来说明一下docker的三大理念。
如上图所示:Build ,ship ,Run(构建,运输, 运行)。
构建:这就是docker的三大核心理念,认为一个东西我构建上了,放在某个地方就可以运行起来,可以用java来进行一个对比,怎么说呢?我有JVM虚拟机,一次构建,备考之后到处运行。但是呢,也有不同的地方,因为docker里面运行的是一个应用(apache ,nginx,tomcat), 它的构建是基于docker的镜像,可以基于这个镜像起任何的容器。
运输: 我们知道openstack 的镜像传到glance ,那么docker是传在dockerhub,一个私有的地方,谁有权访问我就可以给它。
运行:docker运行是起一个容器。
docker的组成
docker是一个传统的CS结构的架构:客户端服务器。BS是什么呢?浏览器和服务器模式。
有一个dockerclient 和docker server
三个组件: 镜像(image) 、容器(container)、仓库(repository)。
docker与openstack的对比:
类别 | docker | open |
部署难度 | 非常简答 | 组件多,部署复杂 |
启动速度 | 秒级 | 分钟级 |
执行性能 | 和物理机系统几乎一至 | VM会占用一些资源 |
镜像体积 | 镜像是MB级别 | 虚拟机镜像GB级别 |
管理效率 | 管理简单 | 组件相互依赖,管理复杂 |
隔离性 | 隔离性高 | 彻底隔离 |
可管理性 | 单进程,不建议启动SSH | 完整的系统管理 |
网络连接 | 比较弱 | 借助neutron可以灵活组件各类网络架构 |
| | |
为什么不建议启动SSH?
这就是docker的理念,我们起一个docker容器,我在里面安装一个zabbix-agent ,saltstack-agent,ssh 当作虚拟机使用,那为什么不直接用虚拟机?
难道就差启动的分钟级这个时间么,docker的真正的最佳实践不是当作虚拟机使用,但是为什么有的还是当虚拟机使用呢?因为没有openstack,关键到底还是要看业务,我们知道IT管理的PPT(流程,人员,工具),比如说,一个新型的公司,架构从头规划,可以根据docker模式来规划,但是如果架构已经成型,流程组织结构都已固话,那么就得考虑业务是否要使用容器来启动。
docker能干什么?
1、简化配置
工作中有很多环境,比如测试环境,开发环境,性能测试,生产和预生产,环境不一致,配置不一致会导致上线失败,测试安装了一个python的依赖,线上没有,测试通过,上生产就开始报错。(不能导入某个模块,起不来了)。
docker可以简化配置,做好一个镜像,直接拿镜像就起得来。openstack也能干这事,saltstack也可以做这些事。
docker解决的不是openstack的问题,应该和RPM包进行对比或者saltstack来对比。
saltstack就可以简化环境,一条命令解决。
2、代码流水线管理
开发写代码-开发环境-提交SVN-测试拉下来测试-预生产环境-灰度发布(生产环境)。
3、开发效率
开发人员入职第一天配环境,用docker镜像构建好,需要啥都装好,RUN起来就完事。
openstack也可以做,给个虚拟镜像就完事。给个IP地址,用户密码SSH上去就完事。举个例子:
这么对比来说,openstack效率更高,给开发每人一台虚拟机,把6080对外(NOVNCPROXY端口),这样开发在家都可以使用,虚拟机在远端,跟你是否在本地没有关系,但是docker不行,因为docker是启在本地。
4、应用隔离
虚拟机是完全隔离,docker只是一个隔离,只是没有占用资源
5、整合服务器
服务器可以跑多个容器来提高利用率,但是也可以其多个虚拟机进程
6、debug能力
docker开发想调试很难,虚拟机爱怎么调都可以
7、多租户
openstack设计就是多租户,一个租户可以有多个用户
8、快速部署
docker是秒级,体积小,完胜openstack
docker就是以快为容器,比如,抢红包,我可以1秒钟启动上千个容器,但是起虚拟机不行。
但是呢,一切的一切还是看业务。
使用docker的几个理由:
1、技术储备
2、跟上潮流
3、符合当前业务需求
大多数都是第2个,很少说有业务需求的。
安装SSH来进行管理,其实我们也是这么做的。
优势就是快,但是缺点很多。
docker组成基于CS,如果server宕了呢?所有的容器都会停止运行,没有多server,业界虽有提出,但是还是不行。
所以说,现在基本上都是混合使用docker,不能把鸡蛋放到一个篮子里,如果docker报了一个大bug,所有容器都宕掉了,怎么办?
作为一个合格的架构师要考虑到不可能的可能。还是那句话,不能把鸡蛋放到一个篮子里。
那么docker改变了什么呢?
1、面向产品: 产品交付
2、面向开发: 简化环境配置
3、面向测试: 多版本测试
4、面向运维: 环境一致性
5、面向架构: 自动化扩容(微服务)
=================================分割线=====================================================
实战来了:
1、安装docker
1
|
[root@jixuege ~]# yum install docker
|
2、启动docker
1
|
[root@jixuege ~]
# systemctl start docker
|
3、pull镜像
1
|
[root@jixuege ~]
# docker pull centos
|
4、查看镜像
1
2
3
4
|
[root@jixuege ~]
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.io
/centos
latest 60e65a8e4030 6 weeks ago 196.6 MB
属于哪个仓库 标签 唯一ID 创建时间 大小
|
镜像怎么来的?
可以自己导入一个,方法如下
导出镜像到/opt目录
1
2
3
|
[root@jixuege ~]
# docker save centos >/opt/centos.tar.gz
[root@jixuege ~]
# ll /opt/
-rw-r--r-- 1 root root 204205056 Feb 5 16:09 centos.
tar
.gz
|
从/opt目录下导入镜像
1
|
[root@jixuege ~]
# docker load < /opt/centos.tar.gz
|
这样就可以导入镜像了
5、如何删除一个镜像呢?
1
2
|
[root@jixuege ~]
# docker rmi ID号
注意,如果镜像创建了容器,那么镜像不能被删除,如果想删除,需要加参数 -f 即 docker rmi -f ID号
|
6、创建并启动第一个容器
1
2
|
[root@jixuege ~]
# docker run centos /bin/echo "hehe"
hehe
|
说明:
docker run 所有容器都使用这个参数 centos指的是镜像的名称,后面跟着是一个命令,启动一个容器执行了一个命令:echo "hehe"
运行完之后就退出了,没有为容器指定名字
7、查看一下刚才创建的容器:
1
2
3
4
|
[root@jixuege ~]
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c2e9c96f6f9c centos
"/bin/echo hehe"
4 minutes ago Exited (0) 4 minutes ago hungry_chandrasekhar
容器的ID 镜像 命令 创建时间 状态(退出) 端口没有 不给名字它自己起了一个名字
|
8、启动一个有名字的容器不让退出
1
2
3
4
5
6
|
[root@jixuege ~]
# docker run --name mydocker -t -i centos /bin/bash
[root@a15b76fd966d /]
#
--name 起一个名字
-t 分配一个伪终端
-i 容器的标准输入为打开状态,这2个要一起使用
/bin/bash
执行一个命令,这个命令是
/bin/bash
|
启动容器是秒级的
9、查看
1
2
3
4
5
|
[root@a15b76fd966d /]
# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 11772 1868 ? Ss 03:55 0:00
/bin/bash
root 14 0.0 0.1 35888 1472 ? R+ 03:57 0:00
ps
aux
[root@a15b76fd966d /]
#
|
这个容器里面只有一个进程就是/bin/bash,也就是说这个容器只运行了一个进程,这个进程是在启动容器的时候让它执行的。
我们在主机上查看,运行的容器
1
2
3
|
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a15b76fd966d centos
"/bin/bash"
2 minutes ago Up 2 minutes mydocker
|
容器的主机名和容器的ID是一样的。
当执行docker run的时候,它会在本地检查有没有centos这个镜像,如果没有就在dockerhub上去下载一个,有的话就直接启动,利用这个镜像启动容器。
10、退出容器
1
2
|
[root@a15b76fd966d /]
# exit
exit
|
退出以后,容器就自动终止了。
11、镜像的管理
搜索镜像:
docker search +镜像名(centos 、 nginx 等)
1
2
3
4
5
6
7
|
[root@jixuege ~]# docker search centos
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/centos The official build of CentOS. 1902 [OK]
docker.io docker.io/jdeathe/centos-ssh CentOS-6 6.7 x86_64 / EPEL/IUS Repos / Ope... 14 [OK]
docker.io docker.io/jdeathe/centos-ssh-apache-php CentOS-6 6.7 x86_64 / Apache / PHP / PHP M... 11 [OK]
docker.io docker.io/million12/centos-supervisor Base CentOS-7 with supervisord launcher, h... 9 [OK]
docker.io docker.io/blalor/centos Bare-bones base CentOS 6.5 image 8 [OK]
|
获取镜像:
docker pull + 镜像的name
1
2
3
|
[root@jixuege ~]# docker pull docker.io/jdeathe/centos-ssh-apache-php
Using default tag: latest
Trying to pull repository docker.io/jdeathe/centos-ssh-apache-php ... latest: Pulling from jdeathe/centos-ssh-apache-php
|
注意,这个地方pull的后面需要接整个镜像的name,如果有标签需要加上标签,不加的话默认是Using default tag: latest
查看镜像:
docker images
1
2
3
|
[root@jixuege ~]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/mynginx v4 109dc6393163 5 weeks ago 350.9 MB
|
删除镜像:
docker rmi +镜像ID
启动容器:
docker run --name test -it centos /bin/bash
查看容器:
docker ps 查看运行的容器
docker ps -a 查看所有容器包括已停止的
docker start ID 把停止的容器启动起来
进入容器呢?
docker attach +容器的ID 这样就进入到容器里面了
举例:
1
2
3
|
[root@jixuege ~]
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a15b76fd966d centos
"/bin/bash"
56 minutes ago Exited (0) 50 minutes ago mydocker
|
这个是已停止的容器,那么启动容器
1
2
|
[root@jixuege ~]
# docker start a15b76fd966d
a15b76fd966d
|
进入容器
1
2
3
4
5
|
[root@jixuege ~]
# docker attach a15b76fd966d
[root@a15b76fd966d /]
# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 11772 1860 ? Ss 04:53 0:00
/bin/bash
root 15 1.0 0.1 35888 1468 ? R+ 04:54 0:00
ps
aux
|
现在如果我exit出去,容器就停止了。这个不是我们想看到的,为什么呢?因为你退出了bash
所以说容器适合单进程,比如说我起个nginx,我就只起一个nginx,容器的理念就是单进程,可以当虚拟机使用,但是理念不是一个虚拟机。
另外一种方法进入容器exit不让其退出就是nsenter,如果没有需要安装util-linux,这个可以访问另一个进程的名字空间namespace。
我们需要知道进程的PID
启动容器,因为一个静止的容器不会有PID
1
2
|
[root@jixuege ~]
# docker start a15b76fd966d
a15b76fd966d
|
查看启动的容器
1
2
3
|
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a15b76fd966d centos
"/bin/bash"
About an hour ago Up 2 seconds mydocker
|
查看PID
1
2
|
[root@jixuege ~]
# docker inspect --format "{{.State.Pid}}" a15b76fd966d
31106
|
进入容器
1
2
|
[root@jixuege ~]
# nsenter -t 31106 -u -i -n -p
[root@a15b76fd966d ~]
#
|
退出,发现依旧在运行
1
2
3
4
5
|
[root@a15b76fd966d ~]
# exit
logout
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a15b76fd966d centos
"/bin/bash"
About an hour ago Up 3 minutes mydocker
|
写成脚本,传PID就可以进入
1
2
3
4
5
6
7
8
9
10
|
[root@jixuege ~]
# cat ns.sh
#!/bin/bash
PID=$(docker inspect --
format
"{{.State.Pid}}"
$1)
nsenter -t $PID -u -i -n -p
[root@jixuege ~]
# chmod +x ns.sh
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a15b76fd966d centos
"/bin/bash"
About an hour ago Up 6 minutes mydocker
[root@jixuege ~]
# ./ns.sh a15b76fd966d
[root@a15b76fd966d ~]
#
|
比较推荐进入docker容器的方式。
如何删除容器呢?
docker rm ID 删除已停止运行的容器
docker rm -f ID 强行删除正在运行的容器
创建容器,容器退出自动删除
1
|
docker run --
rm
centos
/bin/echo
"hehe"
|
删除正在运行的容器
1
|
[root@jixuege ~]
# docker kill $(docker ps -a -q)
|
还有2种进入容器的方式
docker exec |docker attach 这2种方式不推荐,还是推荐使用nsenter -t $PID -u -i -n -p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Usage:
nsenter [options] <program> [args...]
Options:
-t, --target <pid> target process to get namespaces from 后面接PID
-m, --
mount
[=<
file
>] enter
mount
namespace
-u, --uts [=<
file
>] enter UTS namespace (
hostname
etc)
-i, --ipc [=<
file
>] enter System V IPC namespace
-n, --net [=<
file
>] enter network namespace
-p, --pid [=<
file
>] enter pid namespace
-r, --root [=<
dir
>]
set
the root directory
-w, --wd [=<
dir
>]
set
the working directory
-F, --no-fork
do
not fork before
exec
'ing <program>
-h, --help display this help and
exit
-V, --version output version information and
exit
For
more
details see nsenter(1).
|
12、docker的网络访问
默认是帮忙做了一个映射,有个桥接网卡,帮忙做端口映射
1
2
3
|
[root@jixuege ~]
# brctl show
bridge namebridge idSTP enabledinterfaces
docker08000.024241919583no
|
让容器里的某一个端口对外,映射有两种方式,随机映射和指定端口映射
1
2
3
4
5
6
|
[root@jixuege ~]
# docker run -d -P nginx
99ce23e7ef812403fc46c797fb4ac1631eacd34a335d59588112160d716d4132
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
99ce23e7ef81 nginx
"nginx -g 'daemon off"
16 seconds ago Up 14 seconds 0.0.0.0:32769->80
/tcp
, 0.0.0.0:32768->443
/tcp
berserk_kowalevski
[root@jixuege ~]
#
|
访问以下
查看访问日志
1
2
3
4
|
[root@jixuege ~]
# docker logs 99ce23e7ef81
192.168.56.1 - - [06
/Feb/2016
:05:31:54 +0000]
"GET / HTTP/1.1"
200 612
"-"
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36"
"-"
2016
/02/06
05:31:54 [error] 6
#6: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.56.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.56.123:32769", referrer: "http://192.168.56.123:32769/"
192.168.56.1 - - [06
/Feb/2016
:05:31:54 +0000]
"GET /favicon.ico HTTP/1.1"
404 570
"http://192.168.56.123:32769/"
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36"
"-"
|
指定端口映射: 参数-p
再启动一个nginx,81对应容器里面的80
1
2
3
4
5
|
[root@jixuege ~]
# docker run -d -p 81:80 nginx
74dd6739a63009777113f7953a3da4e912eab33125ba0d06d8c2998d51869743
[root@jixuege ~]
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
74dd6739a630 nginx
"nginx -g 'daemon off"
3 seconds ago Up 2 seconds 443
/tcp
, 0.0.0.0:81->80
/tcp
berserk_wozniak
|
访问一下:
这个就是docker的网络访问了。
13、docker数据管理
docker的数据存储默认有2种方式来管理容器中的数据
1)数据卷:一个特殊的容器,所有其他的docker都可以连到这个容器,共享一个data,类似于搞一个NFS
启动一个看看
1
2
3
|
[root@jixuege ~]
# docker run -it --name volume-test1 -v /data/ centos
[root@f7635bd01032 /]
# ll /data/
total 0
|
怎么查看数据放在哪了呢?
#列出所有的信息
[root@jixuege ~]# docker inspect f7635bd01032
找到下面这个Source
1
2
3
4
5
6
7
8
9
10
|
"Mounts"
: [
{
"Name"
:
"ede625a5f6da0417ec616b30368e6b7d2181f89f882d9c7f7824dfe74c9acc5e"
,
"Source"
:
"/var/lib/docker/volumes/ede625a5f6da0417ec616b30368e6b7d2181f89f882d9c7f7824dfe74c9acc5e/_data"
,
"Destination"
:
"/data"
,
"Driver"
:
"local"
,
"Mode"
:
""
,
"RW"
:
true
}
],
|
进入到这个目录下,创建一个文件,然后在容器的/data/目录下查看看是否有这个文件
1
2
3
4
|
[root@jixuege ~]
# cd /var/lib/docker/volumes/ede625a5f6da0417ec616b30368e6b7d2181f89f882d9c7f7824dfe74c9acc5e/_data
[root@jixuege _data]
# touch test
[root@jixuege _data]
# ls
test
|
去容器下查看并验证
1
2
3
|
[root@f7635bd01032 /]
# ll /data/
total 0
-rw-r--r-- 1 root root 0 Feb 6 11:48
test
|
说明:上面的命令是起一个容器,然后呢,把容器的/data/目录挂载到物理机的source下的目录下,这样我在物理机上创建的文件都可以直接同步到容器里面。
#还可以,启动一个容器,挂载到物理机的指定目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[root@jixuege ~]
# docker run -it -v /opt/:/opt centos
[root@eeb1353b4cae /]
# ll /opt/
total 1200816
-rw-r--r-- 1 root root 33 Jan 12 09:52 a.sh
drwxr-xr-x 9 root root 149 Dec 29 02:36 apache-tomcat-8.0.30
-rw-r--r-- 1 root root 9150593 Dec 1 22:56 apache-tomcat-8.0.30.
tar
.gz
-rw-r--r-- 1 root root 204205056 Feb 5 08:09 centos.
tar
.gz
drwxr-xr-x 3 root root 18 Dec 29 13:21 dockerfile
-rw-r--r-- 1 root root 0 Dec 29 12:12 hehe
-rw-r--r-- 1 root root 181260798 Dec 29 03:02 jdk-8u65-linux-x64.
tar
.gz
drwxr-xr-x 8 10 143 4096 Oct 7 00:29 jdk1.8.0_65
-rw-r--r-- 1 root root 18082304 Jan 4 02:10 microbox_etcd.
tar
.gz
drwxr-xr-x 2 root root 61 Dec 30 09:15 nginx
-rw-r--r-- 1 root root 442205184 Jan 13 11:36 registry.
tar
.gz
-rw-r--r-- 1 root root 188601344 Jan 4 01:41 rethinkdb.
tar
.gz
drwxr-xr-x. 2 root root 6 Oct 29 2014 rh
-rw-r--r-- 1 root root 61221888 Jan 7 16:57 shipyard.
tar
.gz
-rw-r--r-- 1 root root 107682084 Jan 8 02:42 shipyard.zip
-rw-r--r-- 1 root root 17193472 Jan 7 16:37 swarm.
tar
.gz
-rw-r--r-- 1 root root 12 Jan 12 09:52
test
.sh
|
可以把物理机 的一个目录挂到/data/目录下,适用于什么场景呢?
比如说我开发写好了代码在物理机的/data/目录,我可以把这个目录挂载到一台nginx的容器,然后呢吧容器里的nginx的路径指定到挂载点即可。
#还可以挂载单个文件
1
2
3
|
[root@jixuege ~]
# docker run -it -v ~/.bash_history:/.bash_histroy centos
[root@df1ddc3ee603 /]
# ll .bash_histroy
-rw------- 1 root root 12146 Feb 6 05:01 .bash_histroy
|
#挂载并指定权限为只读
1
2
|
[root@jixuege ~]
# docker run -it -v /opt:/opt:ro centos
[root@963470b40e76 /]
# ll /opt/
|
这样进入容器之后不能修改文件,只能读
所有评论(0)