通过构建微服务学习Docker

如果想要动手试试 Docker ,那么就行动吧!

本文会讲解Docker如何工作,会遇到什么问题,以及如何助力基本的开发任务 - 构建微服务。

本文使用带有MySQL后台的Node.js服务作为示例,介绍如何在本地运行代码,以及运行微服务和数据库的容器。

什么是Docker?

Docker本质上是一种软件,让用户创建镜像(很像虚拟机的模板),并且随后在容器里运行该镜像的实例。

Docker维护着有很多镜像的存储库,称为 Docker Hub ,用户可以将其作为尝试镜像的起点,或者作为镜像的免费存储。用户可以安装Docker,选择想要使用的镜像,然后在容器里运行其实例。

本文会尝试构建镜像,从镜像创建容器等等。

安装Docker

要跟上本文的实验,需要安装Docker。

在docs.docker.com/engine/installation处查看平台适用的安装向导。

如果你使用的是Mac或者Windows,考虑使用一个虚拟机。我在Mac OS X上使用Parallels运行Ubuntu虚拟机来完成大多数开发任务。因为可以做快照,当实验的时候把环境破坏了的话,可以恢复快照回去。

试一试

键入如下命令:

docker run -it ubuntu

一段时间之后,你会看到如下提示:

root@719059da250d:/#

试试如下命令,然后退出容器:

root@719059da250d:/# lsb_release -a  
No LSB modules are available.  
Distributor ID:    Ubuntu  
Description:    Ubuntu 14.04.4 LTS  
Release:    14.04  
Codename:    trusty  
root@719059da250d:/# exit

这看上去似乎没干什么,其实底层发生了很多事情!

你看到的是在你的机器上运行着的Ubuntu的隔离容器环境里的bash shell。这个环境完全归你所有——可以在上面安装东西,运行软件,可以做任何你想做的事情。

下图表明了刚刚发生了什么(图来自于《 理解Docker文档架构 》一文):

  1. 我们发出了docker命令:
    docker : 运行docker客户端
    run : 运行新容器的命令
    -it : 让容器带有交互型终端的参数
    ubuntu : 容器所依赖的基础镜像

  2. 在主机(我们的机器)上运行的docker服务检查本地是否有所请求的镜像拷贝——这里发现没有。

  3. docker服务检查公有存储库(docker hub),看是否有可用的名为 ubuntu 的镜像——这里发现有。

  4. docker服务下载镜像,将其存储到镜像的本地缓存里(下一次就可以直接使用了)。

  5. docker服务基于 ubuntu 镜像创建新容器。

尝试下面这些命令:

docker run -it haskell  
docker run -it java  
docker run -it python

这里我们不打算使用 Haskell ,但是你可以看到,运行一个环境非常非常容易。

构建自己的镜像也很简单,可以在其中包含应用程序或者服务,可以是数据库等等。随后就可以在任意安装了Docker的机器上运行它们——镜像可以保证以相同的,可预测的方式在每台机器上运行。我们可以将软件及其运行所需的环境整体构建成代码,并且轻松部署。

让我们以一个简单微服务为例。

概述

这里将构建一个管理邮件地址到电话号码目录的微服务,使用Node.js和MySQL。

开始

要完成本地开发,需要安装MySQL,并且创建一个测试数据库...

创建本地数据库,并且在之上运行脚本,这很容易,但是可能会带来一些问题。很多不受控制的事情开始了。它可能能工作,我们甚至可以使用一些提交进代码库的shell脚本来控制这些步骤,但是如果其他开发人员已经安装了MySQL了呢?如果他们的数据库已经使用了我们想要创建的名称'users'了呢?

第1步:在Docker里创建测试数据库服务器

这是很好的Docker用户场景。我们可能不想在Docker里运行生产环境数据库(比如可能会使用Amazon RDS),但是可以瞬间使用Docker容器创建一个干净的MySQL数据库做开发——保持干净的开发机器,并且保证所有东西都在控制中,并且可重复。

运行如下命令:

docker run --name db -e MYSQL_ROOT_PASSWORD=123 -p 3306:3306 mysql:latest

该命令启动一个运行着的MySQL实例,通过使用3306端口,root密码123可以访问该实例。

1. docker run 告诉引擎,用户想要运行一个镜像(在最后传入的是镜像, mysql:latest )

