提交 2e18a40c 编写于 作者: J jackfrued

更新了部分文档和代码

上级 5bf23a29
<!--
HTML - 超文本标记语言 - 可以在浏览器中运行出网页的编程语言
1. 标签 - 承载网页上显示的内容
2. 层叠样式表 - 负责网页的显示
3. JavaScript - 负责交互行为
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>垃圾分类查询助手</title>
<!--
0. 可回收物(如:玻璃类、牛奶盒、金属类、塑料类、废纸类、织物类)
1. 有害垃圾(如:废电池、废墨盒、废油漆桶、过期药品、废灯管、杀虫剂)
2. 厨余垃圾(如:骨骼内脏、菜梗菜叶、果皮、茶叶渣、残枝落叶、剩菜剩饭)
3. 其他垃圾(如:宠物粪便、烟头、污染纸张、破旧陶瓷品、灰土、一次性餐具)
-->
<!-- 层叠样式表 -->
<style>
.search, .result {
width: 720px;
margin: 50px auto;
}
.search > input {
width: 520px;
border: none;
outline: none;
text-align: center;
font-size: 36px;
line-height: 36px;
border-bottom: 1px solid gray;
margin: 0 20px;
}
.search button {
background-color: red;
color: white;
font-size: 28px;
border: none;
outline: none;
width: 120px;
}
.result > p, .result > div {
width: 640px;
margin: 0 auto;
}
.result > p, .result span {
text-align: left;
font-size: 28px;
}
.result img {
vertical-align: middle;
}
.explain {
font-size: 12px;
color: darkgray;
}
.result .pre {
font-size: 16px;
}
</style>
</head>
<body>
<!-- div 是代表一个逻辑区域的块标签 -->
<div id="app">
<div class="search">
<!-- type属性是text的input标签代表文本框 可以接收用户输入 -->
<!-- placeholder是文本框的输入提示 -->
<input type="text" placeholder="请输入垃圾名字" v-model="word" @keydown.enter="search()">
<!-- button代表按钮 点击可以开始查询 -->
<button @click="search()">查询</button>
</div>
<div class="result">
<!-- p代表一个段落 -->
<p v-if="searched && !results">没有对应的查询结果</p>
<div v-for="result in results">
<p>
<!-- img是图像标签 可以用来实现图片-->
<img :src="pictures[result.type]" width="56" :alt="types[result.type]">
&nbsp;&nbsp;
<!-- span是跨度标签 代表一个逻辑区域(不分段)-->
<span>{{ result.name }}</span>
&nbsp;&nbsp;
<span class="pre" v-if="result.aipre == 1">(预测结果)</span>
</p>
<p class="explain">说明:{{ result.explain }}</p>
</div>
</div>
</div>
<!-- JavaScript代码 可以负责在用户点击查询按钮时联网获取垃圾分类结果 -->
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
word: '',
searched: false,
types: ['可回收物', '有害垃圾', '厨余垃圾', '其他垃圾'],
pictures: ['recyclable.png', 'harmful-waste.png', 'kitchen-waste.png', 'other-waste.png'],
results: []
},
methods: {
// 查询垃圾分类的函数
search() {
if (this.word.trim().length > 0) {
let key = '9aeb28ee8858a167c1755f856f830e22'
let url = `http://api.tianapi.com/txapi/lajifenlei/?key=${key}&word=${this.word}`
fetch(url)
.then(resp => resp.json())
.then(json => {
// 处理返回的JSON格式数据
this.searched = true
this.results = json.newslist
})
}
}
}
})
</script>
</body>
</html>
\ No newline at end of file
## Docker在项目中的应用
### Docker简介
软件开发中最为麻烦的事情可能就是配置环境了。由于用户使用的操作系统具有多样性,即便使用跨平台的开发语言(如Java和Python)都不能保证代码能够在各种平台下都可以正常的运转,而且在不同的环境下我们安装的软件需要依赖的软件包也是不一样的。
那么问题来了,我们安装软件的时候可不可以把软件运行的环境一并安装?我们是不是可以把原始环境一模一样地复制过来呢?
虚拟机(virtual machine)就是带环境安装的一种解决方案,它可以在一种操作系统里面运行另一种操作系统,比如在Windows系统里面运行Linux系统,在macOS上运行Windows,而应用程序对此毫无感知。使用过虚拟机的人都知道,虚拟机用起来跟真实系统一模一样,而对于虚拟机的宿主系统来说,虚拟机就是一个普通文件,不需要了就删掉,对宿主系统或者其他的程序并没有影响。但是虚拟机通常会占用较多的系统资源,启动和关闭也非常的缓慢,总之用户体验并没有想象中的那么好。
Docker属于对Linux容器技术的一种封装(利用了Linux的namespace和cgroup技术),它提供了简单易用的容器使用接口,是目前最流行的 Linux 容器解决方案。Docker将应用程序与该程序的依赖打包在一个文件里面,运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。
![](./res/docker_vs_vm.png)
目前,Docker主要用于几下几个方面:
1. 提供一次性的环境。
2. 提供弹性的云服务(利用Docker很容易实现扩容和收缩)。
3. 实践微服务架构(隔离真实环境在容器中运行多个服务)。
### 安装Docker
下面的讲解以CentOS为例,使用[Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)[macOS](https://docs.docker.com/docker-for-mac/install/)[Windows](https://docs.docker.com/docker-for-windows/install/)的用户可以通过点击链接了解这些平台下如何安装和使用Docker。
0. 确定操作系统内核版本(CentOS 7要求64位,内核版本3.10+;CentOS 6要求64位,内核版本2.6+)。
```Shell
uname -r
```
1. 在CentOS下使用yum安装Docker并启动。
```Shell
yum -y install docker
systemctl start docker
```
2. 检视Docker的信息和版本。
```Shell
docker version
docker info
```
3. 下载镜像文件。
```Shell
docker pull <name>
```
例如:`docker pull hello-world`
4. 运行镜像文件。
```Shell
docker run <image-id>
```
例如:`docker run hello-world`
5. 查看镜像文件。
```Shell
docker image ls
docker images
```
6. 删除镜像文件。
```Shell
docker rmi <name>
```
例如:`docker rmi fce289e99eb9`
7. 查看正在运行容器。
```Shell
docker ps
```
8. 停止运行的容器。
```Shell
docker stop <container-id>
docker stop <name>
```
例如:`docker stop hello-world`
对于那些不会自动终止的容器,就可以用下面的方式来停止。
```Shell
docker container kill <container-id>
```
如果要在Ubuntu(内核版本3.10+)下面安装和启动Docker,可以按照如下的步骤进行。
```Shell
apt update
apt install docker-ce
service docker start
```
如果需要,可以更换Ubuntu软件下载源来提升下载速度,具体请参照清华大学开源软件镜像站上的[《Ubuntu镜像使用帮助》](<https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/>)
安装Docker后,由于直接访问dockerhub下载镜像会非常缓慢,建议更换国内镜像,可以通过修改 `/etc/docker/daemon.js` 文件来做到。云服务器(如:阿里云)通常已经设置了默认的镜像服务器,并不需要手动进行指定。
```JavaScript
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
]
}
```
### 使用Docker
#### 安装Nginx
下面我们就基于Docker来创建一台HTTP服务器,我们选择用Nginx来搭建该服务,因为Nginx是高性能的Web服务器,同时也是做反向代理服务器的上佳选择。要做到这件事情,只需要使用下面的命令在Docker中创建一个容器即可。
```Shell
docker container run -d -p 80:80 --rm --name mynginx nginx
```
> 说明:上面的参数`-d`表示容器在后台运行(不产生输出到Shell)并显示容器的ID;`-p`是用来映射容器的端口到宿主机的端口;`--rm`表示容器停止后自动删除容器,例如通过`docker container stop mynginx`以后,容器就没有了;`—name`后面的mynginx就是自定义容器的名字。在创建容器的过程中,需要用到nginx的镜像文件,镜像文件的下载是自动完成的,如果没有指定版本号,默认是最新版本(latest)。
如果需要将自己的Web项目(页面)部署到Nginx上,可以使用容器拷贝命令将指定路径下所有的文件和文件夹拷贝到容器的指定目录中。
```Shell
docker container cp /root/web/index.html mynginx:/usr/share/nginx/html
```
如果不愿意拷贝文件也可以在创建容器时通过数据卷操作`--volume`将指定的文件夹映射到容器的某个目录中,例如将Web项目的文件夹直接映射到`/usr/share/nginx/html`目录。
```Shell
docker container run -d -p 80:80 --rm --name mynginx --volume $PWD/html:/usr/share/nginx/html nginx
```
> 说明:上面创建容器和拷贝文件的命令中,`container`是可以省略的,也就是说`docker container run`和`docker run`是一样的,而`docker container cp`和`docker cp`是一样的。此外,命令中的`--volume`也可以缩写为`-v`,就如同`-d`是`--detach`的缩写,`-p`是`--publish`的缩写。`$PWD`代表宿主系统当前文件夹,这些对于用过Linux系统的人来说相信很容易理解。
要查看运行中的容器,可以使用下面的命令。
```Shell
docker ps
```
要让刚才创建的容器停下来,可以使用下面的命令。
```Shell
docker stop mynginx
```
由于在创建容器时使用了`--rm`选项,容器在停止时会被移除,当我们使用下面的命令查看所有容器时,应该已经看不到刚才的`mynginx`容器了。
```Shell
docker container ls -a
```
如果在创建容器时没有指定`--rm`选项,那么也可以使用下面的命令来删除容器。
```Shell
docker rm mynginx
```
#### 安装MySQL
我们可以先检查一下服务器上有没有MySQL的镜像文件。
```Shell
docker search mysql
```
下载MySQL镜像并指定镜像的版本号。
```Shell
docker pull mysql:5.7
```
如果需要查看已经下载的镜像文件,可以使用下面的命令。
```Shell
docker images
```
创建并运行MySQL容器。
```Shell
docker run -d -p 3306:3306 --name mysql57 -v $PWD/mysql/conf:/etc/mysql/mysql.cnf.d -v $PWD/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
```
注意,上面创建容器时我们又一次使用了数据卷操作,那是因为通常容器是随时创建随时删除的,而数据库中的数据却是需要保留下来的,所以上面的两个数据卷操作一个是映射了MySQL配置文件所在的文件夹,一个是映射了MySQL数据所在的文件夹,这里的数据卷操作非常重要。我们可以将MySQL的配置文件放在`$PWD/mysql/conf`目录下,配置文件的具体内容如下所示:
```INI
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
log-error=/var/log/mysql/error.log
server-id=1
log-bin=/var/log/mysql/mysql-bin.log
expire_logs_days=30
max_binlog_size=256M
symbolic-links=0
```
如果安装了MySQL 8.x版本(目前的最新版本),在使用客户端工具连接服务器时可能会遇到“error 2059: Authentication plugin 'caching_sha2_password' cannot be loaded”的问题,这是因为MySQL 8.x默认使用了名为“caching_sha2_password”的机制对用户口令进行了更好的保护,但是如果客户端工具不支持新的认证方式,连接就会失败。解决这个问题有两种方式:一是升级客户端工具来支持MySQL 8.x的认证方式;二是进入容器,修改MySQL的用户口令认证方式。下面是具体的步骤,我们先用`docker exec`命令进入容器的交互式环境,假设运行MySQL 8.x的容器名字叫`mysql8x`
```Shell
docker exec -it mysql8x /bin/bash
```
进入容器的交互式Shell之后,可以首先利用MySQL的客户端工具连接MySQL服务器。
```Shell
mysql -u root -p
Enter password:
Your MySQL connection id is 16
Server version: 8.0.12 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
```
接下来通过SQL来修改用户口令就可以了。
```SQL
alter user 'root'@'%' identified with mysql_native_password by '123456' password expire never;
```
当然,如果愿意你也可以查看一下用户表检查是否修改成功。
```SQL
use mysql;
select user, host, plugin, authentication_string from user where user='root';
+------+-----------+-----------------------+-------------------------------------------+
| user | host | plugin | authentication_string |
+------+-----------+-----------------------+-------------------------------------------+
| root | % | mysql_native_password | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| root | localhost | mysql_native_password | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+------+-----------+-----------------------+-------------------------------------------+
2 rows in set (0.00 sec)
```
在完成上面的步骤后,现在即便不更新客户端工具也可以连接MySQL 8.x了。
## 使用Docker部署服务
### Docker简介
软件开发中最为麻烦的事情可能就是配置环境了。由于用户使用的操作系统具有多样性,即便使用跨平台的开发语言(如Java和Python)都不能保证代码能够在各种平台下都可以正常的运转,而且在不同的环境下我们安装的软件需要依赖的软件包也是不一样的。
那么问题来了,我们安装软件的时候可不可以把软件运行的环境一并安装?我们是不是可以把原始环境一模一样地复制过来呢?
虚拟机(virtual machine)就是带环境安装的一种解决方案,它可以在一种操作系统里面运行另一种操作系统,比如在Windows系统里面运行Linux系统,在macOS上运行Windows,而应用程序对此毫无感知。使用过虚拟机的人都知道,虚拟机用起来跟真实系统一模一样,而对于虚拟机的宿主系统来说,虚拟机就是一个普通文件,不需要了就删掉,对宿主系统或者其他的程序并没有影响。但是虚拟机通常会占用较多的系统资源,启动和关闭也非常的缓慢,总之用户体验并没有想象中的那么好。
Docker属于对Linux容器技术的一种封装(利用了Linux的namespace和cgroup技术),它提供了简单易用的容器使用接口,是目前最流行的 Linux 容器解决方案。Docker将应用程序与该程序的依赖打包在一个文件里面,运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。下图是虚拟机和容器的对比,左边是传统的虚拟机,右边是Docker。
![](./res/docker_vs_vm.png)
目前,Docker主要用于几下几个方面:
1. 提供一次性的环境。
2. 提供弹性的云服务(利用Docker很容易实现扩容和收缩)。
3. 实践微服务架构(隔离真实环境在容器中运行多个服务)。
### 安装Docker
下面以CentOS为例讲解如何安装Docker,使用[Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)[macOS](https://docs.docker.com/docker-for-mac/install/)[Windows](https://docs.docker.com/docker-for-windows/install/)的用户可以通过点击对应的链接了解这些平台下如何进行安装。
1. 确定操作系统内核版本(CentOS 7要求64位,内核版本3.10+;CentOS 6要求64位,内核版本2.6+),可以通过下面的命令确定Linux系统内核版本。
```Shell
uname -r
```
2. 在CentOS下使用yum安装Docker并启动。
```Shell
yum -y install docker
systemctl start docker
```
3. 查看Docker的信息和版本。
```Shell
docker version
docker info
```
接下来可以通过下载镜像和创建容器来看看Docker是否可以运转起来。可以使用下面的命令从Docker的镜像仓库下载名为hello-world的镜像文件。
```Shell
docker pull hello-world
```
查看所有镜像文件。
```Shell
docker images
```
```
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/hello-world latest fce289e99eb9 7 months ago 1.84 kB
```
通过镜像文件创建并运行容器。
```Shell
docker container run --name mycontainer hello-world
```
> 说明:其中`mycontainer`是我们给容器起的名字,跟在`--name`参数之后;`hello-world`就是我们刚才下载的镜像文件。
```
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
如果要删除这个容器,可以使用下面的命令。
```Shell
docker container rm mycontainer
```
在删除容器之后,我们还可以删除刚才下载的镜像文件。
```Shell
docker rmi hello-world
```
> 说明:如果要在Ubuntu(内核版本3.10+)下面安装和启动Docker,可以按照如下的步骤进行。
>
> ```Shell
> apt update
> apt install docker-ce
> service docker start
> ```
>
> 国内用户可以通过更换Ubuntu软件下载源来提升下载速度,具体请参照清华大学开源软件镜像站上的[《Ubuntu镜像使用帮助》](<https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/>)。
安装Docker后,由于直接访问[dockerhub](https://hub.docker.com/)下载镜像会非常缓慢,建议将服务器更换为国内镜像,可以通过修改 `/etc/docker/daemon.js` 文件来做到。
```JavaScript
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
]
}
```
### 使用Docker
#### 安装Nginx
下面我们就基于Docker来创建一台HTTP服务器,我们选择用Nginx来搭建该服务,因为Nginx是高性能的Web服务器,同时也是做反向代理服务器的上佳选择。要做到这件事情,只需要使用下面的命令在Docker中创建一个容器即可。
```Shell
docker container run -d -p 80:80 --rm --name mynginx nginx
```
> 说明:上面的参数`-d`表示容器在后台运行(不产生输出到Shell)并显示容器的ID;`-p`是用来映射容器的端口到宿主机的端口,冒号前面是宿主机的端口,冒号后面是容器内部使用的端口;`--rm`表示容器停止后自动删除容器,例如执行命令`docker container stop mynginx`后,容器就不复存在了;`--name`后面的mynginx是自定义的容器名字;在创建容器的过程中,需要用到nginx的镜像文件,镜像文件的下载是自动完成的,如果没有指定版本号,默认是最新版本(latest)。
如果需要将自己的Web项目(页面)部署到Nginx上,可以使用容器拷贝命令将指定路径下所有的文件和文件夹拷贝到容器的指定目录中。
```Shell
docker container cp /root/web/index.html mynginx:/usr/share/nginx/html
```
如果不愿意拷贝文件也可以在创建容器时通过数据卷操作`--volume`将指定的文件夹映射到容器的某个目录中,例如将Web项目的文件夹直接映射到`/usr/share/nginx/html`目录。我们先通过下面的命令让刚才创建的容器停止运行。
```Shell
docker container stop mynginx
```
然后用下面的命令重新创建容器。
```Shell
docker container run -d -p 80:80 --rm --name mynginx --volume $PWD/html:/usr/share/nginx/html nginx
```
> 说明:上面创建容器和拷贝文件的命令中,`container`是可以省略的,也就是说`docker container run`和`docker run`是一样的,而`docker container cp`和`docker cp`是一样的。此外,命令中的`--volume`也可以缩写为`-v`,就如同`-d`是`--detach`的缩写,`-p`是`--publish`的缩写。`$PWD`代表宿主系统当前文件夹,这些对于使用过Unix或者Linux系统的人来说,应该是很容易理解的。
要查看运行中的容器,可以使用下面的命令。
```Shell
docker ps
```
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c38d2476384 nginx "nginx -g 'daemon ..." 4 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp mynginx
```
要启动和停止容器,可以使用下面的命令。
```Shell
docker start mynginx
docker stop mynginx
```
由于在创建容器时使用了`--rm`选项,容器在停止时会被移除,当我们使用下面的命令查看所有容器时,应该已经看不到刚才的`mynginx`容器了。
```Shell
docker container ls -a
```
如果在创建容器时没有指定`--rm`选项,那么也可以使用下面的命令来删除容器。
```Shell
docker rm mynginx
```
要删除正在运行中的容器,需要使用`-f`选项。
```Shell
docker rm -f mynginx
```
#### 安装MySQL
我们再来尝试用Docker安装一台MySQL服务器,首先可以先检查一下有没有MySQL的镜像文件。
```Shell
docker search mysql
```
```
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/mysql MySQL is a ... 8486 [OK]
...
```
> 说明:上面查询结果的列依次代表索引、镜像名、镜像描述、用户评价、是否官方镜像、自动构建。
下载MySQL镜像并指定镜像的版本号。
```Shell
docker pull mysql:5.7
```
如果需要查看已经下载的镜像文件,可以使用下面的命令。
```Shell
docker images
```
```
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest e445ab08b2be 2 weeks ago 126 MB
docker.io/mysql 5.7 f6509bac4980 3 weeks ago 373 MB
```
创建并运行MySQL容器。
```Shell
docker run -d -p 3306:3306 --name mysql57 -v $PWD/mysql/conf:/etc/mysql/mysql.cnf.d -v $PWD/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
```
注意,上面创建容器时我们又一次使用了数据卷操作,那是因为通常容器是随时创建随时删除的,而数据库中的数据却是需要保留下来的,所以上面的两个数据卷操作一个是映射了MySQL配置文件所在的文件夹,一个是映射了MySQL数据所在的文件夹,这里的数据卷操作非常重要。我们可以将MySQL的配置文件放在`$PWD/mysql/conf`目录下,配置文件的具体内容如下所示:
```INI
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
log-error=/var/log/mysql/error.log
server-id=1
log-bin=/var/log/mysql/mysql-bin.log
expire_logs_days=30
max_binlog_size=256M
symbolic-links=0
```
如果安装了MySQL 8.x版本(目前的最新版本),在使用客户端工具连接服务器时可能会遇到`error 2059: Authentication plugin 'caching_sha2_password' cannot be loaded`的问题,这是因为MySQL 8.x默认使用了名为“caching_sha2_password”的机制对用户口令进行了更好的保护,但是如果客户端工具不支持新的认证方式,连接就会失败。解决这个问题有两种方式:一是升级客户端工具来支持MySQL 8.x的认证方式;二是进入容器,修改MySQL的用户口令认证方式。下面是具体的步骤,我们先用`docker exec`命令进入容器的交互式环境,假设运行MySQL 8.x的容器名字叫`mysql8x`
```Shell
docker exec -it mysql8x /bin/bash
```
进入容器的交互式Shell之后,可以首先利用MySQL的客户端工具连接MySQL服务器。
```Shell
mysql -u root -p
Enter password:
Your MySQL connection id is 16
Server version: 8.0.12 MySQL Community Server - GPL
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
```
接下来通过SQL来修改用户口令就可以了。
```SQL
alter user 'root'@'%' identified with mysql_native_password by '123456' password expire never;
```
当然,如果愿意你也可以查看一下用户表检查是否修改成功。
```SQL
use mysql;
select user, host, plugin, authentication_string from user where user='root';
+------+-----------+-----------------------+-------------------------------------------+
| user | host | plugin | authentication_string |
+------+-----------+-----------------------+-------------------------------------------+
| root | % | mysql_native_password | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| root | localhost | mysql_native_password | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+------+-----------+-----------------------+-------------------------------------------+
2 rows in set (0.00 sec)
```
在完成上面的步骤后,现在即便不更新客户端工具也可以连接MySQL 8.x了。
#### 安装Redis
接下来我们试一试运行多个容器并让多个容器之间通过网络通信。我们创建4个Redis容器来实现一主三从的主从复制结构。
```Shell
docker run -d -p 6379:6379 --name redis-master redis redis-server
docker run -d -p 6380:6379 --name redis-slave-1 --link redis-master:redis-master redis redis-server --replicaof redis-master 6379
docker run -d -p 6381:6379 --name redis-slave-2 --link redis-master:redis-master redis redis-server --replicaof redis-master 6379
docker run -d -p 6382:6379 --name redis-slave-3 --link redis-master:redis-master redis redis-server --replicaof redis-master 6379
```
上面的命令中,`--link`参数用于给容器创建网络别名,因为三台从机(slave)需要通过网络连接自己的主机(master)。虽然,我们可以通过`docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container-ID>`命令来查看到容器的IP地址,但是由于容器的即装即用性,容器的IP地址有可能会发生变化,如果直接使用IP地址,在容器重启后就可能会因为IP地址的变化导致从机无法连接到主机。使用`--link`参数创建网络别名就是为了在启动Redis服务器时在`redis-server`后面的`--replicaof`参数后使用这个别名而不是IP地址。
接下来我们进入名为`redis-master`的容器,看看主从复制的配置是否成功。
```Shell
docker exec -it redis-master /bin/bash
```
通过`redis-cli`启动命令行工具。
```Shell
redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:3
slave0:ip=172.17.0.4,port=6379,state=online,offset=1988,lag=0
slave1:ip=172.17.0.5,port=6379,state=online,offset=1988,lag=1
slave2:ip=172.17.0.6,port=6379,state=online,offset=1988,lag=1
master_replid:94703cfa03c3ddc7decc74ca5b8dd13cb8b113ea
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1988
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1988
```
### 构建镜像
Docker镜像是由文件系统叠加而成的,系统的最底层是bootfs,相当于就是Linux内核的引导文件系统;接下来第二层是rootfs,这一层可以是一种或多种操作系统(如Debian或Ubuntu文件系统),Docker中的rootfs是只读状态的;Docker利用联合挂载技术将各层文件系统叠加到一起,最终的文件系统会包含有底层的文件和目录,这样的文件系统就是一个镜像,如下图所示。
之前我们讲过了如何查找、列出镜像和拉取(下载)镜像,接下来看看构建镜像的两种方式:
1. 使用`docker commit`命令。(不推荐)
2. 使用`docker build`命令和Dockerfile文件。
#### 使用commit命令构建镜像
为了演示如何构建镜像,我们先使用Ubuntu镜像来定制一个容器,命令如下所示。
```Shell
docker run --name myubuntu -it ubuntu /bin/bash
```
在容器中执行下面的命令来安装Apache服务器并退出容器。
```Shell
apt -y upgrade
apt -y install apache2
exit
```
我们将这个容器作为一个定制的Web服务器保存起来,当需要这样一台Web服务器的时候,就没有必要重新创建容器并安装Apache了。
首先我们通过下面的命令查看容器的ID。
```Shell
docker container ls -a
```
```
docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
014bdb321612 ubuntu "/bin/bash" 5 minutes ago Exited (0) myubuntu
```
提交定制的容器。
```Shell
docker commit 014bdb321612 jackfrued/mywebserver
```
查看镜像文件。
```Shell
docker images
```
```
REPOSITORY TAG IMAGE ID CREATED SIZE
jackfrued/mywebserver latest 795b294d265a 14 seconds ago 189 MB
```
生成镜像文件以后,后面就可以利用刚才创建的镜像文件来创建新的容器。
#### 使用Dockerfile构建镜像
Dockerfile使用DSL(Domain Specific Language)来构建一个Docker镜像,只要编辑好了Dockerfile文件,就可以使用`docker build`命令来构建一个新的镜像。
我们先创建一个新的文件夹并在文件夹下创建名为Dockerfile的文件。
```Shell
mkdir test
cd test
touch Dockerfile
```
编辑这个Dockerfile文件添加如下所示的内容。
```Shell
vim Dockerfile
```
```Dockerfile
# version: 0.0.1
FROM ubuntu:14.04
MAINTAINER jackfrued "jackfrued@126.com"
RUN apt-get update && apt-get install -y nginx
RUN echo 'hello, world!' > /usr/share/nginx/html/index.html
EXPOSE 80
```
我们来解释一下上面的Dockerfile文件。Dockerfile文件通过特殊的指令来指定基础镜像(FROM指令)、创建容器后需要指定的命令(RUN指令)以及需要暴露的端口(EXPOSE)等信息。我们稍后会专门为大家介绍这些Dockfile中的指令。
接下来我们可以使用`docker build`命令来创建镜像,如下所示。
```Shell
docker build -t="jackfrued/webserver" .
```
通过下面的命令可以查看创建好的镜像。
```Shell
docker images
```
```
REPOSITORY TAG IMAGE ID CREATED SIZE
jackfrued/webserver latest 87d6cb096be2 23 minutes ago 222 MB
```
如果想知道镜像文件是如何创建出来的,可以使用下面的命令。
```Shell
docker history jackfrued/webserver
```
```
IMAGE CREATED CREATED BY SIZE
87d6cb096be2 25 minutes ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B
53d3bc3a123e 25 minutes ago /bin/sh -c service nginx start 3 B
10646b63275e 25 minutes ago /bin/sh -c echo 'hello, world!' > /usr/sha... 14 B
f3e3bf3e998e 25 minutes ago /bin/sh -c apt-get update && apt-get insta... 34.3 MB
c98e22cf5a64 26 minutes ago /bin/sh -c #(nop) MAINTAINER jackfrued "j... 0 B
2c5e00d77a67 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
<missing> 3 months ago /bin/sh -c mkdir -p /run/systemd && echo '... 7 B
<missing> 3 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0 B
<missing> 3 months ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 195 kB
<missing> 3 months ago /bin/sh -c #(nop) ADD file:1e01ab604c0cc30... 188 MB
```
使用该镜像来创建容器运行Web服务器。
```Shell
docker run -d -p 80:80 --name mywebserver jackfrued/webserver nginx -g "daemon off;"
```
如果希望将上面创建的镜像文件放到dockerhub仓库中,可以按照如下所示的步骤进行操作。
通过下面的命令登录到dockerhub。
```Shell
docker login
```
输入用户名和口令进行登录。
```
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: jackfrued
Password:
Login Succeeded
```
通过下面的命令将镜像推到仓库中。
```Shell
docker push jackfrued/webserver
```
![](./res/dockerhub-repo.png)
#### Dockerfile指令
想了解Dockerfile的指令可以查看官方提供的[参考手册](<https://docs.docker.com/engine/reference/builder/>),下面我们为大家介绍一些常用的指令。
1. **FROM**:设置基础镜像,必须是Dockerfile中的第一条指令。
```Dockerfile
FROM <镜像名> [AS <别名>]
```
```Dockerfile
FROM <镜像名>[:<标签>] [AS <别名>]
```
2. **RUN**:指定构建镜像时要执行的命令。
```Dockerfile
RUN <命令> [参数1], [参数2], ...
```
```Dockerfile
RUN ["可执行文件", "参数1", "参数2", ...]
```
3. **CMD**:指定构建镜像后要执行的命令。
```Dockerfile
CMD <命令> [参数1], [参数2], ...
```
```Dockerfile
CMD ["可执行文件", "参数1", "参数2", ...]
```
> 说明:Docker不同于虚拟机,容器本身就是一个进程,容器中的应用应该位于前台运行。CMD命令相当于就是用来指定容器主进程(创建容器后要在前台执行的程序)的,如果主进程结束了,容器也就停止运行了。所以在容器中启动Nginx不能使用`service nginx start`或是`systemctl start nginx`而是要通过`CMD ["nginx", "-g", "daemon off;"]`让它在前台运行。
4. **ENTRYPOINT**:和CMD类似,也可以执行命令,但`docker run`命令行中指定的任何参数都会被当做参数再次传给ENTRYPOINT指令中的命令,这就使得我们可以构建一个镜像,它既可以运行一个默认的命令,也支持通过`docker run`命令行为该命令指定可覆盖的参数选项。
```Dockerfile
ENTRYPOINT <命令> [参数1], [参数2], ...
```
```Dockerfile
ENTRYPOINT ["可执行文件", "参数1", "参数2", ...]
```
5. **WORKDIR**:在通过镜像创建新容器时,在容器内部创建一个工作目录,ENTRYPOINT和CMD指定的程序会在这个目录下执行。在使用`docker run`命令时可以通过`-w`参数来覆盖由WORKDIR指定的工作目录。例如:
```Dockerfile
WORKDIR /opt/webapp
```
```Shell
docker run -w /usr/share/webapp ...
```
6. **ENV**:在创建镜像时设置环境变量。在使用`docker run`命令时,可以通过`-e`参数来修改环境变量的设置。例如:
```Dockerfile
ENV DEFAULT_PORT=8080
```
```Shell
docker run -e "DEFAULT_PORT=8000" ...
```
7. **USER**:指定镜像会以什么用户身份去运行。例如:
```Dockerfile
USER nginx
```
8. **VOLUME**:在创建容器时添加一个数据卷的挂载点。通过数据卷操作可以实现容器间数据的共享和重用,对卷所作的修改可以马上生效而不需要重新启动容器,我们之前创建容器时使用`—volume`参数就是为了实现数据卷的映射操作。
```Dockerfile
VOLUME ["/路径1", "/路径2/子路径2.1/", ...]
```
9. **ADD**:将构建目录下的文件和文件夹复制到镜像中,如果是压缩文件和归档文件,ADD命令会对这些文件进行解压缩解归档的操作。
```Dockerfile
ADD [--chown=<用户>:<用户组>] <源文件> <目标文件>
```
10. **COPY**:非常类似于ADD,但不会主动对文件进行提取操作。
11. **LABEL**:为Docker镜像添加一些元数据,在使用`docker inspect`命令时会看到这些元数据。
```Dockerfile
LABEL version="1.0.0" location="Chengdu"
```
12. **ONBUILD**:为镜像添加触发器,当一个镜像被用作其他镜像的基础镜像,触发器将会被执行。例如:
```Dockerfile
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make
```
### 容器编排
我们的项目可能会使用了多个容器,容器多了之后管理容器的工作就会变得麻烦。如果要对多个容器进行自动配置使得容器可以相互协作甚至实现复杂的调度,这就需要进行容器编排。Docker原生对容器编排的支持非常弱,但是可以通过社区提供的工具来实现容器编排。
#### Docker Compose
可以通过安装Docker Compose工具来实现基于YAML文件的容器编排,YAML文件会定义一系列的容器以及容器运行时的属性,Docker Compose会根据这些配置来管理容器。
1. 安装Docker Compose。
```Shell
curl -L https://github.com/docker/compose/releases/download/1.25.0-rc2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
> 说明:如果没有curl工具,在CentOS下可以先通过包管理工具yum安装curl再执行上面的命令。
当然我们也可以使用Python的包管理工具pip来安装Docker Compose,命令如下所示。
```Shell
pip3 install -U docker-compose
```
2. 使用Docker Compose。
我们先创建一个名为`composeapp`的文件夹并在该文件夹下创建两个子文件夹`product-service``web-site`,如下所示。
```Shell
mkdir composeapp
cd composeapp
mkdir product-service
mkdir web-site
```
我们先在`product-service`文件夹下编写提供数据的API接口程序。
```Shell
vim product-service/api.py
```
我们用Flask来实现一个非常简单的数据接口服务程序。
```Python
from pickle import dumps, loads
from flask import Flask
from flask_restful import Resource, Api
from redis import Redis
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r'/api/*': {'origins': '*'}})
api = Api(app)
redis = Redis(host='redis-master', port=6379)
class Product(Resource):
def get(self):
data = redis.get('products')
if not data:
products = ['Ice Cream', 'Chocolate', 'Coca Cola', 'Hamburger']
redis.set('products', dumps(products))
else:
products = loads(data)
return {'products': products}
api.add_resource(Product, '/api/products')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
```
由于上面的项目需要依赖`flask``flask-restful`等三方库,所以我们再添加一个指明依赖库的文件并将其命名为`requirements.txt`,其内容如下所示。
```Shell
vim product-service/requirements.txt
```
```
flask
flask-restful
flask-cors
redis
```
稍后我们会将上面的接口服务放在一个容器中运行,为此我们先编写一个Dockerfile文件以便创建对应的镜像,其内容如下所示。
```Shell
vim product-service/Dockerfile
```
```Dockerfile
FROM python:3
ADD . /root/product-service
WORKDIR /root/product-service
RUN pip install -r requirements.txt
CMD ["python", "api.py"]
```
我们再去到`web-site`目录下创建一个页面,稍后我们会通一个容器来提供Nginx服务并运行该页面,而这个页面会访问我们刚才部署的数据接口服务获取数据并通过Vue.js将数据渲染到页面上。
```Shell
vim web-site/index.html
```
```HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>首页</title>
</head>
<body>
<div id="app">
<h2>产品列表</h2>
<ul>
<li v-for="product in products">{{ product }}</li>
</ul>
</div>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
products: []
},
created() {
fetch('http://1.2.3.4:8000/api/products')
.then(resp => resp.json())
.then(json => {this.products = json.products})
}
})
</script>
</body>
</html>
```
接下来,我们要通过一个YAML文件来创建三个容器并指明容器之间的依赖关系。
```Shell
vim docker-compose.yml
```
```YAML
version: '3'
services:
product-service:
build: ./product-service
ports:
- '8000:8000'
links:
- redis-master
web-site:
image: nginx
ports:
- '80:80'
volumes:
- ./web-site:/usr/share/nginx/html
redis-master:
image: redis
expose:
- '6379'
```
有了这个YAML文件,我们就可以使用`docker-compose`命令来创建和管理这三个容器,其命令如下所示。
```Shell
docker-compose up
```
```
Creating network "composeapp_default" with the default driver
Building product-service
Step 1/5 : FROM python:3
---> e497dabd8450
Step 2/5 : ADD . /root/product-service
---> fbe62813d595
Removing intermediate container 6579e845565a
Step 3/5 : WORKDIR /root/product-service
---> 3a722675e3b1
Removing intermediate container 57fc490436ce
Step 4/5 : RUN pip install -r requirements.txt
---> Running in cadc2d0c1b9b
... ...
---> fc747fc11f4a
Removing intermediate container cadc2d0c1b9b
Step 5/5 : CMD python api.py
---> Running in ecbbd2a69906
---> 637e760f2e5b
Removing intermediate container ecbbd2a69906
Successfully built 637e760f2e5b
WARNING: Image for service product-service was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating composeapp_redis-master_1 ... done
Creating composeapp_web-site_1 ... done
Creating composeapp_product-service_1 ... done
Attaching to composeapp_redis-master_1, composeapp_web-site_1, composeapp_product-service_1
... ...
```
## 数据库设计和OOAD
## MySQL性能优化
### 存储引擎
### 使用索引
1. InnoDB
2. MyISAM
### 数据类型
### 索引
#### 索引的类型
在前面[《关系型数据库MySQL》](../Day36-40/36-38.关系型数据库MySQL.md)一文中,我们已经讲到过索引的相关知识,这里我们做一个简单的回顾。
1. B-Tree索引
2. HASH索引
3. R-Tree索引(空间索引)
4. Full-text索引(全文索引)
### 视图
查询的快照,可以将访问权限控制到列上。
```SQL
create view ... as select ...
drop view ...
```
### 使用过程
### 存储过程
过程,通常也称之为存储过程。
```SQL
create procedure ... (params)
......@@ -40,20 +26,12 @@ call ...
cursor.callproc('...')
```
### 触发器
不能用,因为多个行锁可能直接升级为表锁,导致性能低下。
### 数据分区
### 事务控制
### SQL注入攻击
### 数据分区
### SQL优化
#### 优化步骤
1. 通过`show status`了解各种SQL的执行频率。
```SQL
......@@ -82,20 +60,20 @@ cursor.callproc('...')
4. 通过`show profiles``show profile for query`分析SQL。
#### SQL优化
5. 优化CRUD操作。
1. 优化insert语句
2. 优化order by语句
3. 优化group by语句
4. 优化嵌套查询
5. 优化or条件
6. 优化分页查询
7. 使用SQL提示
- USE INDEX
- IGNORE INDEX
- FORCE INDEX
- 优化insert语句
- 优化order by语句
- 优化group by语句
- 优化嵌套查询
- 优化or条件
- 优化分页查询
- 使用SQL提示
- USE INDEX
- IGNORE INDEX
- FORCE INDEX
#### 配置优化
### 配置优化
1. 调整max_connections
2. 调整back_log
......@@ -103,7 +81,7 @@ cursor.callproc('...')
4. 调整thread_cache_size
5. 调整innodb_lock_wait_timeout
#### 架构优化
### 架构优化
1. 通过拆分提高表的访问效率
- 垂直拆分
......@@ -115,21 +93,6 @@ cursor.callproc('...')
- 3NF:所有的属性都直接依赖于主键(消除传递依赖)
- BCNF:消除非平凡多值依赖
3. 使用中间表提高统计查询速度
### 数据备份
#### 导入和导出
1. select ... into outfile ...
2. load data infile ... into table ...
3. mysqldump
4. mysqlimport
#### ibbackup工具
#### xtrabackup工具
### 主从复制
### 集群
4. 主从复制和读写分离
5. 配置MySQL集群
## 使用Django开发项目
## 使用Django开发商业项目
> 说明:本文的部分插图来自于《Python项目开发实战》和《精通Django》,这两本书中都包含了对Django框架精彩的讲解,有兴趣的读者可以自行购买阅读。
......
......@@ -2,7 +2,7 @@
> 作者:骆昊
>
> 最近有很多想学习Python的小伙伴陆陆续续加入我们的交流群,目前我们的交流群人数已经超过一万人,光靠我自己已经无法及时处理小伙伴们的入群申请,更无法及时为大家解答问题。目前我的想法是分技术方向建立讨论群并安排专门的人来管理这些群,群管理者应该具备专业的知识并有相对充裕的时间,可以解答小伙伴们提出的问题。当然,我会向这些管理者支付报酬,如果有兴趣成为管理者的可以跟我私聊。希望通过这种方式,我们能汇聚更多优秀的Python开发者,一方面打造沟通和交流的平台,另一方面让新入行的开发者获得问道的途径并藉此迅速成长。我会继续努力做好线上公开课以及线下技术交流活动,也希望各位小伙伴一如既往的支持我们。创作不易,感谢大家的打赏支持,这些钱不会用于购买咖啡而是捐赠给支教组织([点击](./更新日志.md)了解捐赠情况)。感谢**北京千锋互联科技有限公司Python教学部**对[公开课](https://ke.qq.com/course/406954)提供的支持。
> 最近有很多想学习Python的小伙伴陆陆续续加入我们的交流群,目前我们的交流群人数已经超过一万人,光靠我自己已经无法及时处理小伙伴们的入群申请,更无法及时为大家解答问题。目前我的想法是分技术方向建立讨论群并安排专门的人来管理这些群,群管理者应该具备专业的知识并有相对充裕的时间,可以解答小伙伴们提出的问题。当然,我会向这些管理者支付报酬,如果有兴趣成为管理者的可以跟我私聊。但愿通过这种方式,我们的群能汇聚更多优秀的Python开发者,一方面打造一个优质的沟通和交流的平台,另一方面让新入行的开发者获得问道的途径并藉此迅速成长。我会继续努力做好线上公开课以及线下技术交流活动,也希望各位小伙伴一如既往的支持我们。创作不易,感谢大家的打赏支持,这些钱不会用于购买咖啡而是捐赠给支教组织([点击](./更新日志.md)了解捐赠情况)。感谢北京千锋互联科技有限公司对[公开课](https://ke.qq.com/course/406954)提供的支持。
![](./res/python_qq_group.png)
......@@ -546,38 +546,37 @@
| | 查看评论 | 白元芳 | 正在进行 | 20% | 4 | 2018/8/7 | | 2018/8/7 | | 需要进行代码审查 |
| | 评论投票 | 白元芳 | 等待 | 0% | 4 | 2018/8/8 | | 2018/8/8 | | |
#### 第92天:[Docker的使用](./Day91-100/92.Docker在项目中的应用.md)
4. OOAD和数据库设计
#### 第93天:[数据库设计和OOAD](./Day91-100/93.数据库设计和OOAD.md)
- UML(统一建模语言)的类图
##### 概念模型和正向工程
![uml](./res/uml-class-diagram.png)
1. UML(统一建模语言)的类图
- 通过模型创建表(正向工程)
![uml](./res/uml-class-diagram.png)
```Shell
python manage.py makemigrations app
python manage.py migrate
```
2. 通过模型创建表(正向工程)
- 使用PowerDesigner绘制物理模型图。
```Shell
python manage.py makemigrations app
python manage.py migrate
```
![](./res/power-designer-pdm.png)
##### 物理模型和反向工程
- 通过数据表创建模型(反向工程)
1. PowerDesigner
```Shell
python manage.py inspectdb > app/models.py
```
![](./res/power-designer-pdm.png)
2. 通过数据表创建模型(反向工程)
#### 第92天:[Docker的使用](./Day91-100/92.Docker在项目中的应用.md)
```Shell
python manage.py inspectdb > app/models.py
```
#### 第93天:[MySQL性能优化](./Day91-100/93.MySQL性能优化.md)
#### 第94天:[网络API接口设计](./Day91-100/94.网络API接口设计.md)
#### 第95天:[使用Django开发项目](./Day91-100/95.使用Django开发项目.md)
#### 第95天:[使用Django开发商业项目](./Day91-100/95.使用Django开发商业项 目.md)
##### 项目开发中的公共问题
......@@ -625,7 +624,7 @@
- uWSGI支持异构部署。
- 由于Nginx本身支持uWSGI,在线上一般都将Nginx和uWSGI捆绑在一起部署,而且uWSGI属于功能齐全且高度定制的WSGI中间件。
- 在性能上,Gunicorn和uWSGI其实表现相当。
5. 虚拟化技术(Docker)
5. 使用虚拟化技术(Docker)部署测试环境和生产环境
##### 性能测试
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册