开源应用容器引擎使用指南(Docker usage guide)
概述
Docker
是一个用于开发、发布和运行应用程序的开放平台。Docker
使您能够将应用程序与基础架构分离,以便您可以快速交付软件。使用Docker
,您可以像管理应用程序一样管理基础架构。通过利用Docker
的快速发布、测试和部署代码的方法,您可以显著减少编写代码和在生产环境中运行代码之间的延迟。
官方网站
名称 | 地址 |
---|---|
官方网站 | https://www.docker.com/ |
卸载程序
如果你安装了旧版本的docker
,docker.io
,docker-engine
请先卸载它们
sudo apt-get remove docker docker-engine docker.io containerd runc
安装程序
服务器上安装容器程序
如果你是在ubuntu
服务器上使用docker
程序,请参照下面的步骤安装docker
程序
- 更新索引文件并安装相关依赖
sudo apt-get update && sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
- 公开签名秘钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
- 添加软件仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- 更新索引文件并安装程序
sudo apt-get update && sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证容器程序是否安装成功
如果你执行下面命令docker
打印出客户端和服务端的版本信息说明docker
已经安装成功
sudo docker run version
其它平台上安装容器程序
如果你希望在windows
或者macos
下使用docker
程序,请参照下面的链接安装docker
程序
系统 | 地址 |
---|---|
Windows | https://docs.docker.com/desktop/windows/install/ |
Mac | https://docs.docker.com/desktop/mac/install/ |
Linux | https://docs.docker.com/engine/install/ |
设置国内镜像加速源
添加国内镜像加速源
- 如果
/etc/docker
目录下daemon.json
配置文件不存在,就创建一个daemon.json
配置文件
sudo nano /etc/docker/daemon.json
/etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
- 重启
docker
服务使其生效
sudo systemctl restart docker.service
验证国内镜像加速源是否添加成功
如果在输出的信息中看到https://registry.docker-cn.com
说明国内镜像加速源添加成功
sudo docker info
其它国内镜像加速源
服务器 | 地址 |
---|---|
中国官方镜像 | https://registry.docker-cn.com |
科大镜像 | https://docker.mirrors.ustc.edu.cn |
网易镜像 | https://hub-mirror.c.163.com |
腾讯镜像 | https://mirror.ccs.tencentyun.com |
拉取多个镜像并在同一网络中通信运行容器
通过拉取mongo
和mongo-express
镜像,并在创建的同一网络mongo-network
中分别运行mongo
和mongo-express
容器,在下面步骤中实现了通过网页的形式来管理数据库
拉取数据库镜像
sudo docker pull mongo
拉取数据库界面镜像
sudo docker pull mongo-express
为多个容器创建相互通信的网络
sudo docker network create mongo-network
运行数据库容器
sudo docker run -d \
-p 27017:27017 \
--network mongo-network \
--name mongo \
-e MONGO_INITDB_ROOT_USERNAME=username \
-e MONGO_INITDB_ROOT_PASSWORD=password \
mongo
运行数据库界面容器
sudo docker run -d \
-p 8081:8081 \
--network mongo-network \
--name mongo-express \
-e ME_CONFIG_MONGODB_SERVER=mongo \
-e ME_CONFIG_MONGODB_ADMINUSERNAME=username \
-e ME_CONFIG_MONGODB_ADMINPASSWORD=password \
mongo-express
多容器部署 Docker-compose
多容器部署docker-compose
是以配置文件的形式来拉取多个镜像并在同一网络中通信运行容器,在下面步骤中同样实现了通过网页的形式来管理数据库,比上面直接拉取镜像再运行的方法更简单且更好管理
安装软件
sudo apt install -y docker-compose
准备工作
- 创建
/home/mongo
目录
sudo mkdir -p /home/mongo
- 进入
/home/mongo
目录
cd /home/mongo
编辑配置文件
- 在
/home/mongo
目录中创建docker-compose.yaml
配置文件
sudo nano docker-compose.yaml
/home/mongo/docker-compose.yaml
# 版本信息
version: '3'
# 容器服务,包含多个容器
services:
# 容器一
mongo:
# 容器名称
image: mongo
# 端口[宿主机:容器]
ports:
- "27017:27017"
# 环境变量
environment:
- MONGO_INITDB_ROOT_USERNAME=username
- MONGO_INITDB_ROOT_PASSWORD=password
# 容器二
mongo-express:
# 容器名称
image: mongo-express
# 端口[宿主机:容器]
ports:
- "8081:8081"
# 环境变量
environment:
- ME_CONFIG_MONGODB_SERVER=mongo
- ME_CONFIG_MONGODB_ADMINUSERNAME=username
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
注意:在配置文件中我们并没有为mongo
和mongo-express
容器指定同一网络,它会自动创建默认的网络来进行容器间的通信和默认数据卷来持久化数据
运行容器
sudo docker-compose up -d
停止容器
sudo docker-compose down
指令说明
名称 | 地址 |
---|---|
官方指令说明 | https://docs.docker.com/compose/compose-file/ |
官方指令格式的版本说明 | https://docs.docker.com/compose/compose-file/compose-versioning/ |
指令 | 说明 |
---|---|
version | 指定指令格式版本 |
services | 容器集合 |
build | 指定构建镜像的dockerfile配置文件 |
image | 指定镜像名称 |
container_name | 指定容器名称 |
environment | 设置环境变量 |
env_file | 通过配置文件设置环境变量 |
ports | 暴露端口给宿主机 |
expose | 暴露端口给连接服务且不暴露端口给宿主机 |
labels | 指定标签 |
dns | 自定义容器接口上的DNS服务器 |
network_mode | 设置容器的网络模式 |
networks | 指定网络名称 |
volumes | 指定数据卷挂载路径 |
构建镜像 Dockerfile
构建镜像dockerfile
是以文本文件的形式来构建镜像,dockerfile
文本文件中包含了构建镜像的指令和说明
准备工作
- 创建
/home/helloworld
目录
sudo mkdir -p /home/helloworld
- 进入
/home/helloworld
目录
cd /home/helloworld
编辑配置文件
- 在
/home/helloworld
目录中创建helloworld.js
程序文件
sudo nano helloworld.js
/home/helloworld/helloworld.js
// 引入模块
var http = require('http');
// 网页服务
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('HelloWorld\n');
}).listen(3000);
// 打印输出
console.log('Server running at http://127.0.0.1:3000/');
- 在
/home/helloworld
目录中创建dockerfile
配置文件
sudo nano dockerfile
/home/helloworld/dockerfile
# 基础镜像
FROM node:17-alpine
# 复制本地文件到镜像中
ADD . /helloworld
# 设置工作目录
WORKDIR /helloworld
# 运行命令,通常用于启动程序(只能有一条 CMD 指令)
CMD [ "node","helloworld.js" ]
构建镜像
sudo docker build -t helloworld:latest .
注意:每次修改dockerfile
文件后就需要重新构建镜像
运行容器
sudo docker run -d -p 3000:3000 --name helloworld helloworld:latest
进入容器的终端
sudo docker exec -it helloworld /bin/sh
退出容器的终端
exit
停止容器
sudo docker stop helloworld
指令说明
名称 | 地址 |
---|---|
官方指令说明 | https://docs.docker.com/engine/reference/builder |
指令 | 说明 |
---|---|
FROM | 指定所创建镜像的基础镜像 |
RUN | 运行命令 |
CMD | 指定容器启动时默认执行的命令 |
LABEL | 指定生成镜像的元数据标签信息 |
MAINTAINER | 镜像维护者信息(弃用) |
EXPOSE | 声明镜像内服务所监听的端口 |
ENV | 指定环境变量 |
ADD | 复制内容到镜像中并解压缩内容 |
COPY | 复制内容到镜像中(官方推荐) |
ENTRYPOINT | 指定镜像的默认入口命令 |
VOLUME | 创建数据卷挂载点 |
USER | 设置容器启动的登录用户 |
WORKDIR | 设置工作目录 |
ARG | 指定镜像内使用的参数 |
ONBUILD | 创建子镜像时指定自动执行的操作指令 |
STOPSIGNAL | 容器退出的信号值 |
HEALTHCHECK | 设置所启动容器如何进行健康检查 |
SHELL | 指定默认 shell 类型 |
推送镜像到远程仓库 Docker Hub
创建远程仓库
名称 | 地址 |
---|---|
容器官方镜像仓库 | https://hub.docker.com/ |
注意:要推送镜像到远程仓库需要提前在dokcer hub
上注册帐号密码
登录远程仓库
sudo docker login
注意:输入docker hub
的帐号密码即可登录
标记镜像
sudo docker tag helloworld:latest dabolau/helloworld:latest
推送镜像到远程仓库
sudo docker push dabolau/helloworld:latest
注意:如果修改了镜像需要重新构建镜像后再重复上面三个步骤
注销远程仓库
sudo docker logout
注意:如果不更换其他私有仓库就不需要执行这一步
构建镜像并多容器部署服务
在这个过程中我们会构建镜像并多容器部署三个服务,了解数据卷和网络的相关配置
准备工作
- 创建
/home/api
目录
sudo mkdir -p /home/api
- 进入
/home/api
目录
cd /home/api
编辑配置文件
- 在
/home/api
目录中创建api.js
程序文件
sudo nano api.js
/home/api/api.js
// 引入模块
const Koa = require('koa');
const Router = require('koa-router');
const MongoClient = require('mongodb');
// 实例化对象
const app = new Koa();
const router = new Router();
// 获取当前机器的主机名
function getHostName() {
const os = require('os');
return os.hostname()
}
// 获取当前机器的网络地址
function getIpAddress() {
const os = require('os');
let ifaces = os.networkInterfaces()
for (let dev in ifaces) {
let iface = ifaces[dev]
for (let i = 0; i < iface.length; i++) {
let { family, address, internal } = iface[i]
if (family === 'IPv4' && address !== '127.0.0.1' && !internal) {
return address
}
}
}
}
// 判断是否为容器环境
function isDocker() {
const fs = require('fs');
try {
fs.accessSync('/.dockerenv');
return true;
} catch (error) {
return false
}
}
// 数据库连接地址
let url = `mongodb://username:password@localhost:27017`;
if (isDocker()) {
// 获取环境变量
let mongoAddress = process.env['MONGO_ADDRESS'];
let mongoUsername = process.env['MONGO_USERNAME'];
let mongoPassword = process.env['MONGO_PASSWORD'];
if (mongoAddress && mongoUsername && mongoPassword) {
url = `mongodb://${mongoUsername}:${mongoPassword}@${mongoAddress}`;
} else {
url = `mongodb://username:password@mongo:27017`;
}
}
console.log("Mongo URL",url);
// 初始化对象
const mongoClient = new MongoClient.MongoClient(url);
// 连接数据库
mongoClient.connect(async (err) => {
if (!err) {
console.log(`Mongo connected successfully`);
// 创建数据库
await mongoClient.db("db").createCollection("users", (err) => {
if (err) {
console.log('Collection already exists');
return;
}
console.log('Collection create successfully');
});
app.context.db = mongoClient.db("db");
}
else {
console.log('Mongo connection failed:%s', err);
}
});
// 首页
router.all('/', (ctx) => {
ctx.body = {
"HostName": getHostName(),
"IpAddress": getIpAddress(),
"IsDocker": isDocker(),
}
});
// 获取所有用户信息页
router.all('/user', async (ctx) => {
let user = await ctx.db.collection("users").find({});
let datas = await user.toArray();
if (user) {
ctx.body = {
"Datas": datas,
"Message": "查询成功",
"StatusCode": "200",
};
} else {
ctx.body = {
"Datas": [],
"Message": "查询失败",
"StatusCode": "403",
};
};
});
// 注册页
router.all('/user/register', async (ctx) => {
let usernameObj = { "username": ctx.query.username };
let passwordObj = { "password": ctx.query.password };
let user = await ctx.db.collection("users").updateOne(usernameObj, { '$set': passwordObj }, { upsert: true })
if (user.upsertedId) {
ctx.body = {
"Message": "注册成功",
"StatusCode": "200",
};
} else {
ctx.body = {
"Message": "注册失败",
"StatusCode": "403",
};
};
});
// 登录页
router.all('/user/login', async (ctx) => {
let userObj = { "username": ctx.query.username, "password": ctx.query.password };
let user = await ctx.db.collection("users").findOne(userObj);
if (user) {
ctx.body = {
"Message": "登录成功",
"StatusCode": "200",
};
} else {
ctx.body = {
"Message": "登录失败",
"StatusCode": "403",
};
};
});
// 使用中间件
app.use(router.routes());
app.use(router.allowedMethods());
// 监听端口
app.listen(3000);
// 打印输出
console.log('Server running on http://0.0.0.0:3000/');
- 在
/home/api
目录中创建package.json
配置文件
sudo nano package.json
/home/api/package.json
{
"dependencies": {
"koa": "^2.13.4",
"koa-router": "^10.1.1",
"mongodb": "^4.5.0"
}
}
- 在
/home/api
目录中创建dockerfile
配置文件
sudo nano dockerfile
/home/api/dockerfile
# 基础镜像
FROM node:16-alpine
# 复制本地文件到镜像中
ADD . /api
# 设置工作目录
WORKDIR /api
# 运行命令,通常用于安装应用,安装依赖,配置系统信息(可以有多条 RUN 指令)
RUN npm i --registry=https://registry.npm.taobao.org
# 运行命令,通常用于启动程序(只能有一条 CMD 指令)
CMD ["node","api.js"]
构建镜像
sudo docker build -t api:latest .
注意:每次修改dockerfile
文件后就需要重新构建镜像
标记镜像
sudo docker tag api:latest dabolau/api:latest
推送镜像到远程仓库
sudo docker push dabolau/api:latest
注意:如果修改了镜像需要重新构建镜像后再重复上面三个步骤
编辑配置文件
- 在
/home/api
目录中创建docker-compose.yaml
配置文件
sudo nano docker-compose.yaml
/home/api/docker-compose.yaml
# 版本信息
version: '3'
# 容器服务,包含多个容器
services:
# 容器服务
api:
# 容器名称
image: dabolau/api:latest
# 端口[宿主机:容器]
ports:
- "3000:3000"
# 容器网络
networks:
- mongo-network
environment:
- MONGO_ADDRESS=mongo:27017
- MONGO_USERNAME=username
- MONGO_PASSWORD=password
# 容器服务
mongo:
# 容器名称
image: mongo:latest
# 端口[宿主机:容器]
ports:
- "27017:27017"
# 容器网络
networks:
- mongo-network
# 环境变量
environment:
- MONGO_INITDB_ROOT_USERNAME=username
- MONGO_INITDB_ROOT_PASSWORD=password
# 数据卷[宿主机:容器]
volumes:
- mongo-config:/data/configdb
- mongo-data:/data/db
# 容器服务
mongo-express:
# 容器名称
image: mongo-express:latest
# 端口[宿主机:容器]
ports:
- "8081:8081"
# 容器网络
networks:
- mongo-network
# 环境变量
environment:
- ME_CONFIG_MONGODB_SERVER=mongo
- ME_CONFIG_MONGODB_ADMINUSERNAME=username
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
# 数据卷
volumes:
# 命名数据卷名称与上面容器的宿主机数据卷名称一致
mongo-config:
mongo-data: # 容器网络
networks:
# 命名网络名称与上面容器的网络名称一致
mongo-network:
注意:当docker-compose.yaml
运行时会自动创建网络mongo-network
供三个容器网络通信,创建数据卷mongo-config
和mongo-data
分别持久化存放数据库的配置文件和数据文件,持久化数据放在/var/lib/docker/volumes
目录下
运行容器
sudo docker-compose up -d
停止容器
sudo docker-compose down
容器数据持久化存储卷
名称 | 地址 |
---|---|
官方数据卷说明 | https://docs.docker.com/storage/ |
常见容器中数据库数据卷的默认路径
其它数据库的默认路径请在docker hub
中查看帮助文档
数据库名称 | 数据库容器中的路径 |
---|---|
mongo | /data/db |
mysql | /var/lib/mysql |
postgres | /var/lib/postgresql/data |
在各平台下数据卷的默认路径
数据卷在不同操作系统下路径不同,持久化存储的数据就存放在不同操作系统的对应目录中
名称 | 路径 |
---|---|
windows | c:\ProgramData\docker\volumes |
linux | /var/lib/docker/volumes |
mac | /var/lib/docker/volumes |
苹果系统下找不到数据卷路径的解决办法
在mac
系统中找不到/var/lib/docker/volumes
目录时需要先挂载数据卷运行ubuntu
容器,挂载的数据就存放在这个ubuntu
容器中的/var/lib/docker/volumes
目录下
docker run -v mongo-data:/data/db --name ubuntu -it ubuntu
当再次查看数据卷内容时,需要重新启动ubuntu
容器
docker start ubuntu
再进入终端查看/var/lib/docker/volumes
目录下的数据
docker exec -it ubuntu /bin/bash
容器的基础网络
名称 | 地址 |
---|---|
官方网络说明 | https://docs.docker.com/network/ |
容器网络简单说明
网络名称 | 网络相关说明 |
---|---|
bridge | 网桥网络,虚拟网络与宿主机通信,容器中默认的网络 |
host | 主机网络,与宿主机共用网络,需注意端口冲突 |
none | 没有网络,与外界完全隔离,用于安全性较高的场景 |