Docker入门快速上手(一)——简介&安装&第一个程序

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

删除镜像

写在最后

以上就是这一期的全部内容,感谢您看到这里,如果您有任何疑问或者发现了文章中的错误,请给我留言吧~感激不尽😊
下一期将会介绍如何使用卷来持久化数据,敬请期待!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容