为什么要学习 Docker ?

每学一个东西,我们肯定是基于某个需求去学习的,众所周知,软件开发最麻烦的是环境配置,开发好好的,部署出问题就很难受,所以为了确保开发、测试、部署环境一致,且高效的部署所以选择了容器技术而非 VM ,而 Docker 是基于 Linux 容器技术的开源项目,它的口头禅就是:“一次构建,处处运行”,具有轻量,速度,社区活跃,且拓展性高

安装

点我进入官网安装
Docker 支持 Linux、Mac、 Window,直接去官网下载安装就行了

快速开始

学习新的技术都需要一个 Hello World,让我们快速开始体验一下 Docker
直接进入终端开始吧!

# 拉取nginx镜像
docker pull nginx
# 创建一个nginx容器
docker run -d --name test-nginx -p 3000:80 nginx

然后打开 localhost:3000 即可访问到熟悉的 nginx 页面了

是不是非常简单?那我们接下来具体说一说 Docker 的组成

镜像 image

镜像是一个二进制文件,里面具有应用程序以及依赖,只有通过它,Docker 才能够生成容器,相当于模具一样,同一个镜像文件可以生成多个容器实例

对于如何制作镜像,一般来说我们都是通过加工别人基础镜像来生成我们自己的镜像,而不是从零开始,而且我们也可以在这里共享我们的镜像,这也是我们选择它的理由之一,我们可以享受社区的贡献

镜像常用的命令

# 列出本机的所有 image 文件。
$ docker image ls
# 拉取镜像
$ docker pull [imageName]
# 删除 image 文件
$ docker image rm [imageName]

用 Dockerfile 构建一个镜像

在前面我们已经使用过nginx的镜像了,这次我们尝试用 Dockerfile 构建一个自己的镜像
新建一个 docker-test 文件夹,在里面新建一个index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello World</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

然后新建一个 Dockerfile 文件

# 声明基于 nginx 最新的镜像 这里说一下镜像名:后面的是标签 默认是latest
FROM nginx:latest
# 把刚才 index.html 复制到 nginx 的 html 路径去
COPY index.html /usr/share/nginx/html/index.html
# 声明暴露80端口
EXPOSE 80

运行命令

#  生成一个名为 nginx 标签为0.0.1 的镜像 ,注意最后还有一个 .
docker image build -t nginx:0.0.1 .
# 根据刚生成的镜像 启动容器
docker run -d --name test-nginx1 -p 3001:80 nginx:0.0.1

这时候再次访问 locahost:3001 已经不是默认的 nginx 的访问页面了
这里解释一下参数

  • -p 参数是指容器的 80 端口映射到本机的 3001 端口
  • -d 守护式运行(适合运行应用程序和服务)
  • --name  容器名称 如果不指定则是一个随机的名称

容器 container

容器常用的命令

# 查看正在运行的容器
docker ps
# 查看所有创建过的容器(运行或者关闭)
docker ps -a
# 停止容器
docker stop [container]
# 启动容器
docker start [container]
# 删除容器
docker rm [container]
# 查看后台运行的日志
docker logs [containe]

可以先用这些容器命令操作一下我们之前创建的容器,尝试一下
那么在上一节我们自己构建了一个镜像代替了 nginx 的默认页面,那如果我们还想改怎么办?除了新构建一个镜像之外,我们还可以直接进入容器里进行修改

docker container exec -it [containe] /bin/bash

这样就进去了容器的 shell ,可以随意进行操作,当然就算你误操作比如运行了经典的了,也没有关系
在这里我们是使用了 -it 这个参数 它和 -d 区别就在于
-d => 使用 pm2  start index.js
-it => 使用 node.js
当然,真正开发的时候,肯定不可能是这样去修改了,好比之前的端口映射,也可以将容器的内部的目录也映射出来实现共共享,这就是接下来要说的 Volume

数据卷 Volume

回到我们 docker-test 文件夹,然后重新启动一个nginx容器(这里使用的端口和容器名与快速开始的创建的容器相同,请同学们复习一下容器命令先自行删除再创建)

docker run -d --name test-nginx -v $PWD/index.html:/usr/share/nginx/html/index.html -p 3000:80  nginx

我们打开 locahost:3000 修改一下 index.html 的内容为 Hello Volume ,刷新一下网页即可看到我们修改的内容
在这里
很容易发现我们和之前的区别就是使用了 -v参数  本地路径:容器路径 通过这样进行映射,这样当我们修改本地的文件的时候就等于修改了容器内的文件
那么就当在一个项目中,nginx部署好了前端,那么我们需要一个服务提供数据,在 docker-test 的文件夹下面
创建一个 mysql 文件夹 在mysql文件夹中创建一个data存储数据,创建一个my.cnf用作配置

