1. docker简介
学习一门技能或新的技术,我认为至少要明白三件事:
- 这个东西是什么?
- 为什么会出现,能够为我们解决什么问题?
- 我们如何使用它?
至于为什么会出现,大家可以自行百度或查阅官方文档,很多大牛们都有介绍,比我解释的更好,在此就不多做啰嗦,本着实践的原则,本文中只描述docker的出现为我们解决了什么问题,以及我们怎么样使用它。
在2000年左右入行运维的同学大多数应该遇到过这么一个问题:
同一套代码,开发环境、测试环境反复测试都没有问题,一上线就出现各种各样的问题。对于这类问题之前也做过总结,无非就是配置问题或环境问题,开发、测试、生产环境不一致,导致每次代码发布一堆人熬夜到很晚才能完成,效率根本谈不上。
docker的出现为我们很好的解决了上述问题,所以得以被国内外的同行们认可,能够快速的发展,它能将代码连同运行环境,打包成一个镜像,同一个镜像可以在开发、测试、生产等各个环境进行部署。
同时,可以做到不同的容器之间相互隔离,对于每个容器用到的资源也可以进行限制。
当然,要实现这种部署方式,还离不开代码与配置分离、无状态化改造等等一系列的工作作为前提。但是好就好在这些都是一次性的工作,在后续的文章中,我也会有相关的文章分享出来。
2. docker基础操作
本文主要描述在CentOS7.8操作系统上面安装和配置docker,其他Linux发行版与之类似,因篇幅有限,不区分环境介绍。如在安装配置过程中遇到问题,可留言或加入博客中公布的QQ群进行交流。
2.1. docker安装
2.1.1 配置网卡转发
# 若未配置,需要执行如下
cat <<EOF > /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
EOF
sysctl -p /etc/sysctl.d/docker.conf
# 如果出现如下报错:
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory
# 解决,先执行命令:
modprobe br_netfilter
# 然后再次执行如下命令即可
sysctl -p /etc/sysctl.d/docker.conf
2.1.2 yum安装docker
# 1)下载阿里源repo文件
curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel-aliyun.repo http://mirrors.aliyun.com/repo/epel-aliyun.repo
curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum clean all && yum makecache fast
# 2)查看源中可用版本
yum list docker-ce --showduplicates | sort -r
# 3)yum安装指定版本docker
yum install docker-ce-20.10.8 -y
## 安装旧版本:# yum install -y docker-ce-18.09.9
## 安装最新版:# yum install docker-ce
# 4)配置源加速(阿里云:容器镜像服务 - 镜像加速)
# 或直接访问如下连接,输入帐号密码即可获取自己的镜像加速地址
## https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://7ro8ynda.mirror.aliyuncs.com"
]
}
# 5)设置开机自启
systemctl enable docker
systemctl daemon-reload
# 6)启动docker
systemctl start docker
# 7)查看docker信息
docker info
ps -ef |grep docker
systemctl status docker
# containerd
ps -ef |grep containerd
systemctl status containerd
2.2 docker 常用操作
2.2.1 docker核心要素
docker有三大核心要素:仓库、镜像、容器,三者之间的关系如下图所示:
- 镜像:包含了代码及其运行环境的包,类似于操作系统的ISO文件,是静态文件;
- 容器:镜像运行后即是容器,可以对外提供服务;
- 仓库:存储镜像的地方,类似于yum仓库,包括共有仓库如DockerHub和国内的阿里、网易等;私有仓库,如我们自己搭建的,可以搭建私有仓库的开源软件有官方推荐的Registry和比较著名的Harbor等。
镜像是容器和仓库的桥梁,容器与仓库没有直接关系,他们是通过镜像建立联系的。
我们要运行一个容器,就要从仓库中拉取对应的镜像,然后run起来,就成了可对外提供服务的容器。
2.2.2. 镜像常用操作
# 查看镜像列表
docker images
# 或者
docker image ls
# 获取镜像(两个途径:从共有仓库获取,从私有仓库获取,默认从dockerHub仓库获取镜像
docker pull nginx:alpine
# 完整的写法是:
docker pull docker.io/library/nginx:alpine
# 为镜像打标签
docker tag nginx:alpine localhost:5000/nginx:alpine
# 说明:localhost:5000是我用官方推荐的Registry搭建的私有仓库
docker push localhost:5000/nginx:alpine
# 这样我们就可以将这个镜像推送到我们的私有仓库localhost:5000中
# 查看私有仓库中的镜像
curl -X GET http://localhost:5000/v2/_catalog
{"repositories":["nginx"]}
curl -X GET http://localhost:5000/v2/nginx/tags/list
{"name":"nginx","tags":["alpine"]}
# 根据Dockerfile构建一个自己的镜像(先预览一下,后面详细说明)
docker build . -t my-nginx:ubuntu -f Dockerfile
# 将镜像保存到本地
docker save -o nginx-alpine.tar nginx:alpine
# 删除本地镜像
docker rmi nginx:alpine
# 加载本地镜像
docker load -i nginx-alpine.tar
# 查询镜像被哪些镜像引用
docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=镜像id)
# 删除所有没有用到的镜像
docker image prune -a # docker版本最小为1.25
2.2.3. 容器常用操作
# 通过镜像启动容器(启动容器放后台运行)
docker run --name my-nginx -d nginx:alpine
# 查看容器列表
docker ps
docker ps -a # 包含已经退出的容器
# 进入一个已经启动的容器内部
docker exec -ti my-nginx2 /bin/sh
# 启动并进入容器(退出后,容器也退出状态)
docker run -ti --name my-nginx3 nginx:alpine /bin/sh
# 启动并进入容器,并且在退出容器后自动删除(测试某项功能的时候经常用到)
docker run -ti --rm nginx:alpine /bin/sh
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps
# 停止一个容器(此时容器为Exited状态)
docker stop my-nginx
# 启动一个停止的容器
docker start my-nginx
# 删除一个退出Exited状态的容器(正在运行的容器这种方式是删不掉的)
docker rm my-nginx
# 强制删除一个正在运行的容器
docker rm -f my-nginx-alpine
# 将容器内的端口映射到宿主机提供服务 -p <host_port>:<container_port>
docker run --name nginx -d -p 8080:80 nginx:alpine
# 资源限制,最大可用内存500M
docker run --memory=500m nginx:alpine
# 容器数据持久化 - 挂载主机目录
docker run --name nginx -d -v /opt:/opt nginx:alpine
docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d -v /opt/mysql/:/var/lib/mysql mysql:5.7
# 容器与宿主机之间数据拷贝
docker cp /tmp/test.txt nginx:/tmp
# 容器拷贝到主机
docker cp nginx:/tmp/test.txt ./
# 查看容器日志
docker logs my-nginx
docker logs -f my-nginx
docker logs --tail=100 -f my-nginx
# 不进入容器执行命令查看容器内信息
$ docker exec my-nginx ps aux
# 容器的详细信息查看
docker inspect my-nginx
# 镜像的详细信息查看
docker inspect nginx:alpine
# docker运行容器测试,退出后删除容器(不是删除镜像),在日常工作中测试镜像经常用到
docker run -it --rm ubuntu:14.04 bash
########## 容器批量操作 - 慎用 #########
# 停止所有容器
docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker stop
# 删除所有容器
docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker rm
# 删除所有none容器
docker images|grep none|awk '{print $3 }'|xargs docker rmi
# 运行容器常用参数说明
# -itd:在容器中打开一个伪终端进行交互操作,并在后台运行;
# -v:把宿主机的/data/registry目录绑定 到 容器/var/lib/registry目录(这个目录是registry容器中存放镜像文件的目录),来实现数据的持久化;
# -p:映射端口;访问宿主机的5000端口就访问到registry容器的服务了;
# --restart=always:这是重启的策略,假如这个容器异常退出会自动重启容器;
# --name registry:创建容器命名为registry,你可以随便命名;
# registry:latest:这个是刚才pull下来的镜像;
2.2.4 docker常用管理命令
# 查看docker挂载目录volume
docker inspect --format "{{.Config.Volumes}}" 676b04bec7c5
# 查看Docker 磁盘使用情况
docker system df
# 清理磁盘
docker system prune
# 迁移数据目录
rsync -avz /var/lib/docker /opt/data/docker
# 配置mapper文件,根据docker服务的安装配置文件进行修改
vim /usr/lib/systemd/system/dokcer.service
# 在ExectStart=xxx 中添加属性
ExectStart=xxx --graph /opt/data/docker
# 利用Registry搭建本地docker仓库
docker run -d -p 5000:5000 --restart always --name registry registry:2
# 将本地仓库加入docker配置文件daemon.json中
cat /etc/docker/daemon.json
{
"graph": "/data/docker",
"registry-mirrors": ["https://7ro8ynda.mirror.aliyuncs.com"],
"insecure-registries": ["10.168.215.55:5000"],
}
# 重启docker服务
systemctl restart docker
2.2.5 docker常用选项说明
# 常用选项说明
-d, --detach=false, 指定容器运行于前台还是后台,默认为false
-i, --interactive=false, 打开STDIN,用于控制台交互
-t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false
-u, --user="", 指定容器的用户
-a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
-w, --workdir="", 指定容器的工作目录
-c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
-e, --env=[], 指定环境变量,容器中可以使用该环境变量
-m, --memory="", 指定容器的内存上限
-P, --publish-all=false, 指定容器暴露的端口
-p, --publish=[], 指定容器暴露的端口
-h, --hostname="", 指定容器的主机名
-v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
--volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
--cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
--cidfile="", 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
--cpuset="", 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
--device=[], 添加主机设备给容器,相当于设备直通
--dns=[], 指定容器的dns服务器
--dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
--entrypoint="", 覆盖image的入口点
--env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
--expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
--link=[], 指定容器间的关联,使用其他容器的IP、env等信息
--lxc-conf=[], 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
--name="", 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
--net="bridge", 容器网络设置:
bridge 使用docker daemon指定的网桥
host //容器使用主机的网络
container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
none 容器使用自己的网络(类似--net=bridge),但是不进行配置
--privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
--restart="no", 指定容器停止后的重启策略:
no:容器退出时不重启
on-failure:容器故障退出(返回值非零)时重启
always:容器退出时总是重启
--rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
--sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
2.2.6 介绍一个界面管理docker工具portainer
我们运行docker后,会默认在/var/run下面有个docker.sock,这个工具就是根据这个sock文件来访问和管理本地的docker,使用方法如下:
docker run --name portainer -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
然后访问 ip:9000
后面的文章会介绍Dockerfile的使用,如何制作一个自己的镜像?敬请关注。