文章目录
一、Docker简介
1. 什么是Docker?
docker的官网是https://www.docker.com/
Docker官网有这么一句话,这句话很好的说明了Docker技术的目的与优势,即让开发者更多的关注应用程序,更少的关心运行环境差异,并且缩短代码从开发、测试、发布的周期,让应用程序具备可移植性,易于构建,并易于协作。
Docker是一个应用容器引擎 ,基于Go 语言并遵从 Apache2.0 协议开源。
2. 什么是容器
既然Docker是一个应用容器引擎,那么什么又是容器呢?
考虑一下你有没有碰到这种问题,明明在自己电脑上运行好好的程序,部署到测试环境发现运行出问题了。
测试:你的代码有bug
开发:怎么可能,我自己测试过,好好的,你环境有问题吧?你会用吗?
你花了半个小时,发现是测试环境上有个参数没有配置,然后你解决了这个问题,测试小姐姐夸了你一番,但是确打乱了你的思路,本来打算下班之前搞定的一个需求,就只能下班之后加班或者拖到第二天了。
一个可用软件的交付过程,包含两个部分,开发和维护,不幸的是,我们很难保证软件开发、测试和运行阶段的软件能够在一模一样的环境下运行,很多时候我们不得不花大量的时间去配置环境和教别人配置环境。
并且,当服务器从单机扩展到分布式集群模式,或者我们在交付软件时,需要重新给客户搭建一套独立的环境时,想象一下需要再每台服务器上都进行配置,这多么让人头大啊。
容器: 简单的来说,一个容器包含了程序运行的时的完整环境,除了应用程序本身外,这个程序全部的依赖、配置等都被统一打包到了一起。
大部分容器实现技术基于开发标准,可以运行在所有主流的Linux发行版、windows等操作系统中。通过容器化技术,操作系统发行版本和其他基础环境造成的差异,都被抽象掉了。
那如果这样的话,容器岂不是跟虚拟机是一样的了?
其实docker与虚拟机是类似的东西,虚拟机是在物理硬件上虚拟运行一台或多台独立虚拟机器。我们拿这个虚拟机就可以在安装了虚拟机软件的其他电脑上直接运行,里面的东西就不用我们来回安装和配置了。
虚拟机是运行在物理硬件之上,而容器则是直接运行在操作系统内核之上的用户空间,因此容器虚拟化也被称为操作系统虚拟化,容器技术可以让多个独立的用户空间运行在同一台宿主机上。
如果用一张图来说明的话,应该是这样的:
与传统的虚拟技术相比,容器运行时使用的是操作系统的系统调用接口,而不需要模拟层和管理层。这也降低了运行单个容器所需的开销,使得宿主机中运行更多的容器。由于虚拟机在启动时会通过管理层(hypervisor layer)给虚拟机分配物理资源(CPU、磁盘、网络、内存等),而容器共享宿主机操作系统内核,所以更加轻量化、启动速度更快。
尽管容器化的思想有着光辉的历史,但容器技术复杂性导致容器并没有得到广泛的认可,容器本身比较复杂、不易安装、管理和自动化也很困难。而Docker就是为了改变这一切而生的。
docker本身并不是容器,而是创建和管理容器的工具。
3. docker的组件
Docker核心组件包括:
Docker引擎
Docker镜像
Docker容器
Registry(镜像仓库)
二、Docker安装与Docker管理命令
Docker支持很多的系统,由于系统众多,本文仅以centos7.6安装进行示例。
更多的方法可以参考链接:https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.15d51991WpnOIc
1. 安装Docker的先决条件
- 运行64位CPU架构的计算机
- 运行Linux3.8以上的内核版本
- 内核必须支持一种适合的存储驱动
- 内核必须支持并开启cgroup和命名空间(namespace)
2.Centos 7 安装Docker
# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 libseccomp libseccomp-devel
# Step 2: 添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装 Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 开启Docker服务
sudo service docker start
安装完成后可以运行docker version 检查是否安装成功
3、常用的docker容器管理命令
这一部分,我们将按照: 查找> 下载> 运行> 停止> 删除,这个步骤去运行一个实际的nginx容器
1)docker状态管理
systemctl enable docker #开机自启动docker
systemctl start docker #启动docker
systemctl status docker #查看docker状态
systemctl stop docker #停止docker
systemctl restart docker #重启docker
2)下载nginx镜像
docker search nginx #查找nginx镜像
其中OFFICIAL列表示是否为官方镜像文件
docker pull nginx #下载nginx镜像
下载镜像完成后会有打印Status: Downloaded newer image for docker.io/nginx:latest
docker pull 命令可以携带版本号,如docker pull nginx:5.0,不带版本号时,默认表示拉取最新版本 docker pull nginx:latest
docker images #查看有哪些镜像
3)启动容器
启动容器的命令是 docker run,对于该命令详细的使用方法,可以使用
docker run --help
-p 指定服务器端口映射 例如 -p 8080:80 第一个参数8080代表宿主机端口,后一个参数80代表是容器端口
-d 表示以守护进程模式启动,将容器启动到后台
–name 表示为容器起的名字,可以为容器制定一个名称。不带该参数时,docker会为我们创建的每一个容器生成一个随机的名字
我们使用以下命令启动一个nginx容器
docker run -p 8000:80 --name mynginx -d nginx
我们验证一下nginx容器功能是否正常,访问宿主机IP地址80端口
OK,Nginx访问正常,这样一个nginx的容器就运行起来了
4)查看容器
查看容器的命令为docker ps 对于该命令详细的使用方法,可以使用docker ps --help来查看
docker ps #查看目前工作的容器,加 -a 查看所有运行过的容器
5)与容器交互
容器运行起来之后,我们怎么知道容器内部在干什么呢?
docker logs <容器名或容器ID> 可以用来获取容器的日志,加 -f 参数可以跟踪容器日志
当然,可以已查看容器内部的进程,命令是:
docker top <容器名或容器ID>
docker stats 命令可以用来统计Docker信息
当然,除了查看docker内部的进程信息之外,我们还可以在容器内部运行额外新的进程,命令是:
docker exec 对于该命令详细的使用方法,可以使用docker exec --help来查看
-d 表示运行一个后台进程
-t 表示为我们执行的进程创建TTY终端
-i 表示捕获STDIN,即我们的输入
例如,我们想要进入容器内部,则可以运行以下命令,表示在mynginx容器中运行bash命令,并启动TTY终端捕获我们的输入
docker exec -it mynginx bash
如果想退出的话,直接输入exit回车即可。
6)容器状态管理
docker stop <容器名或容器ID> 停止一个正在运行的容器
docker start <容器名或容器ID> 运行一个已经停止的容器
docker restart <容器名或容器ID> 重启容器
docker pause <容器名或容器ID> 暂停容器
docker pause <容器名或容器ID> 容器取消暂停
7)自动重启容器
如果由于某种错误而导致容器停止运行,还可以在docker run命令中指定–restart标志来让Docker自动重启该容器
–restart=always 总是自动重启该容器
–retart=on-failure:5 当容器退出代码未非0时,自动重启,最多重启5次(退出代码0,表示正常退出)
8)docker详细信息
docker inspect <容器名或容器ID>
使用 docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
9)删除容器
当容器不再使用时,可以使用docker rm 来删除它们
docker kill <容器名或容器ID> 杀死正在运行的容器
docker rm <容器名或容器ID> 删除已经停止的容器
docker kill $(docker ps -a -q) 杀死所有正在运行的容器
docker rm $(docker ps -a -q) 删除所有已经停止的容器
三、Docker镜像仓库与镜像构建
之前,我们学习了Docker的安装与Docker容器管理的命令,这一部分,我们将学习Docker镜像
Docker镜像:用来启动容器的 构建基石。
1)什么是Docker镜像
Docker镜像是由文件系统叠加而成,最底层是一个引导文件系统,即bootfs,在第二层则是root文件系统,即rootfs,rootfs可以是一种或多种操作系统如Debian或ubuntu,用下图来说明一下:
Docker将这样堆叠的文件系统称为镜像,一个镜像可以放在另一个镜像的顶部,位于下面的镜像称为父镜像,最底层的镜像称为基础镜像。当从一个镜像启动容器时,Docker会在该镜像的最顶层加载一个读写文件系统,我们在Docker中运行的程序就是在这个读写层中执行的。
2)镜像仓库
镜像保存在仓库中,仓库存在于Registry中,默认的Registry是由Docker公司运营的公共Registry服务,即DockerHub https://hub.docker.com/ ,镜像常用的命令如下:
docker search <镜像名>:<镜像标签> 镜像查找
docker pull <镜像名>:<镜像标签> 镜像拉取
docker images 列出所有镜像
对于命令详细的使用方法,可以使用docker <命令> --help来查看
当使用docker run命令从镜像启动一个容器时,如果镜像不存在于本地,Docker会先从仓库中下载该镜像。
3)构建镜像
镜像仓库里的镜像为标准镜像,那么我们如何修改定制为自己的镜像呢?
构建镜像有两种方法
- dokcer commit命令
- docker build命令和Dockerfile文件
3.1) dokcer commit 构建镜像
docker commit 构建镜像之前,我们需要运行一个基于需要修改的镜像容器.
以修改nginx镜像为例,通过修改nginx中的index.html,来定义我们自己的镜像。
a. 我们先启动一个nginx容器
docker run -d nginx
b. 然后进入容器进行修改,添加vim命令,并修改index.html文件为 hello bird!
这样就完成了我们想要的定制修改,那么要怎么保存这个修改为私人镜像呢?
c. docker commit ce96035e07d1 bird/nginx 将我们运行的容器保存为新的镜像
查看本地镜像
运行我们新构建的镜像
docker run -d --name mynginx -p80:80 bird/nginx
这样这个自定义的镜像就构建成功了
3.1) Dockerfile构建镜像
推荐使用Dockerfile方式来进行构建镜像,因为它更加灵活和强大
docker build命令需要配合Dockerfile来使用,Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
FROM nginx
RUN apt update
RUN apt install vim -y
RUN echo "hello bird!" >/usr/share/nginx/html/index.html
我们还是先查看一下docker build —help 命令的使用方法
在Dockerfile目录下执行
docker build -t birdlearn/mynginx:v2 .
-t 表示 镜像名称:镜像标签
. 表示上下文路径为当前目录
执行命令后便开始进行镜像的构建了
镜像构建完成后,使用docker images 查看镜像列表,可以看到我们构建的镜像已经在本地仓库了
运行我们刚刚构建的镜像
docker run -p80:80 birdlearn/mynginx:v2
可以看到这个自定义构建的镜像运行起来的容器,已经是我们修改后的效果了
扩展阅读: Dockerfile 详细用法 ————————————TODO
镜像构建完成后,我们如果想要导出导入镜像,则需要用到save、load命令,即
docker save
其中-o和>表示输出到文件,nginx.tar为目标文件,nginx:latest是源镜像名(name:tag)
docker save -o nginx.tar nginx:latest
#或
docker save > nginx.tar nginx:latest
docker load
其中-i和<表示从文件输入。会成功导入镜像及相关元数据,包括tag信息
docker load -i nginx.tar
#或
docker load < nginx.tar
镜像文件可以导出导入,那么容器能否导入导出呢?当然可以,容器的导入导出命令是 import 和 export,即:
docker import
docker import nginx-test.tar nginx:imp
docker export
docker export -o nginx-test.tar nginx-test
其中-o表示输出到文件,nginx-test.tar为目标文件,nginx-test是源容器名(name)
四、Docker的编排 Docker Compose
前面我们讲到了docker的安装与管理,并且知道了docker build 构建镜像、docker run运行镜像为容器。但是当今软件系统开发中,微服务架构的广泛应用,使得一个应用系统一般包含很多的微服务,每个微服务一般都会启动多个实例,如果每个微服务都需要我们手动启动停止,那么可以想象维护工作室多么巨大的。
有没有一个工具,可以让我们轻松高效的管理容器呢?
答案就是Docker Compose工具,Docker Compose试一个多容器编排的工具。
Compose 项目是由Python编写的,实际上就是调用了Docker服务提供的API来对容器进行管理,因此,只要所在的操作系统的平台支持Docker API,就可以在其上利用Compose来进行编排管理。
Docker Compose将管理的容器分为三层,分别是project、service、container
Docker Compose 运行目录下的所有文件(docker-compose.yml)组成一个工程,一个工程包含多个服务,每个服务中定义了容器运行的镜像、参数、依赖,一个服务可包括多个容器实例。
1、Docker Compose安装
安装 Docker Compose 可以通过下面命令自动下载适应版本的 Compose,并为安装脚本添加执行权限
sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
为docker-compose添加可执行权限
sudo chmod +x /usr/local/bin/docker-compose
安装完成后检查
docker-compose -v
2.docker-compose.yml文件
模板文件是Compose的核心,涉及的指令关键字比较多,但是大部分的指令与docker run相关的参数的含义是类似的详见官方文档
官网地址: https://docs.docker.com/compose/compose-file/
这里讲几个常用的参数
docker-compose.yml的常见结构如下
version: '3' # 表示该 Docker-Compose 文件使用的是 Version 3 file
services: # 定义所有的 service 信息, services 下面的第一级别的 key 既是一个 service 的名称
blogweb: # 指定服务名称
image: nginx # 指定 docker 镜像, 可以是远程仓库镜像、本地镜像
build: # 指定包含构建上下文的路径, 或作为一个对象,该对象具有 context 和指定的 dockerfile 文件以及 args 参数值
context: . # 指定构建上下文的路径
dockerfile: ./Dockerfiles/blogweb/Dockerfile # 指定 context 指定的目录下面的 Dockerfile(默认为 Dockerfile)
ports: # 指定端口映射
- "80:80" # 容器的 80 端口和宿主机的 80 端口建立映射关系
- "443:443” # 容器的 443 端口和宿主机的 443 端口建立映射关系
restart: always # 定义容器重启策略 no 禁止自动重启容器(默认) always 无论如何容器都会重启 on-failure 当出现 on-failure 报错时, 容器重新启动
links: # 链接到其它服务中的容器,这样当在本服务器中,建立与其他服务的域名
- app_articles:app_articles
- app_auth:app_auth
- app_files:app_files
depends_on: # 定义容器启动顺序 (此选项解决了容器之间的依赖关系, 此选项在 v3 版本中
- app_articles
- app_auth
- app_files
mysql:
build:
context: .
dockerfile: Dockerfiles/mysql/Dockerfile # 指定 Dockerfile 所在路径
ports:
- "3306:3306"
restart: always
environment: # 设置环境变量, environment 的值可以覆盖 env_file 的值 (等同于 docker run --env 的作用)
- MYSQL_ROOT_PASSWORD=*********
volumes: # 定义容器和宿主机的卷映射关系
- ./data/mysql:/var/lib/mysql # 映射容器内的 /var/lib/mysql 到宿主机的./data/mysql
3、docker-compose 命令
常见的命令如下
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
常用的命令
docker-compose up 创建并启动指定yml文件中的容器 -d 指定以守护进程运行
docker-compose build 当yml文件有修改时,可以使用该命令重新构建镜像
docker-compose up --build 携带build标识,会重新检测yml变更,如果有变更则会重新构建
docker-compose stop 停止服务
五、Docker实战,快速搭建一个博客系统
现在我们认识了Docker技术,也认识了Docker编排技术,那么就让我们实际部署一个由docker组成的系统吧。
我们以Birdlearn博客为例,对原有服务进行Docker化。
Birdlearn 源码地址
基于VUE框架开发的web前端 https://gitee.com/ikachu/BD-Blog
基于Tornado框架开发的后端服务 https://gitee.com/ikachu/bdblog-webapps
docker-compose源码地址
博客架构
由于VUE生成的是静态文件,所以我们只需要将WEB前端的文件挂载到Nginx服务下即可,整个系统需要7个服务,整个docker-compose文件目录如下:
使用 docker-compose up -d 构建镜像并启动容器, 一键完成系统部署
Note: 因为没有给redis设置密码导致docker被植入挖矿程序。
解决办法:redis不要映射到宿主机端口上,或者给redis设置密码。
六、Q&A
- 一个容器里可以两个进程吗?
可以运行多个程序。一般可以用supervisor或脚本来拉起多个程序。但现在一般不建议这么做。建议每个docker容器中只运行一个程序。
- docker 部署中数据库的连接
https://blog.csdn.net/qq_40770950/article/details/95001874
- docker部署 日志
https://www.cnblogs.com/jingjulianyi/p/6637801.html
-
docker如何暴露多个端口?
-1、创建容器时指定docker run -p <host_port1>:<container_port1> -p <host_port2>:<container_port2>
- 2、修改dockerfile expose所需要的端口,这样可以免去-p参数。
-
docker获取运行中容器的IP
docker inspect <容器名> | grep IPAddress
- docker给运行中容器添加端口映射
将容器的8000端口映射到docker主机的8001端口
iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000
- docker端口映射时如何指定TCP/UDP
docker run -ti -d --name my-nginx5 -p 8099:80/tcp docker.io/nginx
docker run -ti -d --name my-nginx5 -p 8099:80/udp docker.io/nginx
- docker删除镜像
# 停止docker
docker stop $(docker ps -a | grep "Exited" | awk '{print $1 }')
# 删除异常停止的docker容器
docker rm $(docker ps -a | grep "Exited" | awk '{print $1 }')
# 删除名称或标签为none的镜像
docker rmi $(docker images | grep "none" | awk '{print $3}')
- 删除未使用到的images
docker image prune -a
# 或者
docker image prune -a -f #-f强制,无需确认