[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000 [client]
default-character-set=utf8 [mysql]
default-character-set=utf8

启动容器

docker run --name test-mysql -it -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -v $PWD/mysql/my.cnf:/etc/mysql/my.cnf -v $PWD/mysql/data:/var/lib/mysql -d mysql

然后我们通过上一节学会的命令进入 test-mysql 容器中创建数据库以及创建表 加插入一条数据

docker container exec -it test-mysql /bin/bash
# 下面是 test-mysql 容器中的 shell
# 登陆 输入密码
mysql -u root -p
# 创建数据库 test
create databse test;
# 进入 test 数据库
use test;
# 进入 PEOPLE 数据表 字段为 name age
Create Table PEOPLE (name VARCHAR(20), age CHAR(20));
# 插入一行数据到 PEOPLE
Insert into PEOPLE Values('kdq', '24')

然后我们退出容器,再 docker-test 下创建一个文件夹 node ,并创建一个 index.js 文件

const http = require("http");
const mysql = require("mysql");
const connection = mysql.createConnection({
host: "test-mysql",
user: "root",
password: "root",
database: "test"
});
connection.connect(); const server = http.createServer().listen(3001); server.on("request", (req, res) => {
if (/testapi/.test(req.url)) {
try {
var sqlstr = "Select * From PEOPLE";
connection.query(sqlstr, function(err, result) {
if (err) {
console.log("SELECT ", err.message);
return;
}
res.end(JSON.stringify(result));
});
} catch (error) {
res.end("404 not found");
}
} else {
res.end("404 not found");
}
});

然后启动容器

docker run -it --name test-node -v $PWD/node:/var/www/node  -v $PWD/mysql/data:/var/lib/mysql -p 3001:3001 node /bin/bash
# 下面是 test-node 容器中的 shell
cd /var/www/node
node index.js

我们发现 mysql 的操作报错了 connect ECONNREFUSED 127.0.0.1:3306 ,原来是因为我们的 mysql 和 node 是两个容器,而容器是相互隔离的,无法 ping 通

那么难道我们得把 mysql 和 node 都得部署在一个容器里?其实 Docker 更建议一个容器做一件事情,而这种理念其实在我们的开发中也是随处可见的,所以 Docker 可以使用 Networking 进行通信

网络 Networking

首先创建一个网络

docker network create test-net

然后把上一节启动 test-mysql 和 test-node 的容器的命令改成

# test-mysql
docker run --name test-mysql -it -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -v $PWD/mysql:/etc/mysql --network test-net -d mysql
# test-node
docker run -it --name test-node -v $PWD/node:/var/www/node --network test-net -p 3001:3001 node /bin/bash

这时候我们在 node 的 index.js 中修改一下连接 mysql 的 host

const connection = mysql.createConnection({
host: "test-mysql",
user: "root",
password: "root",
database: "test"
});

然后我们启动一下 node 服务 访问 localhost:3001/testapi 就能看到我们查询到的数据了
那么我们也可以将 nginx 加入 test-net 网络中互相通信,具体就留给你们自己去做了

组合 docker-compose

经过上一节我们发现启动容器要输入这么多参数,而且多个容器服务就要启动多次,不仅繁琐,还容易出错
我们可以写 Dockerfile 写一层层命令来构建镜像,是不是也可以用一个配置去启动容器?
答案是可以的,这时候就需要 docker-compose ,当然,如果你的 docker 安装的时候自带就不用再次安装了,具体可以观看文档 点我下载
安装之后 在我们的 docker-test 文件夹下新建一个 docker-compose.yml

version: "3.7"
services:
test-mysql:
image: mysql
volumes:
- ./mysql/my.cnf:/etc/mysql/my.cnf
- ./mysql/data:/var/lib/mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=root
networks:
- test-net
test-node:
image: node
volumes:
- ./node:/var/www/node
ports:
- 3001:3001
command:
- /bin/bash
- -c
- |
cd /var/www/node
node index.js
tail -f /dev/null
networks:
- test-net
depends_on:
- test-mysql
test-nginx:
image: nginx
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/index.html:/usr/share/nginx/html/index.html
ports:
- 3000:80
networks:
- test-net
depends_on:
- test-node
networks:
test-net:
driver: bridge

目前的 docker-test 情况

|-- mysql
|-- data
|-- my.cnf
|-- nginx
|-- index.html
|-- nginx.conf
|-- node
|-- node_modules
|-- index.js
|-- package.json
|-- package-lock.json
|-- docker-compose.yml

通过 docker-compose 启动容器(先把之前启动的三个容器关了)

docker-compose up -d

打开 localhost:3001/testapi 发现依然查询到了数据,就这样一个简单的项目环境准备好了

总结

简单的介绍一下如何使用Docker以及基本的命令,相信大家已经对 Docker 有所了解,对于相关配置想知道更多的可以查看官网文档,如果想看书的同学,可以看第一本Docker书

前端 Docker 基本教程的更多相关文章

  1. [转帖]Docker 入门教程

    Docker 入门教程 http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html 自己学的还是太肤浅啊.. 作者: 阮一峰 日期: 201 ...

  2. Docker简明教程

    Docker简明教程 [编者的话]使用Docker来写代码更高效并能有效提升自己的技能.Docker能打包你的开发环境,消除包的依赖冲突,并通过集装箱式的应用来减少开发时间和学习时间. Docker作 ...

  3. Docker入门教程(九)10个镜像相关的API

    Docker入门教程(九)10个镜像相关的API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第九篇,重点介绍了镜像相关的Docker Remote ...

  4. Docker入门教程(八)Docker Remote API

    Docker入门教程(八)Docker Remote API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第八篇,重点介绍了Docker Remote ...

  5. Docker入门教程(七)Docker API

    Docker入门教程(七)Docker API [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第七篇,重点介绍了Docker Registry API和 ...

  6. Docker入门教程(六)另外的15个Docker命令

    Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...

  7. Docker入门教程(五)Docker安全

    Docker入门教程(五)Docker安全 [编者的话]DockOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第五篇,介绍了Docker的安全问题,依然是老话重谈,入门者可以通 ...

  8. Docker入门教程(四)Docker Registry

    Docker入门教程(四)Docker Registry [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第四篇,介绍了Docker Registry,它 ...

  9. Docker入门教程(三)Dockerfile

    Docker入门教程(三)Dockerfile [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第三篇,介绍了Dockerfile的语法,DockerOn ...

随机推荐

  1. Manipulating Data from Oracle Object Storage to ADW with Oracle Data Integrator (ODI)

    0. Introduction and Prerequisites This article presents an overview on how to use Oracle Data Integr ...

  2. 管理2000+Docker镜像,Kolla是如何做到的

    根据 DockerHub 上的数据,整个 Kolla 项目管理的 镜像有 2000 多个,这么多的镜像,是怎么定义,又是如何构建的呢? 简介 我们一直在说的 Kolla,通常情况下泛指,包括了 Kol ...

  3. 微服务的多数据源配置: step 1

    spring boot + mybatis: 实现的功能点: 多数据源 jdbc: spring.datasource.test1.url = jdbc:mysql://localhost:3306/ ...

  4. robotframework,移动端(小程序)自动化,获取元素属性值的方法

    如下图,获取商品价格 属性值显示在content-desc内 传统的get text指定是无法获得到这个元素指定属性的值的 只有通过使用AppiumLibrary.get element attrib ...

  5. python读取json文件

    比如下图json数据,场景需要读取出wxid这项数据,然后传给后面的函数去使用 具体的脚本为 import json f =open('d:\\1024.json',encoding='utf-8') ...

  6. Map梳理

    Map梳理 类型介绍 通用Map:用于在应用程序中管理映射,通常在 java.util 程序包中实现 HashMap.Hashtable.Properties.LinkedHashMap.Identi ...

  7. [C语言学习笔记二] extern 函数的用法

    extern 用来定义一个或多个变量.其后跟数据类型名和初始值.例如: extern int a =10 它与 int,long long int,double,char的本质区别,在于 extern ...

  8. C语言系列之自增自减运算符的用法(二)

    运算符中最难理解的有自增自减运算符的使用方法,下面我将简单总结一下他们的使用方法 我们知道,C语言运行是由右向左运行的 下面我们来看一个例子 当i等于3的时候 j=++i; 由上面可知,C语言是由右向 ...

  9. ros中坐标系管理系统

    首先安装小海龟实例的功能包ros-melodic-turtle-tf  qqtsj  ~  sudo apt install ros-melodic-turtle-tf [sudo] qqtsj ...

  10. vue简介,插值表达式,过滤器

    目录 VUE框架介绍 what?什么是vue? why?为什么要学习vue? special特点? how如何使用? 下载安装? 导入方式? 挂在点el 插值表达式 delimiters自定义插值表达 ...