Docker 使用指南

174 阅读10分钟

开源应用容器引擎使用指南(Docker usage guide)

概述

Docker是一个用于开发、发布和运行应用程序的开放平台。Docker使您能够将应用程序与基础架构分离,以便您可以快速交付软件。使用Docker,您可以像管理应用程序一样管理基础架构。通过利用Docker的快速发布、测试和部署代码的方法,您可以显著减少编写代码和在生产环境中运行代码之间的延迟。

官方网站

名称地址
官方网站www.docker.com/

卸载程序

如果你安装了旧版本的dockerdocker.iodocker-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程序

系统地址
Windowsdocs.docker.com/desktop/win…
Macdocs.docker.com/desktop/mac…
Linuxdocs.docker.com/engine/inst…

设置国内镜像加速源

添加国内镜像加速源

  • 如果/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

其它国内镜像加速源

服务器地址
中国官方镜像registry.docker-cn.com
科大镜像docker.mirrors.ustc.edu.cn
网易镜像hub-mirror.c.163.com
腾讯镜像mirror.ccs.tencentyun.com

拉取多个镜像并在同一网络中通信运行容器

通过拉取mongomongo-express镜像,并在创建的同一网络mongo-network中分别运行mongomongo-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

注意:在配置文件中我们并没有为mongomongo-express容器指定同一网络,它会自动创建默认的网络来进行容器间的通信和默认数据卷来持久化数据

运行容器

sudo docker-compose up -d

停止容器

sudo docker-compose down

指令说明

名称地址
官方指令说明docs.docker.com/compose/com…
官方指令格式的版本说明docs.docker.com/compose/com…
指令说明
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

指令说明

名称地址
官方指令说明docs.docker.com/engine/refe…
指令说明
FROM指定所创建镜像的基础镜像
RUN运行命令
CMD指定容器启动时默认执行的命令
LABEL指定生成镜像的元数据标签信息
MAINTAINER镜像维护者信息(弃用)
EXPOSE声明镜像内服务所监听的端口
ENV指定环境变量
ADD复制内容到镜像中并解压缩内容
COPY复制内容到镜像中(官方推荐)
ENTRYPOINT指定镜像的默认入口命令
VOLUME创建数据卷挂载点
USER设置容器启动的登录用户
WORKDIR设置工作目录
ARG指定镜像内使用的参数
ONBUILD创建子镜像时指定自动执行的操作指令
STOPSIGNAL容器退出的信号值
HEALTHCHECK设置所启动容器如何进行健康检查
SHELL指定默认 shell 类型

推送镜像到远程仓库 Docker Hub

创建远程仓库

名称地址
容器官方镜像仓库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-configmongo-data分别持久化存放数据库的配置文件和数据文件,持久化数据放在/var/lib/docker/volumes目录下

运行容器

sudo docker-compose up -d

停止容器

sudo docker-compose down

容器数据持久化存储卷

名称地址
官方数据卷说明docs.docker.com/storage/

常见容器中数据库数据卷的默认路径

其它数据库的默认路径请在docker hub中查看帮助文档

数据库名称数据库容器中的路径
mongo/data/db
mysql/var/lib/mysql
postgres/var/lib/postgresql/data

在各平台下数据卷的默认路径

数据卷在不同操作系统下路径不同,持久化存储的数据就存放在不同操作系统的对应目录中

名称路径
windowsc:\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

容器的基础网络

名称地址
官方网络说明docs.docker.com/network/

容器网络简单说明

网络名称网络相关说明
bridge网桥网络,虚拟网络与宿主机通信,容器中默认的网络
host主机网络,与宿主机共用网络,需注意端口冲突
none没有网络,与外界完全隔离,用于安全性较高的场景