2. --name db 将这个容器命名为 db .

3. -d 解绑-比如,在后台运行容器。

4. -e MYSQL_ROOT_PASSWORD=123-e 参数告诉docker所提供的环境变量。这之后跟着的变量正是MySQL镜像检查且用来设置的默认root密码。

5. -p 3306:3306 告诉引擎用户想要将容器内的3306端口映射到外部的3306端口上。

最后一部分很重要——即使这是MySQL的默认端口,如果用户不显式告诉docker想要映射的端口,docker就会阻塞该端口的访问(因为容器默认是隔离的,直到用户告诉docker想要访问它们)。

该命令返回值是容器id,这是容器的指针,用户可以用它来停止容器,向容器发送命令等等。让我们看看正在运行的是哪些容器:

$ docker ps
CONTAINER ID  IMAGE         ...  NAMES  
36e68b966fd0  mysql:latest  ...  db

最关键的信息是容器ID,镜像和名称。连接到这个镜像看看里面有什么:

$ docker exec -it db /bin/bash

root@36e68b966fd0:/# mysql -uroot -p123  
mysql> show databases;  
+--------------------+
| Database           |
+--------------------+
| information_schema |
+--------------------+
1 rows in set (0.01 sec)

mysql> exit  
Bye  
root@36e68b966fd0:/# exit

下面这么做也很有意思:

1. docker exec -it db 告诉docker用户想要在名为 db 的容器里执行一个命令(我们也可以使用id,或者id的前几个字母)。 -it 确保用户有交互型终端。

2. mysql -uroot -p123 我们实际在容器里作为进程运行的命令,这里只是mysql客户端。

我们可以创建数据库,表,用户,等等。

打包测试数据库

在容器内运行MySQL需要一些Docker技巧,但是让我们先打住,看看服务。现在,使用脚本创建一个 test-database 目录来启动数据库,停止数据库以及搭建测试数据:

test-database\setup.sql  
test-database\start.sh  
test-database\stop.sh

启动脚本很简单:

#!/bin/sh

# Run the MySQL container, with a database named 'users' and credentials
# for a users-service user which can access it.
echo "Starting DB..."  
docker run --name db -d \  
-e MYSQL_ROOT_PASSWORD=123 \
-e MYSQL_DATABASE=users -e MYSQL_USER=users_service -e MYSQL_PASSWORD=123 \
-p 3306:3306 \
mysql:latest

# Wait for the database service to start up.
echo "Waiting for DB to start up..."  
docker exec db mysqladmin --silent --wait=30 -uusers_service -p123 ping || exit 1

# Run the setup script.
echo "Setting up initial data..."  
docker exec -i db mysql -uusers_service -p123 users < setup.sql

该脚本在一个detached容器里运行数据库镜像(比如,在后台运行),创建了一个用户来访问 users 数据库,然后等待数据库服务器启动,随后运行 setup.sql 脚本来设置初始数据。

setup.sql 是:

create table directory (user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, email TEXT, phone_number TEXT);  
insert into directory (email, phone_number) values ('homer@thesimpsons.com', '+1 888 123 1111');  
insert into directory (email, phone_number) values ('marge@thesimpsons.com', '+1 888 123 1112');  
insert into directory (email, phone_number) values ('maggie@thesimpsons.com', '+1 888 123 1113');  
insert into directory (email, phone_number) values ('lisa@thesimpsons.com', '+1 888 123 1114');  
insert into directory (email, phone_number) values ('bart@thesimpsons.com', '+1 888 123 1115');

stop.sh 脚本会停止容器并且删除容器(docker默认会保留容器,这样能够快速重启,本示例中并不需要这样):

#!/bin/sh

# Stop the db and remove the container.
docker stop db && docker rm db

之后会进一步简化这个过程,让它更加顺畅。在repo里的 step1 分支里查看这一阶段的代码。

文章标签: 微服务 docker


关注微信公众号“架构说”,加入Q群微群,让架构师带你飞︿( ̄︶ ̄)︿。


原文链接: 阅读原文
免责申明: 架构说任何转载的文章都会明确标注原文链接。如有侵权,请与本站联系。
转载说明: 架构说原创文章转载时请务必注明文章作者、链接和来源。