Docker基础
介绍
解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术
与传统虚拟化方式的不同
- 传统虚拟化技术是虚拟出一套硬件之后,在其上运行一个完整的操作系统,在该系统上再运行所需应用进程
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟.因此容器要比虚拟机更加方便
- 容器之间相互隔离,每个容器有自己的文件系统,容器之间进程不会互相影响,能区分计算资源
为什么比虚拟机快
- docker有比虚拟机更少的抽象层. 由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源. 因此在cpu,内存利用率上docker将会在效率上有明显优势
- docker利用的是宿主机的内核,而不需要GuestOS.
- 因此,当创建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核. 创建一个虚拟机时,虚拟机软件需要加载GuestOS,整个新建过程是分钟级别的
三部分
- 镜像 Image
- 容器 Container
- 容器是用镜像创建的运行实例
- 每个容器都是相互隔离的
- 可以把容器看作是一个简易版的Linux环境
- 仓库 Repository
- 集中存放镜像的地方
- 分为公开仓库public和私有仓库private两种形式
- 最大的公开仓库是Docker Hub. 国内有阿里云,网易云
安装
参考官网: https://docs.docker.com/engine/install/centos/
使用阿里云镜像加速
参考官网: https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
常用命令
帮助命令
docker version
docker info
docker --help
镜像命令
docker images
- -q 显示id
- -a 列出全部
docker search
Options:
**–automated :**只列出 automated build类型的镜像;
**–no-trunc :**显示完整的镜像描述;
**-f <过滤条件>:**列出收藏数不小于指定值的镜像。(低版本是-s)
docker search -f stars=10 java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
```docker pull``` : 拉取镜像
* 默认latest
```docker rmi```: 删除镜像
* 默认latest
* 删除单个: ```docker rmi -f hello-world```
* 删除多个: ```docker rmi -f hello-world nginx```
* 删除全部: ```docker rmi -f $(docker images -q)```
### 容器命令
有镜像才能创建容器
#### 新建并启动容器
```docker run [OPTIONS] IMAGE [COMMAND][ARG...]```
常用选项
1. --name: 指定名称
2. -d: 后台运行容器,并返回容器ID,也即**启动守护式容器**
3. **-i: 以交互模式运行容器,通常与-t同时使用**
4. **-t: 为容器重新分配一个伪输入终端,通常与-i同时使用**
5. -P: 随机端口映射
6. -p: 指定端口映射,有以下格式
1. ip:hostPort:containerPort
2. ip::containerPort
3. hostPort:containerPort
4. containerPort
#### 列出所有正在运行的容器
```docker ps [OPTIONS]```
常用选项
* -a: 列出所有正在运行的容器+历史上运行过的
* -l: 显示最近创建的容器
* ~~-n: 显示最近n个创建的容器~~
* -q: 静默模式,只显示容器编号
* --no-trunc: 不截断输出
#### 退出容器
* exit: 容器停止退出
* ctrl + P + Q: 容器不停止退出
#### 启动容器
* ```docker start CONTAINER ID/NAME```
#### 重启容器
* ```docker restart CONTAINER ID/NAME` ``
#### 停止容器
* ```docker stop CONTAINER ID/NAME```
* 强制停止: ```docker kill CONTAINER ID/NAME```
#### 删除已停止容器
* ```docker rm CONTAINER ID```
* 一次性删除多个容器
* ```docker rm -f $(docker ps -a -q)```
* ```docker ps -a -q | xargs docker rm```
#### 守护进程启动
* ```docker run -d CONTAINER NAME```
* 使用```docker ps -a```查看,发现容器已经退出. 是因为**Docker容器后台运行,必须有一个前台进程**.
* 容器运行的命令如果不是那些一直挂起的命令(比如top,tail),都是会自动退出
* 这是docker的机制
* **解决方案: 将要运行的程序用前台进程形式运行**
#### 查看日志
* ```docker logs -f -t --tail CONTAINER ID```
* -t: 加入时间戳
* -f: 跟随最新的日志打印
* --tail 数字: 显示最后多少条
#### 查看容器内运行的进程
```docker top CONTAINER ID```
#### 查看容器内部细节
```docker inspect CONTAINER ID```
#### 与容器以命令行交互
* ```docker exec -it CONTAINER ID bashShell``` (推荐)
* 可以进入容器(bashShell 写 /bin/bash)
* 也可以在外面执行获取结果
* ```docker attach CONTAINER ID```
* 区别:
* attach 是直接进入容器启动命令的终端,不会启动新的进程
* exec 是在容器中打开新的终端,并且可以启动新的进程
#### 从容器内拷贝文件到主机上
* ```docker cp CONTAINER ID:CONTAINER PATH HOSTPATH```
### 总结
[Docker.mmap](../../../Downloads/Docker.mmap)
***
## 镜像
* 镜像是一种轻量级的,可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件.
* UnionFS(联合文件系统)
* 是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加
* 一次同时加载多个文件系统,但从外面看来,只能看到一个文件系统
* docker镜像
* bootfs (boot file system) 主要包含bootloader和kernl.
* bootloader主要是引导加载kernel
* Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs.
* 这一层与典型的Linux系统是一样的,包含boot加载器和内核.当boot加载完成后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs
* rootfs (root file system)
* 在bootfs之上.
* 包含就是Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件.
* rootfs就是各种不同的操作系统发行版,比如Ubuntu, CentOS
* 好处:**共享资源**
### 操作
#### commit
```docker commit```提交容器副本使之成为一个新的镜像
```docker commit -m="描述" -a="作者" 容器ID 要创建的目标镜像名:[标签名]```
***
## 容器数据卷
* 持久化
* 容器之间希望可以共享数据
* docker里面的RDB,AOF
### 介绍
* 卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性
* 设计目的就是数据持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
### 特点
1. 数据卷可用在容器之间共享或重用数据
2. 卷中的更改可以直接生效
3. 数据卷中的更改不会包含在镜像的更新中
4. 数据卷的生命周期一直持续到没有容器使用它为止
### 添加
#### 命令添加
```docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名```
```docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名``` 容器内只读(ro:read only)
#### dockerfile添加
1. 编写
```dockerfile
# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,------success1"
CMD /bin/bash
指定dockerfile 构建
docker build -f /mydocker/DockerFile -t zyq/centos .
运行
docker run -it zyq/centos
数据卷容器
介绍
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器
命令
docker run -t --volumes-from CONTAINER NAME IMAGE
- CONTAINER NAME: 继承自什么容器
- IMAGE: 镜像名
- 子与父之间共享数据卷!
结论
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止
Dockerfile
简介
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本
构建三步骤
- 编写Dockerfile文件
- docker build
- docker run
构建过程解析
基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
执行流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
总结
从应用软件的角度来看,Dockerfile,Docker镜像于Docker容器分别代表软件的三个不同阶段
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器则可以认为是软件的运行态
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石.
Dockerfile涉及的内容包括执行代码或文件,环境变量,依赖包,运行时环境,动态链接库,操作系统的发行版,服务进程和内核进程等等
Dockerfile体系结构
FROM
- 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER
- 镜像维护者的姓名和邮箱地址
RUN
- 容器构建时需要运行的命令
EXPOSE
- 当前容器对外暴露出的端口
WORKDIR
- 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点
ENV
- 用来在构建镜像过程中设置环境变量
ADD
- 将宿主机下的文件拷贝进镜像,且ADD命令会自动处理URL和解压tar压缩包
COPY
- 类似ADD,拷贝文件和目录到镜像中
- 将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
COPY src dest
COPY ["src", "dest"]
VOLUME
- 容器数据卷,用于数据保存和持久化操作
CMD
- 指定一个容器启动时要运行的命令
- Dockerfile中可以有多个CMD指令,但最后只有一个生效,CMD会被
docker run
之后的参数替换
ENTRYPOINT
- 指定一个容器启动时要运行的命令
- ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序和参数
docker run
之后的参数会被当作参数传递给ENTRYPOINT,之后形成新的命令组合
ONBUILD
- 当构建一个被继承的Dockerfile是运行命令,父镜像在被子继承后父镜像的onbuild被触发
案例
自定义镜像centos
目的
- 设置登录后的默认路径
- vim编辑器
- 查看网络配置ifconfig支持
步骤
编写文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14FROM centos
MAINTAINER yiqing<y.zhang@live.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "success------ok"
CMD /bin/bash构建 -f指定dockerfile文件
docker build -t 新镜像名:TAG
docker build -f /mydocker/dockerfile2 -t mycentos:1.3 .
运行
docker run -it mycentos:1.3
自定义tomcat
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29FROM centos
MAINTAINER yiqing<y.zhang@live.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local路径下
COPY c.txt /usr/local/container.txt
#把java与tomcat添加到容器中
ADD jdk-8u281-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-10.0.2.tar.gz /usr/local/
#安装vim
RUN yum -y install vim
#设置访问的落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_281
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.2
ENV CATALINA_BASE /usr/local/apache-tomcat-10.0.2
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
CMD /usr/local/apache-tomcat-10.0.2/bin/startup.sh && tail -F /usr/local/apache-tomcat-10.0.2/bin/logs/catalina.out构建
统一目录下如果名字为Dockerfile,自动去找
docker build -t yiqingtomcat10
运行
1
2
3
4
5docker run -d -p 9080:8080 --name mytomcat10 \
-v /mydockerfile/tomcat/test:/usr/local/apache-tomcat-10.0.2/webapps/test \
-v /mydockerfile/tomcat/tomcat10logs/:/usr/local/apache-tomcat-10.0.2/logs \
--privileged=true \
yiqingtomcat10
安装服务
Mysql
docker pull mysql
运行
1
2
3
4
5
6docker run -p 3306:3306 --name mysql \
-v /mydockerfile/mysql/conf:/etc/mysql/conf.d \
-v /mydockerfile/mysql/logs:/logs \
-v /mydockerfile/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql交互
docker exec -it mysql /bin/bash
登录mysql
mysql -uroot -p
备份mysql
docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p "123456"' > /yiqing/all-databases.sql
Redis
docker pull redis
docker run -p 6379:6379 --name redis \ -v /mydockerfile/redis/data:/data \ -v /mydockerfile/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf \ -d redis redis-server /usr/local/etc/redis/redis.conf \ --appendonly yes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3. 创建redis.conf文件(略)
4. 连接: ```docker exec -it redis redis-cli```
## 上传镜像到阿里云
### 从容器创建一个新的镜像
```docker commit [OPTIONS] CONTAINER ID [REPOSITORY[:TAG]]```
示例: ```docker commit -a yiqing -m "new centos with vim and ifconfig" c8855ee794d3 mycentos:1.4```
### 推送到阿里云
1. 登录阿里云容器镜像服务
2. 创建镜像仓库
3. 推送
```bash
sudo docker login --username=[xxx] registry.cn-shanghai.aliyuncs.com
sudo docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/yiqing/personal:[镜像版本号]
sudo docker push registry.cn-shanghai.aliyuncs.com/yiqing/personal:[镜像版本号]