Docker简介
为什么有Docker
一款产 品从开发到上线,从操作系统,到运行环境,再到应用配置。作为开发+运维之间的协作我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,特别是各种版本的迭代之后,不同版本环境的兼容,对运维人员都是考验
环境配置如此麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境-模-样地复制过来。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。
Docker是什么
Docker是基于Go语言实现的云开源项目。通过对应用组件的封装、分发、部署、运行等生命期的管理,使用户的APP (可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
Linux容器技术的出现就解决了这样一 一个问题,而Docker就是在它的基础上发展过来的。将应用运行在Docker容器上面,而Docker容器在任何操作系统上都是一-致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作
Docker好处
解决了 运行环境 和 配置问题 的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术
容器与虚拟机的比较
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程
而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便
每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源
Docker三要素
镜像、仓库、容器
镜像就是模板,容器就是镜像的一个实例,docker利用容器独立运行一个或一组应用,可以把容器看作是一个简易版的Linux环境和运行在其中的应用程序,仓库是集中存放镜像的地方。
Docker运行流程
https://baijiahao.baidu.com/s?id=1697352130792897690&wfr=spider&for=pc
-
用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
-
Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
-
Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
-
Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graphdriver 将下载镜像以 Graph 的形式存储。
-
当需要为 Docker 创建网络环境时,通过网络管理驱动 Networkdriver 创建并配置 Docker容器网络环境。
-
当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
-
Libcontainer 是一项独立的容器管理包,Networkdriver 以及 Execdriver 都是通过 Libcontainer 来实现具体对容器进行的操作。
Docker安装
1.系统
确定Linux系统是Centos7及以上版本
cat /etc/redhat-release
2.卸载
如果之前安装过旧版本的Docker,可以使用下面命令卸载:
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine \
docker-ce
3.yum安装gcc相关
基础构建包
Centos7能上外网
yum -y install gcc
yum -y install gcc-c++
4.安装需要的软件包
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2 --skip-broken
5.设置stable镜像仓库
# 设置docker镜像源
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
6.更新yum软件包索引
速度会快些
yum makecache fast
7.安装docker ce
docker-ce为社区免费版本
yum install -y docker-ce
8.启动docker
先关防火墙
# 关闭
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
#查看是否关闭防火墙
systemctl status firewalld
启动docker
systemctl start docker # 启动docker服务
systemctl enable docker # 设置开启自启动
查看docker版本
docker -v
9.配置镜像加速
docker官方镜像仓库网速较差,我们需要设置国内镜像服务
##创建文件夹
sudo mkdir -p /etc/docker
> ##在文件夹内新建一个daemon.json文件
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://akchsmlh.mirror.aliyuncs.com"]
}
EOF
##重新加载文件
sudo systemctl daemon-reload
##重启docker
sudo systemctl restart docker
Docker常用命令
帮助启动类命令
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开启启动: systemctl enable docker
查看docker概要信息: docker info
查看docker总体帮助文档 docker --help
查看docker命令帮助文档 docker 具体命令 --help
镜像命令
docker images
列出本地主机上的镜像
-a : 列出本地所有的镜像(含历史印象层)
-q: 只显示镜像ID
docker search 镜像名称
查看远程仓库( https://hub.docker.com)上的镜像
--limit: 只列出N个镜像,默认25个 (docker search --limit 5 redis)
docker pull 镜像名称
下载镜像
docker pull 镜像名字[:TAG]
docker pull 镜像名字
没有TAG默认就是最新版 等价于 docker pull 镜像名字:latest
docker system df
查看镜像/容器/数据卷所占的空间
docker rmi 镜像id
删除镜像
删除单个: docker rmi -f 镜像ID
删除多个: docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部: docker rmi -f $(docker images -qa)
虚悬镜像
仓库名、标签都是<none>
的镜像,俗称虚悬镜像dangling iamge
容器命令
docker run [options] IMAGE [COMMAND] [ARG…]
新建+启动容器
OPTIONS说明(常用): 有些是一个减号,有些是两个
--name="容器名字" 为容器指定一个名称
-d 后台运行容器并返回容器ID,也即 启动守护式容器(后台运行)
-i 以交互模式运行容器,通常与 -t 同时使用:
-t 为容器重新分配一个伪输入终端,通常与 -i 同时使用: 也即 启动交互式容器(前台有伪终端,等待交互)
-P 随机端口映射: 大写P
-p 指定端口映射: 小写p
#使用镜像centos:latest以交互模式启动一个容器,在容器内执行 /bin/bash命令
docker run -it centos /bin/bash
#参数说明
-i: 交互式操作
-t: 终端
centos: centos镜像
/bin/bash: 放在镜像名后的是命令,这里我们希望有个交互式shell,因此用的是/bin/bash
要退出终端,直接输入exit
docker ps
查看运行中的容器
OPTIONS说明(常用):
-a: 列出当前所有正在运行的容器+历史上运行过的
-l: 显示最近创建的容器
-n: 显示最近n个创建的容器
-q: 静默模式,只显示容器编号
#其他命令
#退出容器
1. exit: run进去容器,exit退出,容器停止
2. ctrl+p+q: run进去容器,ctrl+p+q退出,容器不停止
#启动已经停止的容器
docker start 容器ID或者容器名
# 停止容器
docker stop 容器ID或者容器名
# 重启容器
docker restart 容器ID或者容器名
# 强制停止容器
docker kill 容器ID或者容器名
# 删除已经停止的容器
docker rm 容器ID
# 一次性删除多个容器实列
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm
重要
# 启动守护式容器(后台服务器)
在大部分的场景下,我们希望docker的服务是在后台运行的,通过-d指定容器的后台运行模式
docker run -d 容器名
redis前后台启动演示:
前台交互式启动
docker run -it redis:6.0.8
后台守护式启动
docker run -d redis:6.0.7
# 查看容器日志
docker logs 容器ID或者容器名
OPTIONS说明:
-f : 跟踪日志输出
--since :显示某个开始时间的所有日志
-t : 显示时间戳
--tail :仅列出最新N条容器日志
列:
docker logs -f mynginx: 跟踪查看容器mynginx的日志输出。
docker logs --since="2016-07-01" --tail=10 mynginx: 查看容器mynginx从2016年7月1日后的最新10条日志。
# 查看容器内运行的进程
docker top 容器ID或者容器名
# 查看容器内部细节
docker inspect 容器ID或者容器名
# 进入正在运行的容器并命令行交互
1. docker exit -it 容器ID或者容器名 /bin/bash
2. 重新进入docker attach 容器ID
区别:
attach直接进入容器启动命令的终端,不会启动行的进程,用exit退出,会导致容器停止
exec是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止
通常使用 dockerexec命令
# 从容器内拷贝文件到主机上
容器 -》 主机
docker cp 容器ID:容器内路径 目的主机路径
列:
docker cp /www/runoob 96f7f14e99ab:/www/ 将主机/www/runoob目录拷贝到容器96f7f14e99ab的/www目录下。
docker cp /www/runoob 96f7f14e99ab:/www 将主机/www/runoob目录拷贝到容器96f7f14e99ab中,目录重命名为www。
docker cp 96f7f14e99ab:/www /tmp/ 将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中。
# 导入和导出容器
export 导出容器的内容流作为一个tar归档文件【对应import命令】
import 从tar包中的内容创建一个新的文件系统再导入为镜像【对应export】
列:
docker export 容器ID或者容器名 > 名字.tar 将容器打包成一个tar包
cat 文件名.tar | docker import 镜像用户/镜像名:镜像版本号 (镜像用户/镜像名:镜像版本号 都是自己定义的,入 tzh/tzh_image:1.1)
列:
docker export 02135 > myubuntu.tar
docker import myubuntu.tar runoob/ubuntu:v4
docker commit :从容器创建一个新的镜像。
OPTIONS说明:
-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;
-p :在commit时,将容器暂停。
列:
docker commit -m "my apache" 容器名称或id 打包的镜像名称:标签
docker commit -m "接口测试" 5d6696effe78 django_api:v1
上述两种方法从容器变成镜像后,通过docker run 命令再生产一个新的容器
docker run -it 镜像名称 /bin/bash
Docker镜像
原理
镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包含代码、运行时所需的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
分层的镜像
以pull为列,在下载的过程中我们可以看到docker的镜像好像是一层一层的在下载
UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,Union文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作具体的应用镜像
特性: 一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际是由一层一层的文件系统组成,这种层级的文件系统叫UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docekr镜像的最底层就是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核,当boot加载完之后整个内核就都在内存中,此时内存的使用权已由bootf转交给内核,此时系统也会卸载bootfs
rootfs(root file system),在bootfs之上,包含的就是典型Linux系统中的 /dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
对于一精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要对外提供rootfs就行了,由此可见
为什么采用分层
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需在磁盘保存一份base镜像:同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的:
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作为“容器层”, “容器层”之下通常叫镜像层。
镜像库
共有
Docker Hub
私有
阿里云
Docker Hub
本地搭建
# 本地搭建镜像库
#1. 下载镜像Docker Registry
docker pull registry
# 运行私有库Registry,相当于本地有个私有Docker Hub
docker run -d -p 5000:5000 -v /data/myRegistry/:/tmp/registry --privileged=true registry
# 案例演示创建一个新的镜像,ubuntu安装ifconfig命令
docker commit -m "我的私服库" -a "tan" ba1b60 wdbuuntu:1.1
docker run -it 6f623c828f0e /bin/bash
# curl验证私服库上有什么镜像(/v2/_catalog是默认的)
curl -XGET http://10.0.90.190:5000/v2/_catalog
# 将新镜像修改成符合规范私服规范的Tag
docker tag wdbuuntu:1.1 10.0.90.190:5000/wdbuuntu:1.1
# 修改配置文件使之支持http
# docker默认不允许http方式推送镜像,通过配置选项来取消这个限制,如果不生效,重启docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://zfzbet67.mirror.aliyuncs.com"],
"insecure-registries" ["10.0.90.190:5000"]
}
# push推送到私服库
docker push 10.0.90.190:5000/wdbuuntu:1.1
# curl验证私服库上有什么镜像
curl -XGET http://10.0.90.190:5000/v2/_catalog
# 从私服库上拉
docker pull 10.0.90.190:5000/wdbuuntu:1.1
Docker容器数据卷
容器卷
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能绕过Union File System提供的一些用于持续存储或共享数据的特性
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会再容器删除时删除其挂载的数据卷
目的
将运用于运行的环境打包镜像,run后形成容器实列,但是我们对数据的要求希望是持久化的
Docker容器产生的数据,如果不备份,那么当容器实列删除后,容器内的数据自然也就没有了
为了能保存数据在docker中我们使用卷
特点
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接实时生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
–privileged=true
Docker挂载主机目录访问 如果出现 cannot open directory: Permission denied
解决办法: 在挂载目录后面多加一个 --privileged=true即可
容器实列
宿主机vs容器之间添加容器卷
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
# 查看数据卷是否挂载成功: Mounts中会显示挂载的信息
docker inspect 容器ID或者容器名
# 容器和宿主机之间数据共享
docker修改,主机同步获得
主机修改,docker同步获得
docker容器stop,主机修改,docker容器重启 数据同步
读写规则映射添加说明
# 读写(默认)
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
# 只读
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
卷的继承和共享
# 容器1完成和宿主机的映射
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
# 容器2继承容器1的卷规则
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu /bin/bash
Docker简单安装
mysql
简单安装
问题1: 中文乱码
问题2: 没有挂载数据卷,删了容器数据就没了
# 拉取镜像
docker pull mysql:5.7
# 创建容器
docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 进入容器
docker exec -it a01c07f24eee /bin/bash
# 进入mysql 输入前面设置的密码
mysql -u root -p
# 可以执行一系列操作
create database db1;
use db1;
create table mytable(id int, name varchar(20));
insert into mytable values(1,'docker');
select * from mytable;
实战安装
# 创建容器
docker run -d -p 3306:3306 --privileged=true -v /data/docker/mysql/conf:/etc/mysql/conf.d -v /data/docker/mysql/logs:/var/log/mysql -v /data/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
# 新建my.cnf, 通过容器卷同步给mysql容器实例
cd /data/docker/mysql/conf
vi my.cnf
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
# 重启mysql容器实例
docker restart mysql
或
docker stop mysql
docker start mysql
# 重新进入并查看字符编码
docker exec -it mysql /bin/bash
# 进入mysql 输入前面设置的密码
mysql -u root -p
# 可以执行一系列操作: 可以去Navicat上执行
create database db1;
use db1;
create table mytable(id int, name varchar(20));
insert into mytable values(1,'我的docker');
select * from mytable;
# 验证是否修改了数据集编码(看到大部分是utf8编码的就说明已经改了)
SHOW VARIABLES LIKE 'character%';
redis
# 拉取镜像
docker pull redis:6.0.8
# 在本地建立一个目录/data/docker/redis用于存放redis数据
mkdir -p /data/docker/redis
# 将redis.conf文件模板拷贝进 /data/docker/mysql目录下
去网上拉一个配置,百度搜: redis 6.0.8 conf配置文件
# /data/docker/mysql目录下修改redis.conf文件
开启redis验证(可选)
requirepass 密码
运行redis外部连接(必须)
注释掉# bind 127.0.0.1
将daemonize yes注释掉或者改成no, 改配置跟docker run中的-d参数冲突,会导致容器启动失败
daemonize no
开启redis数据持久化(可选)
appendonly yes
# 创建容器(不用/bin/bash的原因而用现在这个启动方式可以通过启动和停止容器来操作数据库)
docker run -p 6379:6379 --name redis --privileged=true -v /data/docker/redis/redis.conf:/etc/redis/redis.conf -v /data/docker/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
# 证明docker启动使用了指定的配置文件
可通过修改redis的配置文件中的密码来查看
Docker复杂安装
mysql主从复制
# 搭建步骤
# 1. 新建主服务器容器实列3307
docker run -d -p 3307:3306 --name mysql-master --privileged=true -v /data/docker/mysql-master/conf:/etc/mysql/conf.d -v /data/docker/mysql-master/logs:/var/log/mysql -v /data/docker/mysql-master/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 2. 进入/data/docker/mysql-master/conf目录下新建my.cnf
[mysqld]
## 设置server_id, 同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间,默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如: 1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
# 3. 修改完配置后重启master实例
docker restart mysql-master
# 4. 进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -u root -p
# 5. master容器实列内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';
# 6. 新建从服务器容器实列3308
docker run -d -p 3308:3306 --name mysql-slave --privileged=true -v /data/docker/mysql-slave/conf:/etc/mysql/conf.d -v /data/docker/mysql-slave/logs:/var/log/mysql -v /data/docker/mysql-slave/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 7. 进入/data/docker/mysql-slave/conf目录下新建my.cnf
[mysqld]
## 设置server_id, 同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备Slave作为其它数据库实列的master时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间,默认值为0,表示不自动清理
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如: 1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示将复制事件写入自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
# 8. 修改完配置后重启slave实列
docker restart mysql-slave
# 9. 在主数据库中查看主从同步状态(11步会用到这里的值)
show master status;
# 10.进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -u root -p
# 11.从数据库中配置主从复制
change master to master_host='10.0.90.191', master_user='slave', master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001', master_log_pos=617,master_connect_retry=30;
参数说明:
master_host: 主数据库的IP地址
master_port: 主数据库的运行端口
master_user: 在数据库创建的用于同步数据的用户账号
master_password: 在数据库场景用于同步数据的用户密码
master_log_file: 指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取file参数
master_log_pos: 指定从数据库从哪个位置复制数据,通过查看主数据的状态,获取Position参数
master_connect_retry: 连接失败重试的时间间隔,单位为秒
# 12.从数据库中查看主从同步状态
show slave status \G;
查看:(No说明没同步)
Slave_IO_Running: No
Slave_SQL_Running: No
# 13.从数据库中开启主从同步
start slave;
show slave status \G;
得到:(说明链路打通)
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
# 14.查看从数据库状态发现并已经同步
主机新建库-使用库-新建表-插入数据
从机使用库,查看记录
# 15.主从复制测试
Dockerfile
简介
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本
构建过程解析
# Dockerfile内容基础知识
1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2. 指令按照从上到下,顺序执行
3. #标识注释
4. 每条指令都会创建一个新的镜像层并对镜像镜像提交
# Docker执行Dockerfile的大致流程
1. docker从基础镜像运行一个容器
2. 执行一条指令并对容器做出修改
3. 执行类似docker commit的操作提交一个新的镜像层
4. docker再基于刚提交的镜像运行一个新容器
5. 执行dockerfile的下一条指令直到所有指令都执行完成
# Docker bulid
docker build -t journal-img /root/data/dockerImage/journalDocker/
docker run -d -p 8080:8090 --name journal journal-img
常用保留字指令
FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
MAINTAINER
镜像维护者的姓名和邮箱地址
RUN
容器构建时需要运行的命令
两种格式
shell格式: RUN pip install requests
exec格式: RUN ["可执行文件", '参数1', '参数2']
RUN是在docker build时运行
EXPOSE
当前容器对外暴露出的端口
WORKDIR
指定容器创建后,终端默认登录的进来工作目录,一个落脚点
USER
指定改镜像以什么样的用户去执行,如果都不指定,默认是root
ENV
用来在构建镜像过程中设置环境变量
ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY
类似ADD,拷贝文件和目录到镜像中
将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
COPY src dest
COPY ["src", "dest"]
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先创建好
VOLUME
容器数据卷,用于数据保存和持久化工作
CMD
指定容器启动后要干的事情
Dockerfile可以有多个CMD命令,但只有最后一个生效,CMD会被docker run之后的参数替换
注意
CMD实在docker run时运行,RUN是在docker build时运行
ENTRYPOINT
用来指定一个容器启动时要运行的命令
类似CMD命令,但是ENTRYPOINT不会被docker run后面的命令覆盖
而且这些命令行参数会被当做参数送给ENTRYPOINT指令指定的程序
列:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
就会变成 nginx -c /etc/nginx/nginx.conf
ENTRYPOINT 和 CMD 联合使用
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,
而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令
换句话说实际执行时,会变成: <ENTRYPOINT> "<CMD>"
灵魂拷问
那么有了 CMD 后,为什么还要有 ENTRYPOINT 呢?这种 <ENTRYPOINT> "<CMD>" 有什么好处么?
CMD 和 ENTRYPOINT 区别
CMD # 指定这个容器启动的时候要运行的命令,不可以追加命令
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
案列
# 案列1: 安装一个python环境并且执行python脚本
# 基于的基础镜像
FROM python:3.6.5
# 维护者信息
MAINTAINER hello hello@163.con
# 代码添加到code文件夹
ADD ./ /code/Serpapi
# 设置code文件夹是工作目录
WORKDIR /code/Serpapi
# 安装支持
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
RUN pip install -r requirements.txt
CMD ["python", "/code/Serpapi/crawle_server.py"]
# 案列2: 安装一个python环境,跑一个Flask程序
FROM python:3.6.5
MAINTAINER hello hello@163.con
# 代码添加到code文件夹
ADD ./ /code/VerifyDoi
WORKDIR /code/VerifyDoi
# 安装支持
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
EXPOSE 5000
#关闭防火墙
#RUN systemctl stop firewalld.service
#RUN systemctl disable firewalld.service
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install uwsgi
#CMD ["python", "/code/VerifyDoi/run.py"]
#CMD nohup python -u /code/VerifyDoi/run.py > nohup.log 2>&1 &
CMD uwsgi --ini /code/VerifyDoi/verify_doi_uwsgi.ini
Docker网络
是什么
Dokcer服务器会默认创建一个docker0网桥(其上有一个docker0内部接口),改桥接完了过的名称为docker0,它在内核层联通了其他的物理或者虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络,Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信
docker不启动,默认网络情况
ens33
lo
virbr0
docker启动后,网络情况(docker0:虚拟网桥)
查看docker网络模式命令
命令: docker network ls
默认创建三大网络模式
[root@slave1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
67a21682299c bridge bridge local
c0c8cf2b233b host host local
935ca5b5197f none null local
常用基本命令
# 查看网络
docker network ls
# 查看网络源数据
docker network inspect xxx网络名字
# 删除网络
docker network rm xxx网络名字
# 创建网络: 名字为mynetwork
docker network create mynetwork
能干嘛
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
网络模式
总体介绍
# 网络模式
1. bridge (使用 --network bridge指定,默认使用docker0)
为每一个容器分配、设置IP等,并将容器连接到一个docker0的虚拟网桥,默认为改模式
2. host(使用--network host指定)
容器将不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口
3. none(使用--network none指定)
容器有独立的network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等
4. container(使用--network container: NAME或者容器ID指定)
新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP、端口范围
容器实例内默认网络IP生产规则
容器底层网络会发生改变,IP会随着容器的删除新增会变
案列说明
bridge
# 网桥docker0创建一对对等虚拟社保接口,一个叫veth,另一个叫eth0,成对匹配
# 1. 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
# 2. 每个容器实列内部也有一块网卡,每个接口叫eth0
# 3. docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一配对
# 综上所述: 将宿主机上的所有容器都链接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的IP,此时两个容器的网络是互通的
host
# 直接使用宿主机的IP地址与外界进行通信,不在需要而外进行NAT转换
容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespce,容器将不会虚拟出自己的网卡,而是使用宿主机的IP和端口
启动容器时,如果有-p 指定端口映射的话,会出现警告
原因:
docker启动时指定 --network=host或者-net=host,如果还指定了-p映射端口,那这个时候就会出现警告,并通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复则递增
解决:
解决的办法就是使用docker的其他完了过模式,列如--network=bridge,这样就可以解决问题,或者直接无视
none
# 禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
在none模式下,并不为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡、配置IP等
container
# 新建的容器和已经存在的一个容器共享一个网络IP配置,而不是和宿主机共享
# 新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等,同样,两个容器除了网络方面,比如文件系统、进程列表等还是隔离的。
自定义网络
Docker-compose容器编排
是什么
# Docker-Compose是Docker官方的开源项目,负责实现对docker容器集群的快速编排
Compose是Docker公司推出的一个工具软件,可以管理多个Docker容器组成一个应用,你需要定义一个YAML格式的配置文件docker-compose.yml,写好多个容器之间的调用关系,然后,只需要一个命令,就能同时启动/关闭这些容器
能干嘛
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源很少,所以最好是将每个服务单独的分隔开来,但是这样又面临一个问题
如果我们需要同时部署好多个服务,难道每个服务都要单独写Dockerfile然后再构建镜像、构建容器?这样会很麻烦,所以docker官方给我们提供了docker-compose多服务部署的工具
列如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要加上后端的数据库mysql、redis、队列这些
Compose运行用户通过一个单独的docker-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)
可以很容易的用一个配置文件定义一个多容器的应用,然后使用一条指令按照这个应用的所有依赖,完成构建,Docker-Compose解决了容器与容器之间如何管理编排的问题
Compose核心概念
# 一文件,两要素
docker-compose.yml
服务、工程
# 服务
一个个应用容器实例,比如订单微服务、库存微服务、mysql容器等等
# 工程
由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义
Compose使用的三个步骤
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用docker-compose.yml定义一个完整业务单元,安排好整体应用中的各个容器服务
最后执行docker-compose up命令来启动并运行整个应用程序,完成一键部署上线