经常写程序的同学们往往会遇到这样一些痛点:代码更新发布、部署效率实在是低下,环境的一致性也难以保证,明明在开发环境里能运行的代码,换了一台机器怎么就跑不通了?
云计算时代,还在用传统方式部署代码,怎么好意思说自己是9102年的工程师?实在是不能忍!今天,你虾就给大家安利一下被誉为“云计算时代的颠覆性技术”——Docker
什么是Docker?
Docker 是一个基于 Go 语言,并遵从 Apache2.0 协议开源的应用容器引擎。
它是一种容器级的虚拟化技术, 开发者可以打包他们的应用以及依赖包到一个轻量级、可移植的容器中,并发布到任何流行的 Linux 机器上,无需担心环境的问题。
Docker 和 VM,傻傻分不清楚
前面我们提到,Docker 是一种基于虚拟化的技术,谈到虚拟化就不得不说 VM(Virtual Machine 虚拟机),既然都是基于虚拟化,Docker 和 VM 又有什么差别呢,别急,咱们慢慢来聊这个问题。
我们先来看右侧 VM 的架构图,在 Infrastucture(可以理解为底层硬件)之上,有一层 Hypervisor,它是一种运行在物理服务器和操作系统之间的中间层,可以允许多个操作系统和应用共享底层硬件。虚拟机在主操作系统之上运行多个不同的子操作系统,并通过 Hypervisor 调用底层的硬件。
假设你需要运行3种相互隔离的应用,那你得创建3台虚拟机,这也就意味着在 Hypervisor 之上会运行着3个子操作系统,这样会产生特别大的资源开销。
(P.S 其实图中 Hypervisor 和 Infrastucture 之间应该还有一层 Host Operating System)
而 Docker 就显得十分轻便了,它的守护进程(Docker Daemon)取代了 Hypervisor,直接运行在操作系统之上,应用的源代码与它的依赖都打包在Docker镜像 (image) 中,Docker 引擎通过镜像去创建容器(container)。不同的应用运行在不同的容器中,它们之间是相互隔离的。
并且,Docker 守护进程可以直接与操作系统进行通信,为各个 Docker 容器分配资源,由于没有臃肿的从操作系统,虚拟机启动需要数分钟,而 Docker 容器可以在数毫秒内启动,效率提升明显,且节省了大量的磁盘空间以及其他系统资源。
说了这么多,你是不是认为 Docker 完全可以吊打虚拟机了呢,其实不是。俗话说术业有专攻,相比 Docker,虚拟机更擅长彻底隔离整个运行环境,最常见的就是云厂商通过VM的方式来隔离不同的用户;而 Docker 通常用于隔离不同的应用。
如何使用Docker
Docker的安装(以CentOS 7 为例)
#安装一些必要的系统工具:
yum install -y yum-utils device-mapper-persistent-data lvm2
#更新系统内核以及yum缓存
yum update
yum makecache fast
#安装Docker并启动
yum -y install docker-ce
systemctl start docker
#测试Docker是否安装成功
docker run hello-world
如果屏幕出现了 Hello from Docker ,恭喜你,安装这一步就已经大功告成了
Docker的相关概念
在进一步学习 Docker 之前,我们需要科普一些 Docker 的相关概念,这样在下面的学习中,你才会有一种事半功倍的 feeling
Key | Value |
---|---|
Docker镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板 |
Docker容器 (Container) | Docker通过镜像创建出容器,用于运行一组独立的应用 |
Docker仓库 (Registry) | 用于保存镜像的代码仓库 |
通常,我们会从Docker仓库中下载对应的镜像,并通过镜像创建出运行应用的容器
Docker实例
多说无益,下面我们将通过两个比较典型的实例,将相关的知识点串联起来,来学习如何使用Docker
使用Docker安装Python
刚刚我们说过,想使用Docker容器,第一步是从仓库中下载相应的镜像,这就引出了我们教程中的第一条命令
docker search
作用:从镜像仓库中查找指定镜像
语法:docker search [OPTIONS] TERM
示例:docker search python
详解:从仓库中寻找Python相关的镜像
[root@FUCC ~]# docker search python
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/python Python is an interpreted, interactive, obj... 4356 [OK]
docker.io docker.io/django Django is a free web application framework... 856 [OK]
docker.io docker.io/pypy PyPy is a fast, compliant alternative impl... 196 [OK]
docker.io docker.io/kaggle/python Docker image for Python scripts run on Kaggle 125 [OK]
docker.io docker.io/arm32v7/python Python is an interpreted, interactive, obj... 38
docker.io docker.io/centos/python-35-centos7 Platform for building and running Python 3... 36
在这里我们直接选择官方的镜像,标签(版本)为3.7
docker pull
作用:从镜像仓库中拉取或者更新指定镜像
语法:docker pull [OPTIONS] NAME:TAG
示例:docker pull python:3.7
详解:从仓库中下载标签为3.7的 Python镜像
[root@FUCC ~]# docker pull python:3.7
Trying to pull repository docker.io/library/python ...
3.7: Pulling from docker.io/library/python
5ae19949497e: Downloading [=============> ] 13.72 MB/50.38 MB
ed3d96a2798e: Download complete
f12136850781: Downloading [============================================> ] 8.789 MB/9.978 MB
1a9ad5d5550b: Downloading [==> ] 2.628 MB/51.77 MB
6f18049a0455: Waiting
ce39fa9d79d1: Waiting
Digest: sha256:d8718f4c8f28360c88d2d8b53681edb3c95e6a7bacedabd32eb5b1d120a75dc5
Status: Downloaded newer image for docker.io/python:3.7
此时,Docker便已经帮我们从仓库中下载指定的镜像了,下载完成后,可以使用下面这条命令来查看本地已经存在的Docker镜像
docker images
作用:列出本地镜像
语法:docker images [OPTIONS] [REPOSITORY[:TAG]]
示例:docker images
详解:查看本地所有的docker镜像
[root@FUCC ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/python 3.7 42d620af35be 6 days ago 918 MB
docker.io/rabbitmq 3-management 7aae48fa6ef6 7 days ago 179 MB
docker.io/golang latest f50db16df5da 9 days ago 774 MB
可以看到,此时本地已经存在了python3.7的镜像,事不宜迟,我们就用这个镜像来创建一个容器吧,Let's go !
docker run
在创建容器之前,我们先简单聊一下ID的概念,在Docker中,我们通常使用ID来作为一个镜像或者容器的唯一标识,一般以"命令 + ID"的方式对一个镜像或者容器进行操作,如上面这段代码,我们可以看到python3.7这个镜像的ID为42d620af35be
作用:创建一个新的容器
语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
为了测试我们的python环境是否安装完成,我们先在本地新建一个 hello.py 的文件
##!/usr/bin/python
import sys
print("Hello, Docker!")
print(sys.version) #输出Python版本号
以我的环境为例,我把这段代码保存在了本地的 /root/code/python 目录下
接下来,我们就使用 docker 中的 python 环境去运行这段代码吧
[root@FUCC python]# docker run -v $PWD:/usr/src/code -w /usr/src/code python:3.7 python hello.py
Hello,Docker!
3.7.4 (default, Jul 13 2019, 14:04:11)
[GCC 8.3.0]
乍一看,这么长的一段命令着实有点吓人,别慌,待我来把命令拆解开细细讲给你听
docker run: 用于创建一个容器,这段我们刚刚聊过,pass
-v $PWD:/usr/src/code: 用于挂载本地的目录到docker容器中,以这条命令为例,它将执行这段命令所在的目录,挂载到了容器中的 /usr/src/code 目录下,冒号前面是本地路径,后面为对应的容器中的目录,你也可以不用PWD,直接用绝对路径的写法
-w /usr/src/code: -w用于指定容器的工作目录,在上一步中,我们将本地存放python代码的目录挂载到了容器中的 /usr/src/code 目录,所以我们将这个目录设置为容器的工作目录
python:3.7:指定镜像,你也可以用Image ID 来替换这里的镜像名称
python hello.py:这里应该就不用我多说了,这是在容器中执行的命令
看到这里,我给你布置一道思考题,假设我在本地的 /root/data/ 目录中存放了一个 hello.go 的代码文件,想要使用Image ID 为 f50db16df5da 的golang 容器运行这段代码,命令应该怎么写呢,欢迎在评论区留言
(P.S 运行go语言代码的命令为 go run FILENAME)
使用Docker安装MariaDB
从Docker仓库中搜索并下载MariaDB镜像的过程相信你已经能无师自通了,这里我们主要是聊启动的过程。
相信你已经知道,类似于数据库这类的服务,需要在本地开启相对应的端口,那么在Docker中应该如何实现呢,还记得在刚刚的Python案例中,我们将存放代码的本地目录和容器中的目录做了一个映射吗,同样的,端口也可以有这种操作
[root@FUCC python]# docker run -d -v /data/mysql/:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --restart unless-stopped 3a2ef06682ac
-d:将容器在后台运行
-p 3306:3306:将容器中3306的端口映射到主机的3306端口
-e MYSQL_ROOT_PASSWORD=123456:初始化root的密码为123456
--restart unless-stopped: 设置当容器意外停止时自动重启
3a2ef06682ac:创建容器的Image ID
这时我们可以验证一下数据库服务是否启动
docker ps
作用:列出容器
语法:docker ps [OPTIONS]
[root@FUCC ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
107b52416c13 3a2ef06682ac "docker-entrypoint..." 5 minutes ago Up 5 minutes 0.0.0.0:3306->3306/tcp quizzical_mcnulty
接下来,我们进入容器内部看一看
docker exec
作用:在运行的容器中执行命令
语法:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
示例:docke exec -it 107b52416c13 bash
详解:进入ID为107b52416c13的容器中执行bash命令
进入容器中,我们和平时操作Linux没什么两样,使用之前创建好的账户进入MariaDB,成功!
[root@FUCC ~]# docker exec -it 107b52416c13 bash
root@107b52416c13:/# mysql -u root -p123456
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.6-MariaDB-1:10.4.6+maria~bionic mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
讲到这里,相信你对Docker已经有了一些简单的认识,但这些都只是沧海一粟,单靠这篇文章是绝对讲不完的(你标题不是说入门看这一篇就够了吗),在下一篇文章里(如果有的话),咱们再好好聊一聊进阶的内容,Bye~
有疑问加站长微信联系(非本文作者)