注意
本系列文章已升级、转移至我的自建站点中,本章原文为:Docker入门
目录
1.前言
如果你长期写C/C++代码,那你应该很容易发现C/C++开源项目存在的一个严重问题:只要作者没有将源码编译为可执行文件、现成的动静态库,需要我们自己去编译,就会有极大概率编译不出来、报各种错。
究其根本在于C/C++过于复杂,尤其是其代码的编译环境往往需要各种依赖,并且在各个操作系统上的环境依赖还有很大可能是不一致的。
而本文要介绍的docker便能很好的解决这个问题,但其解决的也不仅仅只是这一个问题。
事实上并不只是C/C++语言,各种项目交付都会由于各种各样的环境原因,导致其在作者电脑上可以跑起来,可一旦将其交给客户,就会有相当大的概率跑不起来。
比如如今大火的各种大语言模型,如果你尝试过自己去本地部署大模型,就会知道其过程的艰辛了,其对新手是相当不友好的。
而docker就是这样的一个容器技术:它不仅仅只发布项目本身,它还会发布想要让项目运行起来所需要的一切环境。
甚至你可以简单的将其理解为,docker容器就是一个非常小型的系统,你可以在该系统中安装所有需要的依赖环境、以及告诉它如何启动我们的程序。
此时它就带来了一个惊人的好处:只要你能本地将其跑起来,那么你将其打包后发给别人,别人就一定能跑起来!
原因就在于,所有依赖环境此时都已经在docker容器内部了!
但要注意,docker容器内的系统是linux/unix环境,并不支持运行windows软件。
2.docker安装
不同系统安装docker环境的方式并不完全相同,相比之下Windows系统安装docker环境更加简单,只需要下载安装Docker Desktop即可:Docker Desktop
进入安装界面,勾选所有配置,然后直接点击Ok,等待其安装完成。
然后打开软件,点击Accept:
直接无账号使用即可,如果后续你需要发布自己打包的镜像,就需要自己去注册一个账号登录了:
然后下一步是选择身份,直接跳过即可:
然后我们就进入到docker的主页面了:
虽然初次看起来你可能感觉有点懵,但事实上大多数时候我们都只用的上图中的三个页面。
- Contailers:我们此时运行中的容器
- Images:我们下载、打包的所有镜像
- Volumes:持久化卷
其中第一个容器很好理解,就是我们前面介绍的,它不仅仅包含了程序本身,还包含了需要运行程序的所有依赖环境。
而镜像,就是容器的基础,如果你安装过Windows系统就知道,Windows系统实际上是在一个以.ios结尾的镜像文件中的,通过下载、安装、运行该镜像才形成了我们所看到的各种各样的定制化的Windows系统。
而这里的镜像也是类似的含义:作者将所有需要的东西全部打包为一个镜像,并暴露出一些可以由使用者自定义的选项,使用者只需要填写这些选项运行镜像,就形成了一个自己的容器!
一个最简单的实例就是,一个包含了web服务器的docker镜像需要暴露出端口访问,虽然业界都使用80与443作为端口使用,但这并不能满足所有人的需求,有的人可能自己电脑上这两个端口已经有其它服务占了,想要使用其它端口启动该web服务。
此时打镜像的作者就可以将这个选项预留出来打成镜像,然后使用者就可以自行定义端口、启动镜像,将其作为一个容器进行运行。
3.docker基本使用
docker使用起来是非常简单的,如果我们不需要自己打镜像、只是使用别人提供的镜像。
其官方网站为:Docker Hub。
里面拥有大量别人已经打好的镜像,我们可以直接拉取下来使用。
比如我们现在想要用docker启动一个web服务器,那么我们可以直接进入docker hub搜索httpd:
可以看到,它是docker官方提供的http服务器镜像,下方的页面就是使用它的教程示例。
不过其介绍的是另外一种自己打镜像的方式,这个后面再介绍,现在我们先来试一试最简单的方式。
首先看到该镜像的各种版本,一般其放在了最前面:
但大多数时候为了简单,我们一般是直接选择latest,也就是最新的一个版本。
然后打开我们的命令行,运行下面这句命令拉取镜像:
bash
docker pull httpd:latest
事实上这条命令就在页面的右边:
只不过我这里还手动给它加了一个版本,意思是让其拉取我们指定的版本,也就是latest
,名字与版本之间用冒号分割。
拉取完成后,我们就可以在docker desktop软件中看到它了,可以直接点击运行:
然后就会让我们选择各种选项,也就是前面所说的,要基于该镜像创建一个容器:
最开始的容器名就不多说了,自己随便填即可。
而第二个就是要我们填端口了,容器本身你可以将其看作是一个独立的系统,而右边的80/tcp
含义就是容器内使用的tcp协议80端口暴露web服务,左边需要填写的是我们自己真实机器要使用的端口。
比如我这里填写的8080端口,含义就是所有访问本机8080端口的tcp流量都转发到容器中的80端口,此时就等价于,我在本机的8080端口启动了一个web服务。
然后就是下面的Volumes了,也就是卷,因为打包镜像的作者只负载web服务本身,而这个web服务要向外展现的内容还是需要使用者自己提供的。
而这个卷的含义就是,将左边的本地路径映射到容器内部的指定路径中去。
我这里的含义就是,将本机路径D:\Desktop
映射到到容器内的/usr/local/apache2/htdocs/
目录下,后面的这个目录是容器内web服务启动时找文件的路径。
这个目录可以从其官方文档中看到:
除此之外,你还可以设置环境变量,但这里不需要。
然后直接点击Run启动容器:
可以看到,容器已经成功启动了,并且还能看到容器的日志信息。
此时我们直接在浏览器中访问8080端口:
可以看到,一个web服务就这样非常容易的搭建起来了,期间我们仅仅只是运行了一条命令,填写了一些参数,没有遇到任何与依赖环境有关的问题,就让项目跑起来了,是不是非常爽!
此时容器的运行逻辑如下:
- 浏览器访问8080端口,所有到达8080端口的请求都会被docker转发到容器内的80端口
- 容器内的80端口实际上才是真正运行web服务器的端口,它会将指定目录
/usr/local/apache2/htdocs/
内的文件数据作为网页返回。 - 由于
/usr/local/apache2/htdocs/
此时与本机的D:\Desktop
相互映射,所以此时该目录下的文件数据就等价于在访问本机D:\Desktop
目录下的所有文件。 - 最后将数据通过容器内80端口转发到主机8080端口返回给浏览器。
使用容器的一个关键点在于,你需要将容器作为一个完全独立的系统看待。它内部有自己的一套文件系统、网络系统,主机想要与其互通,就需要进行文件映射、网络转发。
4.打包docker镜像
上面使用的是别人写好的镜像,使用起来需要填写很多东西,会比较麻烦。
为了简化使用步骤,我们常常就会做这样一件事:在别人的镜像之上添加一些自己的东西打包成为一个新的镜像,然后下次使用的时候直接运行使用即可。
比如上面这个httpd是一个非常通用的镜像,我们想要写一个web服务交给客户使用,肯定不会去让其自己手动填写路径映射、将网页文件映射进容器的吧,那样太麻烦了。
所以此时我们就可以在原本镜像之上,添加一个步骤,将我们写好的网页文件直接拷进容器的指定目录,并将其打包为一个新的镜像,此后别人使用时直接填写端口就可以运行了!
而打包Docker镜像,我们就需要在项目的目录中创建一个叫做Dockerfile的文件:
然后直接复制官方文档的代码即可。
注意Dockerfile没有任何后缀名,其名字也是固定的,一般不要更改。
这个文件有固定的一些命令,比如这里用到的两个命令:
- FROM:拉取指定镜像
- COPY:复制文件
拉取镜像前面我们也通过docker pull命令试过了,两者效果是一样的,只不过FROM
被用于拉取指定镜像构建我们自己的镜像。
在FROM拉取的基础镜像之后,使用了COPY命令,将主机的public-html目录复制到容器内指定目录下。
COPY命令有两个参数,第一个参数是主机路径,第二个是容器路径,作用就是将主机路径文件复制到容器内。
但要注意,我这里没有这个public-html目录,所以得自己先创建一个:
然后我们就可以在这个目录下运行下面这个命令编译我们自己的镜像了:
bash
docker build -t docker_web .
build用于构建命令,-t参数用于指定镜像的名字,最后的点,代表Dockerfile文件所在的目录,也就是当前目录下:
当构建成功,就可以看到上图中第二点所在就是我们自己的docker镜像名称。
然后你可以直接运行命令、传入相关参数启动我们的镜像:
bash
docker run -dit --name http_name -p 8080:80 docker_web
其中run代表运行容器,-dit代表后台运行,--name用于指定容器的名字,-p用于指定映射端口,这里依旧是本机的8080与容器内的80端口进行映射,最后的docker_web指定容器的镜像名称。
更简单的,我们可以直接在Docker Desktop内运行:
方法与前面所述一致,只不过此时由于我们已经将网页文件复制到镜像中了,所以不再需要添加卷来映射。
5.docker进阶
以上便是docker常用的方式与流程,非常简单。
大多数时候,我们可能都是直接使用别人打好的镜像,直接拉取、填写参数、运行即可。
而如果想要自己打镜像让别人使用,那么就需要自己编写Dockerfille文件,里面有大量的命令,需要你自己去搜索研究。
更进一步,当构造多个容器一起工作的项目时,你还需要了解Docker Compose工作原理,它可以将多个容器组织到同一个内部局域网中互相访问、使用,让你可以同时构建多个容器、并保护各个容器之间的依赖关系。
再进一步,你可能还会对k8s、微服务、云原生感兴趣,后续有空我再对其做更多的介绍
本系列文章已升级、转移至我的自建站点中,本章原文为:Docker入门