Docker 从入门到放弃 --- 基础篇
引言
之前发过docker基础和如何使用docker搭建一个lnmp环境,并推送到dockerHub的文章(如果基础命令不太熟悉,可以看一下之前的文章)。今天再入一次门,实用为主。主要是木得办法,到现在环境还没搞出来呢【手动捂脸】。不说了,开干!有了这两篇文章,github上看到满意的项目,反手就把环境搭出来了!
如果你认为学习docker是运维该做的,那你就错了。作为一名研发工程师,学会基础的docker使用,能大大提高平时的效率
虽然docker已经出来将近8年,但是相信还是有很多人并不知道docker是什么?为什么这么受欢迎?读完本篇,希望能解决你的疑惑。
痛点
不撞墙,哪知道另辟蹊径?
熟悉计算机发展史的应该知道,软件开发的痛点就是环境配合问题。各种不同环境的计算机,导致开发出来的软件只能在某个或某些计算机上运行。
安装一个运行环境需要考虑各种组件和库,还要考虑兼容问题。最常见的就是,“咦?在我的电脑上能运行起来啊”。既然是同样的软件包,那唯一的问题就是出在了运行环境上,那如果能把你的环境也带上一并给我,不就可以运行起来了?
虚拟机
虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。虚拟机技术帮我们实现了可以在一个操作系统上运行另一个操作系统。
上大学时,在一台windows系统上边安装三台Linux虚拟机搭建hadoop,记忆犹新啊。虽然我们只要安装好一台虚拟机,并在上边安装上必要的软件之后,就可以复制出来一个一模一样的。但是缺点也是不言而喻的,它不仅占用资源多(就算是纯终端的一个虚拟机也有几百兆),启动也是超级慢,如果三台虚拟机同时运行起来,是卡的一批啊(2核8G)
Linux容器
由于虚拟机存在的这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)
它可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpace。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与传统虚拟化技术相比,它的优势在于
启动快:容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多
资源占用少:容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源
体积小:容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多
它就像是一个轻量级的虚拟机,可以提供虚拟化的环境,但是成本开销小很多
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。
Docker
Docker是什么?
Docker可以看做是上边提到的Linux容器的一种封装,提供简单易用的容器使用接口。是目前最流行的Linux容器解决方案
Docker通过将应用程序和该程序的依赖,都打包到一个文件中,然后运行该文件,就会生成一个容器。程序就可以在这个容器中运行,效果是和在物理机上是一样的。因此,有了Docker,就可以解决环境的问题了
Docker的用途
Docker的主要用途,目前有三大类。
提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境
提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容
组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构
Docker的安装
安装可参考官方文档:
安装完成之后,可以使用一下命令查看是否安装成功
镜像(image)
关于docker里边镜像、容器、仓库更加详细的概念及命令,可以参考我之前的《docker基础学习》。
Docker把应用程序及其依赖,打包在image文件里面。通过这文件,可以生成Docker容器。image文件可以理解成是容器的模板。Docker根据image文件生成容器的实例。同一个image文件,可以生成多个同时运行的容器实例
image是二进制文件。实际开发中,一个image文件往往通过继承另一个image文件,然后在其基础上加一些个性化设置而生成。比如,你可以在Ubuntu的image基础上,往里面加入Apache服务器,形成你的image。
image文件是通用的,一台机器的image文件拷贝到另一台机器,照样可以使用。一般我们都会去dockerHub官网上下载别人制作好的image文件,这样比较节省时间,如果需要增加一些特性,可以在别人的image基础上进行添加
image实例
可以通过一个简单的的image文件来感受一下。docker官方提供的有一个测试的镜像:library/hello-world
首先通过前边提到的拉取一个镜像的命令来拉取测试镜像
library/hello-world是image文件在仓库里面的位置,其中library是image文件所在的组,hello-world是image文件的名字
此时就可以通过docker images看到刚拉取到的image。然后通过下边的命令运行这个image文件,就会生成一个正在运行的容器实例
输出结果:
docker container run命令会先看本地是否有指定的image文件,如果没有会从远程仓库拉取
对于上边的测试镜像,当其运行起来,输出一段内容之后就自动终止了。但是有些容器不会自动终止,因为它可能提供的是服务。比如,安装运行Ubuntu的image,就可以在命令行体验Ubuntu系统
对于那些不会自动终止的容器,可以使用docker container kill命令手动终止
容器
image文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件:image文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已
终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除
制作自己的Docker容器
了解了docker以及image文件之后,接下来的问题就是,如何可以生成image文件?如果你要推广自己的软件,肯定要自己制作 image文件。这就需要用到Dockerfile文件。它是一个文本文件,用来配置image。Docker根据该文件生成二进制的image文件。
下面就通过一个实例,演示如何编写Dockerfile文件
下边是以一个开源的数据管理系统为例来介绍如何编写Dockerfile文件,从而实现在容器中运行起来这个项目。
首先下载源代码
编写Dockerfile文件
如果项目中有哪些路径下的文件不希望打包到image文件中,则可以在项目根目录下创建一个.dockerignore文件,文件内容为要排除的文件的路径,我这里不希望将.git文件和node_modules目录打包进image文件,因此.dockerignore文件内容为
然后在项目的根目录下创建Dockerfile文本文件,内容为
>* FROM node:12.14:该image文件继承官方的 node image,冒号表示标签,这里标签是12.14,即12.14版本的node
>* COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都打包进入image 文件的/app目录
>* WORKDIR /app:指定接下来的工作路径为/app(很像cd)
>* RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入image文件
>* EXPOSE 3000:将容器3000端口暴露出来, 允许外部连接这个端口
创建image文件
有了Dockerfile文件以后,就可以使用docker image build命令创建image文件了
在上边的命令中,-t参数用来指定image文件的名字,后面还可以用冒号指定标签(这里需要注意,image名称需要是小写)。如果不指定,默认的标签就是latest。最后的那个点表示Dockerfile文件所在的路径,上例是当前路径,所以是一个点。如果运行成功,就可以通过docker images命令看到新生成的image文件data-admin:v1了
生成容器
docker container run命令会从image文件生成容器
>* -p参数:容器的3000端口映射到本机的8000端口
>* -it参数:容器的Shell映射到当前的Shell,然后你在本机窗口输入的命令,就会传入容器
>* data-admin:v1:image文件的名字(如果有标签,还需要提供标签,默认是latest标签)
>* /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动Bash,保证用户可以使用Shell
(当然也还有更多的参数,可以参考我之前的docker基础文章)
如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。这表示你已经在容器里面了,返回的提示符就是容器内部的Shell提示符。执行npm run serve就可以将项目正常运行起来了(会遇到一个vue cli在容器中运行的问题,大家可自行解决,参考:https://github.com/vuejs/vue-cli/issues/1716)
该例中,Node进程运行在Docker容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射
CMD命令
在上边的例子中,当我们将容器运行起来之后,还需要进入到容器中,执行yarn serve才能将项目运行起来。这个命令其实可以写在Dockerfile中,此时,当容器运行起来后,该命令会自动执行
上面的 Dockerfile 里面,多了最后一行CMD yarn serve,它表示容器启动后自动执行yarn serve
RUN命令与CMD命令的区别,简单说,RUN命令在image文件的构建阶段执行,执行结果都会打包进入image文件;CMD命令则是在容器启动后执行。另外,一个Dockerfile可以包含多个RUN命令,但是只能有一个CMD命令
注意:指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令。现在,启动容器可以使用下面的命令
如果想将image文件推送到dockerHub,可以参考我之前的《mac OS中使用docker安装ubuntu+lnmp》这篇文章最下边一部分
还是需要动手做起来,才能更深的理解
参考:
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html
https://www.jianshu.com/p/63fea471bc43
版权声明: 本文为 InfoQ 作者【书旅】的原创文章。
原文链接:【http://xie.infoq.cn/article/5f0c11ab209b82ae9f6fc9c6d】。文章转载请联系作者。
评论