docker

操作概念图

操作概念图

对应概念

  • 镜像:就类似于我们用虚拟机,创建虚拟机前要下载的系统镜像文件,比如iso文件、img文件等等这样一些镜像文件。通俗来说就是为容器用来创建容器的

  • 容器:它可以类比成正在运行中的一个虚拟机。

  • tar文件:tar文件就类似于vm使用时的vmdk文件,它可以将镜像直接保存成一个tar文件,然后怎样给别人然后别人通过load指令,重新加载成一个镜像,然后通过run指令就可以起来一个正在运行中的容器了。

  • Dockerfile:Dockerfile相当于一个配置文件,通过写“如何构建”的步骤,来指定一个镜像是如何构建的。通过docker build指令可以将dockerfile构建成一个镜像。

  • 仓库(Repository):仓库中保存了很多的镜像,包括一些共有的第三方已经做好的镜像比如ubuntu镜像nginx镜像mysql镜像tomcat镜像等等。我们可以通过docker poll指令下载这些镜像到本地。当然也可以把这些镜像通过push上传上去。

docker总述

通过以上这些技术的组合,最后的结果就是,绝大部分应用,开发者都可以通过docker build创建镜像,通过docker push上传镜像,用户通过docker pull下载镜像,用docker run运行应用。用户不需要再去关心如何搭建环境,如何安装,如何解决不同发行版的库冲突——而且通常不会需要消耗更多的硬件资源,不会明显降低性能。这就是其他答主所说的标准化、集装箱的原因所在。


Docker基础命令操作

查看docker相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@docker01 ~]#  docker version  
Client:
Version: 17.12.0-ce
API version: 1.35
Go version: go1.9.2
Git commit: c97c6d6
Built: Wed Dec 27 20:10:14 2017
OS/Arch: linux/amd64
Server:
Engine:
Version: 17.12.0-ce
API version: 1.35 (minimum version 1.12)
Go version: go1.9.2
Git commit: c97c6d6
Built: Wed Dec 27 20:12:46 2017
OS/Arch: linux/amd64
Experimental: false

配置docker镜像加速

1
2
3
4
vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

启动第一个容器

1
2
3
4
5
6
7
8
9
10
[root@docker01 ~]# docker run -d -p 80:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
e7bb522d92ff: Pull complete
6edc05228666: Pull complete
cd866a17e81f: Pull complete
Digest: sha256:285b49d42c703fdf257d1e2422765c4ba9d3e37768d6ea83d7fe2043dad6e63d
Status: Downloaded newer image for nginx:latest
8d8f81da12b5c10af6ba1a5d07f4abc041cb95b01f3d632c3d638922800b0b4d
# 容器启动后,在浏览器进行访问测试

参数说明

Image

Docker镜像生命周期

Image

Docker镜像相关操作

搜索官方仓库镜像

1
2
3
4
[root@docker01 ~]#  docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 3992 [OK]
ansible/centos7-ansible Ansible on Centos7 105 [OK]

列表说明

Image

获取镜像

根据镜像名称拉取镜像

