Docker入门快速上手(一)
前言
大家好,我是日菊君victor,接触docker已经有一段时间了,算是小有心得,但是在刚刚接触docker的时候确苦恼于难以找到合适的上手教程,所以此次为大家准备了一系列简单的docker教程,希望能够帮助大家在刚开始接触docker的时候能够快速上手,以便将来的深入学习。
btw,这是我第一次在网上发布技术文章,有任何不对的地方请给我留言,感激不尽。
本文未经授权禁止转载,转载请联系作者junqinyang957@gmail.com
一、Docker是什么?
此处内容我尽量写的让中学生也能看懂,故在一些细节上难免出现不严谨的地方,如果您想要深入研究,可以上docker官网查看官方详细介绍。
btw,官方也提供了docker的入门教程,写的也很不错。
简而言之:初学者可以将docker单纯看作没有图形界面的虚拟机。
试想,当你坐在楼下的星爸爸里,嘬着☕️,用你从大学开始用的Windows笔记本电脑做着自己的个人网站,一切准备都已经搞定,从前端网页到后端数据库等等。
但是当你想要部署到刚刚下单的云服务器的时候,发现将项目从win移植到Linux服务器上是也是一项繁琐的工程。shit!有没有办法可以让我一次开发全平台都可以用?我不想再重新配置烦人的环境、安装数据库、添加权限啦!JOJO!
来了~docker就是这样一个工具,能够帮助您创建一个可重复的环境。您可以指定特定的操作系统、不同库的具体版本以及不同的环境变量等等。而且,您可以在您现有的环境中隔离地运行docker上的应用。比如在你的Windows上运行一个Linux的docker应用。
docker创建了称为容器的独立的包,里面包含了运行程序所需的所有内容。每个容器都有自己的cpu、内存和网络等等,且不依赖特定的操作系统或内核。是不是觉得很像虚拟机呀?没错,咱们暂时可以简单的将docker当作一个没有图形界面,只有命令行的虚拟机,当然这种说法不严谨,不过对于入门而言已经足够了。
二、安装docker & 第一个程序
安装步骤
具体以官方安装文档为准。
macOS(本文使用的操作系统,同样适用于Linux)
推荐使用homebrew安装:
brew cask install docker
Linux——ubuntu为例
卸载旧版本:
$ sudo apt-get remove docker \
docker-engine \
docker.io
安装docker ce:
$ sudo apt-get update
$ sudo apt-get install docker-ce
Windows10
官网下载安装程序
Docker化一个应用程序
我们待会儿要进行的步骤:
- 1.创建应用程序
- 2.创建一个Dockerfile
- 3.构建一个docker image
- 4.创建一个容器
1.创建我们的应用程序
现在让我们创建一个node.js项目,如果您对node不熟悉也没有关系,按照我的操作来就可以了,我们的重点还是在docker上,该项目由以下几个文件组成:
- app.js
- package.json
- Dockerfile
在这之前您要先确保您的电脑上已经安装了node,比如在macOS上可以用homebrew安装:
brew install node
要生成package.json,我们只需要打开命令行在您的项目目录下,输入:
npm init -y
这样会生成含有一组默认值的package.json文件。
然后我们要添加要用的依赖项——express库,输入:
npm install express --save
我们将创建app.js并添加以下代码:
// app.js
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
输入以下命令来运行程序:
node app.js
现在用浏览器打开http://localhost:3000 我们应该可以看到 Hello World!
这一步就搞定了~
注意:我们刚刚给这个应用程序分配到端口是3000,稍后创建Dockerfile的时候要注意以下。
2.创建Dockerfile
我们来创建Dockerfile。这个文件是一个清单,是一个构建docker的指令文件。
我们需要什么,来让我们的程序以docker的形式跑起来呢?
- 复制所有程序文件到容器内
- 安装依赖项,比如express
- 用来告诉容器如何启动程序的指令
在复杂一些的程序中,我们可能需要设置环境变量啊、数据库啊等等。而现在我们只需要做上面的这些内容,让我们试着在Dockerfile中写出来:
// Dockerfile
FROM node:latest
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
ENTRYPOINT ["node", "app.js"]
解释:
- FROM :从Docker Hub中选择一个系统镜像(image)并下载到本地。Docker Hub是一个全球的镜像仓库,我们可以从上面直接拉镜像到本地。在这里我们选择了一个基于ubuntu的已经安装了node.js的现成镜像,这个镜像名字叫node。同时,我们通过使用后缀 :latest 选择该镜像的最新版本。(如果您本地已经有了该镜像,它就不用下载了)
- WORKDIR :设置一个工作目录,这个目录是镜像内的目录。我们在下面一个命令要用到。
- COPY :将文件从所在目录复制到WORKDIR指定的目录中。
- RUN :这玩意儿会在终端执行命令,在该项目中我们让他执行安装所有我们需要的库。
- ENTRYPOINT :在此说明如何启动我们的应用程序。之前我们运行程序使用node app.js命令,在此处需要将这个命令指定为一个数组。所以["node", "app.js"]将会被转化成node app.js到终端运行。
OK~我们已经为我们的项目创建好了所有需要的文件,此时你的当前目录里应该有这些东西:
app.js
Dockerfile
/node_modules // npm install的时候生成
package.json // npm init的时候生成
package-lock.json // npm install的时候生成
3.构建docker image
要想让我们的程序在容器中运行,需要两步:
- 建立镜像:在Dockerfile和docker build命令的帮助下,我们将创建一个镜像。
- 启动容器:在我们已有一个镜像的前提下,我们需要创建一个容器。
首先,使用以下命令创建镜像:
docker build -t whatever/node:latest .
注意命令最后的 . 是一个重要参数,表示你的Dockerfile在当前目录下(然而这样理解并不准确,这个参数实际上是指定上下文路径,不过这不影响接下来的内容)
如果您本地没有已经拉取好的node镜像,那么您的终端应该显示这样儿的内容:
让我们瞧瞧我们的镜像:
nice~
4.创建容器
接下来就是从我们的镜像中创建一个容器。一个容器就是一个孤立的空间,我们的程序就在里头跑着。我们使用docker run命令来创建容器:
docker run whatever/node
别急着运行,这个命令还不够完善,因为我们要将容器内部的端口映射到主机上的外部端口。毕竟这是一个我们希望通过浏览器来访问的程序。还记得咱们之前设置的端口是多少吗?没错,就是3000~ 进行端口映射要使用 -p ,如下所示:
-p [外部端口]:[内部端口]
完整的命令如下:
docker run -p 8000:3000 whatever/node
运行后,咱们打开浏览器,访问http://localhost:8000 , 8000是我们的外部端口,映射到容器内部的3000端口。你应该可以看到:
成功啦~~
使用环境变量来改善设置
到这里,我们已经学会了如何构建我们的docker镜像,如何运行容器。
但是我们其实还可以在端口部分做一些小优化。在上面的程序中,我们手动规定了我们的app.js和Dockerfile内的端口都是3000,这种静态的规定方法容易出错。我们可以想办法让app.js自动匹配我们在Dockerfile里写的端口。
为此,我们可以引入环境变量。我们需要:
- 1.在Dockerfile中添加一个环境变量
- 2.在app.js内读取环境变量
1.添加环境变量
我们要使用ENV命令,如下:
ENV PORT=3000
把它添加到我们的Dockerfile中:
FROM node:latest
WORKDIR /app
COPY . .
ENV PORT=3000
RUN npm install
EXPOSE 3000
ENTRYPOINT ["node", "app.js"]
再将EXPOSE改为使用我们的变量,从而摆脱了静态值的依赖:
FROM node:latest
WORKDIR /app
COPY . .
ENV PORT=3000
RUN npm install
EXPOSE $PORT
ENTRYPOINT ["node", "app.js"]
注意我们使用变量的时候要以$作为前缀。
2.在app.js内读取环境变量
将app.js代码修改为:
// app.js
const express = require('express')
const app = express()
const port = process.env.PORT
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
注意:当我们修改app.js或者Dockerfile后,我们需要重建我们的镜像,即重新运行docker build。在此之前,我们要先把当前运行的容器给关了,具体操作请看下面的章节。
管理你的容器
我猜,你现在是不是因为不知道怎么关闭当前容器而感到很慌?别慌,跟我做,你可以打开另一个终端窗口,执行以下操作:
docker ps
该命令会列出所有正在运行的容器,您可以看到容器的名称和id:
如上所示,我们可以使用容器的id来停止容器,像这样:
docker stop 203
使用id的前三位就够了,不需要更多,当然你想多输入一些也没问题。
daemon mode
运行容器要单独打开一个终端窗口不够方便,我们可以让容器在后台运行,这就是Daemon模式。我们只需要在运行容器时添加一个 -d 即可:
返回的是容器id,你想要停下容器只需要输入docker stop 33a,这同样是id的前三位。
交互模式——进入容器
如果我们想要进入我们已经运行的容器里看一看,该怎么做呢?
我们需要命令docker exec,如下:
注意只能进入正在运行的容器,如果你的容器已经停止,需要启动它后再进入。
其中 -it 就意味着交互模式,而我们的参数bash则表示我们将运行一个bash shell。
进入容器后我们还运行了ls命令,该命令列出了容器中当前目录下的内容(Linux相关知识),这样我们可以验证我们是否正确的构建了这个容器。
如果我们只想在容器上运行一些命令,比如node命令,我们可以直接输入:
docker exec 33a node app.js
容器内就会运行命令node app.js
docker kill & docker stop对比
想要停下容器,除了docker stop之外,还可以使用docker kill。它们有什么区别呢?
- docker stop发送一个信号SIGTERM,隔一段时间后再发送SIGKILL信号。简单说就是在彻底关闭容器前,给容器一段宽限期,让容器释放资源并保存状态。(我保证在三天之内撒了里~)
- docker kill立即发送SIGKILL信号。
综上,在生产环境中,使用docker stop可能更加明智优雅。
清理容器
想要删除某个容器?
docker container ls -a
列出所有容器
docker rm 容器id
删除容器
想要删除某个镜像?
docker images
列出镜像
docker image rm 镜像id
删除镜像
写在最后
以上就是这一期的全部内容,感谢您看到这里,如果您有任何疑问或者发现了文章中的错误,请给我留言吧~感激不尽😊
下一期将会介绍如何使用卷来持久化数据,敬请期待!