1
2
3
4
[root@docker01 ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
af4b0a2388c6: Downloading 34.65MB/73.67MB

查看当前主机镜像列表

1
2
3
4
[root@docker01 ~]# docker image list 
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest ff426288ea90 3 weeks ago 207MB
nginx latest 3f8a4339aadd 5 weeks ago 108MB

拉第三方镜像方法

1
docker pull index.tenxcloud.com/tenxcloud/httpd

导出镜像

1
2
3
4
5
6
[root@docker01 ~]# docker image list 
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest ff426288ea90 3 weeks ago 207MB
nginx latest 3f8a4339aadd 5 weeks ago 108MB
# 导出
[root@docker01 ~]# docker image save centos > docker-centos.tar.gz

删除镜像

1
2
3
4
[root@docker01 ~]# docker image rm centos:latest
[root@docker01 ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 3f8a4339aadd 5 weeks ago 108MB

导入镜像

1
2
3
4
5
6
7
[root@docker01 ~]# docker image load -i docker-centos.tar.gz  
e15afa4858b6: Loading layer 215.8MB/215.8MB
Loaded image: centos:latest
[root@docker01 ~]# docker image list
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest ff426288ea90 3 weeks ago 207MB
nginx latest 3f8a4339aadd 5 weeks ago 108MB

查看镜像的详细信息

1
[root@docker01 ~]# docker image inspect centos

容器的日常管理

容器的起/停

最简单的运行一个容器

1
[root@docker01 ~]# docker run nginx

创建容器,两步走(不常用)

1
2
3
4
[root@docker01 ~]# docker create centos:latest  /bin/bash
bb7f32368ecf0492adb59e20032ab2e6cf6a563a0e6751e58930ee5f7aaef204
[root@docker01 ~]# docker start stupefied_nobel
stupefied_nobel

快速启动容器方法

1
[root@docker01 ~]# docker run  centos:latest  /usr/bin/sleep 20;

容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

查看正在运行的容器

1
2
3
4
5
[root@docker01 ~]# docker container ls

[root@docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8708e93fd767 nginx "nginx -g 'daemon of…" 6 seconds ago Up 4 seconds 80/tcp keen_lewin

查看你容器详细信息/ip

1
[root@docker01 ~]# docker container  inspect  容器名称/id

查看你所有容器(包括未运行的)

1
2
3
4
5
[root@docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8708e93fd767 nginx "nginx -g 'daemon of…" 4 minutes ago Exited (0) 59 seconds ago keen_lewin
f9f3e6af7508 nginx "nginx -g 'daemon of…" 5 minutes ago Exited (0) 5 minutes ago optimistic_haibt
8d8f81da12b5 nginx "nginx -g 'daemon of…" 3 hours ago Exited (0) 3 hours ago lucid_bohr

停止容器

1
2
3
4
[root@docker01 ~]# docker stop 容器名称/id 

[root@docker01 ~]# docker container kill 容器名称/id

进入容器方法

启动时进去方法

1
2
3
[root@docker01 ~]# docker run -it #参数:-it 可交互终端
[root@docker01 ~]# docker run -it nginx:latest /bin/bash
root@79241093859e:/#

退出/离开容器

1
ctrl+p & ctrl+q

启动后进入容器的方法

启动一个docker

1
2
3
4
5
[root@docker01 ~]# docker run -it centos:latest 
[root@1bf0f43c4d2f /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:47 pts/0 00:00:00 /bin/bash
root 13 1 0 15:47 pts/0 00:00:00 ps -ef

attach进入容器,使用pts/0 ,会让所用通过此方法进如放入用户看到同样的操作。

1
2
3
4
5
[root@docker01 ~]# docker attach 1bf0f43c4d2f
[root@1bf0f43c4d2f /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:47 pts/0 00:00:00 /bin/bash
root 14 1 0 15:49 pts/0 00:00:00 ps -ef

自命名启动一个容器 –name

1
2
3
4
5
[root@docker01 ~]# docker attach 1bf0f43c4d2f
[root@1bf0f43c4d2f /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:47 pts/0 00:00:00 /bin/bash
root 14 1 0 15:49 pts/0 00:00:00 ps -ef

exec 进入容器方法(推荐使用)

1
2
3
4
5
6
7
[root@docker01 ~]# docker exec -it clsn1  /bin/bash 
[root@b20fa75b4b40 /]# 重新分配一个终端
[root@b20fa75b4b40 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 16:11 pts/0 00:00:00 /bin/bash
root 13 0 0 16:14 pts/1 00:00:00 /bin/bash
root 26 13 0 16:14 pts/1 00:00:00 ps -ef

删除所有容器

1
2
[root@docker01 ~]# docker rm -f  `docker ps -a -q`
# -f 强制删除

启动时进行端口映射

-p参数端口映射

1
2
[root@docker01 ~]# docker run -d -p 8888:80  nginx:latest 
287bec5c60263166c03e1fc5b0b8262fe76507be3dfae4ce5cd2ee2d1e8a89a9

不同指定映射方法

Image

随机映射

1
docker run -P (大P)# 需要镜像支持

Docker 数据卷的管理

挂载时创建卷

挂载卷

1
2
[root@docker01 ~]# docker run -d -p 80:80 -v /data:/usr/share/nginx/html nginx:latest
079786c1e297b5c5031e7a841160c74e91d4ad06516505043c60dbb78a259d09

容器内站点目录: /usr/share/nginx/html

在宿主机写入数据,查看

1
2
3
[root@docker01 ~]# echo "http://www.nmtui.com" >/data/index.html
[root@docker01 ~]# curl 10.0.0.100
http://www.nmtui.com

设置共享卷,使用同一个卷启动一个新的容器

1
2
3
4
[root@docker01 ~]# docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx:latest 
351f0bd78d273604bd0971b186979aa0f3cbf45247274493d2490527babb4e42
[root@docker01 ~]# curl 10.0.0.100:8080
http://www.nmtui.com

查看卷列表

1
2
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME

创建卷后挂载

创建一个卷

1
2
3
4
5
[root@docker01 ~]# docker volume create 
f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521

指定卷名

1
2
3
4
[root@docker01 ~]# docker volume ls 
DRIVER VOLUME NAME
local clsn
local f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521

查看卷路径

1
2
3
4
5
6
7
8
9
10
11
12
[root@docker01 ~]# docker volume inspect clsn 
[
{
"CreatedAt": "2018-02-01T00:39:25+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/clsn/_data",
"Name": "clsn",
"Options": {},
"Scope": "local"
}
]

使用卷创建

1
2
3
4
5
6
[root@docker01 ~]# docker run -d -p 9000:80 -v clsn:/usr/share/nginx/html nginx:latest 
1434559cff996162da7ce71820ed8f5937fb7c02113bbc84e965845c219d3503
# 宿主机测试
[root@docker01 ~]# echo 'blog.nmtui.com' >/var/lib/docker/volumes/clsn/_data/index.html
[root@docker01 ~]# curl 10.0.0.100:9000
blog.nmtui.com

设置卷

1
2
[root@docker01 ~]# docker run  -d  -P  --volumes-from 079786c1e297 nginx:latest 
b54b9c9930b417ab3257c6e4a8280b54fae57043c0b76b9dc60b4788e92369fb

查看使用的端口

1
2
3
4
5
6
7
8
9
10
11
12
[root@docker01 ~]# netstat -lntup 
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1400/sshd
tcp 0 0 10.0.0.100:2375 0.0.0.0:* LISTEN 26218/dockerd
tcp6 0 0 :::9000 :::* LISTEN 32015/docker-proxy
tcp6 0 0 :::8080 :::* LISTEN 31853/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 31752/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 1400/sshd
tcp6 0 0 :::32769 :::* LISTEN 32300/docker-proxy
[root@docker01 ~]# curl 10.0.0.100:32769
http://www.nmtui.com

手动将容器保存为镜像

本次是基于docker官方centos 6.8 镜像创建

官方镜像列表:

https://hub.docker.com/explore/

启动一个centos6.8的镜像

1
2
3
4
5
6
[root@docker01 ~]# docker pull  centos:6.8
[root@docker01 ~]# docker run -it -p 1022:22 centos:6.8 /bin/bash
# 在容器种安装sshd服务,并修改系统密码
[root@582051b2b92b ~]# yum install openssh-server -y
[root@582051b2b92b ~]# echo "root:123456" |chpasswd
[root@582051b2b92b ~]# /etc/init.d/sshd start

启动完成后镜像ssh连接测试

将容器提交为镜像

1
[root@docker01 ~]# docker commit brave_mcclintock  centos6-ssh

使用新的镜像启动容器

1
2
[root@docker01 ~]# docker run -d  -p 1122:22  centos6-ssh:latest  /usr/sbin/sshd -D 
5b8161fda2a9f2c39c196c67e2eb9274977e7723fe51c4f08a0190217ae93094

在容器安装httpd服务

1
[root@5b8161fda2a9 /]#  yum install httpd -y

编写启动脚本脚本

1
2
3
4
5
6
[root@5b8161fda2a9 /]# cat  init.sh 
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D
[root@5b8161fda2a9 /]# chmod +x init.sh
# 注意执行权限

再次提交为新的镜像

1
2
[root@docker01 ~]# docker commit  5b8161fda2a9 centos6-httpd 
sha256:705d67a786cac040800b8485cf046fd57b1828b805c515377fc3e9cea3a481c1

启动镜像,做好端口映射。并在浏览器中测试访问

1
2
[root@docker01 ~]# docker run -d -p 1222:22 -p 80:80  centos6-httpd /init.sh 
46fa6a06644e31701dc019fb3a8c3b6ef008d4c2c10d46662a97664f838d8c2c

Dockerfile自动构建docker镜像

官方构建dockerffile文件参考

https://github.com/CentOS/CentOS-Dockerfiles

Dockerfile指令集

dockerfile主要组成部分:

  • 基础镜像信息 FROM centos:6.8
  • 制作镜像操作指令RUN yum insatll openssh-server -y
  • 容器启动时执行指令 CMD [“/bin/bash”]

dockerfile常用指令:

  • FROM 这个镜像的妈妈是谁?(指定基础镜像)
  • MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)
  • RUN 你想让它干啥(在命令前面加上RUN即可)
  • ADD 给它点创业资金(COPY文件,会自动解压)
  • WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)
  • VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)
  • EXPOSE 它要打开的门是啥(指定对外的端口)
  • CMD 奔跑吧,兄弟!(指定容器启动后的要干的事情)

dockerfile其他指令:

  • COPY 复制文件
  • ENV 环境变量
  • ENTRYPOINT 容器启动后执行的命令

创建一个Dockerfile

创建第一个Dockerfile文件

1
2
3
4
5
6
7
8
9
# 创建目录
[root@docker01 base]# cd /opt/base
# 创建Dcokerfile文件,注意大小写
[root@docker01 base]# vim Dockerfile
FROM centos:6.8
RUN yum install openssh-server -y
RUN echo "root:123456" |chpasswd
RUN /etc/init.d/sshd start
CMD ["/usr/sbin/sshd","-D"]

构建docker镜像

1
2
[root@docker01 base]# docker image build  -t centos6.8-ssh . 
-t 为镜像标签打标签 . 表示当前路径

使用自构建的镜像启动

1
2
[root@docker01 base]# docker run  -d -p 2022:22 centos6.8-ssh-b 
dc3027d3c15dac881e8e2aeff80724216f3ac725f142daa66484f7cb5d074e7a

使用Dcokerfile安装kodexplorer

Dockerfile文件内容

1
2
3
4
5
6
7
8
FROM centos:6.8
RUN yum install wget unzip php php-gd php-mbstring -y && yum clean all
# 设置工作目录,之后的操作都在这个目录中
WORKDIR /var/www/html/
RUN wget -c http://static.kodcloud.com/update/download/kodexplorer4.25.zip
RUN unzip kodexplorer4.25.zip && rm -f kodexplorer4.25.zip
RUN chown -R apache.apache .
CMD ["/usr/sbin/apachectl","-D","FOREGROUND"]

更多的Dockerfile可以参考官方方法。

Docker中的镜像分层

参考文档:

http://www.maiziedu.com/wiki/cloud/dockerimage/

Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。

Image

从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

Docker 镜像为什么分层

镜像分层最大的一个好处就是共享资源。

比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。这就是容器 Copy-on-Write 特性。

可写的容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

Image

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

容器层的细节说明

镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。

文件操作的

Image

只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。

这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。

参考: