20

云计算 docker实验系列

 6 years ago
source link: https://www.sdnlab.com/20883.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者简介:鸿哥,硕士研究生,国内某通信设备公司软件研发工程师,主要从事云计算、SDN技术开发

1、 docker简介
docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、Bare metal、OpenStack 集群和其他的基础应用平台。

docker-668x400.jpg

2、 docker常用命令解析

Java
docker ps 查看当前正在运行的容器 docker ps -a 查看所有容器的状态 docker start/stop id/name 启动/停止某个容器 docker attach id 进入某个容器(使用exit退出后容器也跟着停止运行) docker exec -ti id 启动一个伪终端以交互式的方式进入某个容器(使用exit退出后容器不停止运行) docker images 查看本地镜像 docker rm id/name 删除某个容器 docker rmi id/name 删除某个镜像 docker run --name test -ti ubuntu /bin/bash 复制ubuntu容器并且重命名为test且运行,然后以伪终端交互式方式进入容器,运行bash docker build -t soar/centos:7.1 . 通过当前目录下的 dockerfile创建一个名为soar/centos:7.1的镜像 docker run -d -p 2222:22 --name test soar/centos:7.1 以镜像soar/centos:7.1创建名为test的容器,并以后台模式运行,并做端口映射到宿主机2222端口,P参数重启容器宿主机端口会发生改变
1
2
3
4
5
6
7
8
9
10
11
    docker ps查看当前正在运行的容器
    docker ps-a查看所有容器的状态
    docker start/stop id/name启动/停止某个容器
    docker attach id进入某个容器(使用exit退出后容器也跟着停止运行)
    docker exec-ti id启动一个伪终端以交互式的方式进入某个容器(使用exit退出后容器不停止运行)
    docker images查看本地镜像
    docker rm id/name删除某个容器
    docker rmi id/name删除某个镜像
    docker run--name test-ti ubuntu/bin/bash  复制ubuntu容器并且重命名为test且运行,然后以伪终端交互式方式进入容器,运行bash
    docker build-tsoar/centos:7.1.  通过当前目录下的    dockerfile创建一个名为soar/centos:7.1的镜像
    docker run-d-p2222:22--name test soar/centos:7.1  以镜像soar/centos:7.1创建名为test的容器,并以后台模式运行,并做端口映射到宿主机2222端口,P参数重启容器宿主机端口会发生改变

3、 docker实战-需要实现的架构
本文重点讲解如何使用 docker来搭建应用平台,在一台linux服务器上搭建如下结构的应用,其中包括一个HAProxy代理服务器(容器),目的是保证APP(Django)的高可用性,2个Django应用容器,3个Redis内存数据库容器。HAProxy将用户请求转发至另一台Django容器,由Django容器进行逻辑处理,并通过Redis(master)获取内存数据库数据,而Redis(master)与Redis(slave)进行数据同步。

docker-1.png

4、实现步骤
1)搭建 docker应用环境
安装 docker软件

Java
$sudo apt-get update $sudo apt-get install docker.io 修改镜像源 $sudo vi /etc/default/ docker 添加 DOCKER_OPTS="--registry-mirror=https:// docker.mirrors.ustc.edu.cn" 其他镜像 docker 官方中国区 https://registry. docker-cn.com 网易 http://hub-mirror.c.163.com ustc大学 https:// docker.mirrors.ustc.edu.cn
1
2
3
4
5
6
7
8
9
$sudo apt-get update
    $sudo apt-get install     docker.io
修改镜像源
    $sudo vi/etc/default/    docker     添加
    DOCKER_OPTS="--registry-mirror=https://    docker.mirrors.ustc.edu.cn"
其他镜像
    docker官方中国区    https://registry.    docker-cn.com
网易                  http://hub-mirror.c.163.com
ustc大学             https://    docker.mirrors.ustc.edu.cn

启动 docker服务

Java
$sudo service docker start
1
$sudo service     docker start

测试下是否可以使用

Java
$sudo docker run ubuntu:15.10 /bin/echo "Hello world"
1
$sudo     docker run ubuntu:15.10/bin/echo"Hello world"

输出

Java
Unable to find image 'ubuntu:15.10' locally 15.10: Pulling from library/ubuntu 7dcf5a444392: Pull complete 759aa75f3cee: Pull complete 3fa871dc8a2b: Pull complete 224c42ae46e7: Pull complete Digest: sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3 Status: Downloaded newer image for ubuntu:15.10 Hello world
1
2
3
4
5
6
7
8
9
Unable tofind image'ubuntu:15.10'locally
15.10:Pulling from library/ubuntu
7dcf5a444392:Pull complete
759aa75f3cee:Pull complete
3fa871dc8a2b:Pull complete
224c42ae46e7:Pull complete
Digest:sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3
Status:Downloaded newer image forubuntu:15.10
Hello world

意思是 docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果,同时 docker首先从本地主机上查找镜像是否存在,如果不存在, docker 就会从镜像仓库 docker Hub 下载公共镜像。

2)获取应用栈各节点所需要的镜像
docker从 docker hub上获取HAProxy、redis、以及Django的镜像。

Java
$sudo docker pull ubuntu $sudo docker pull django $sudo docker pull haproxy $sudo docker pull redis $sudo docker images //显示所有镜像
1
2
3
4
5
    $sudo     docker pull ubuntu
    $sudo     docker pull django
    $sudo     docker pull haproxy
    $sudo     docker pull redis
    $sudo     docker images      //显示所有镜像

3)配置好各个容器之间的网络通信,由于这里是所有容器都在同一个服务器上,因此可以忽略各个主机之间的连接,只需要配置好各个容器之间的连接即可。使用--link参数能够进行容器间的安全通信,使用格式为name:alias,例如:

Java
$sudo docker run --link redis:redis --name console ubuntu bash
1
$sudo     docker run--link redis:redis--name console ubuntu bash

表示将在ubuntu镜像上启动一个容器,并启动该容器的bash,同时命名为console,同时将新启动的console容器连接到名为redis容器上。因此应用栈启动命令如下:

Java
启动redis $sudo docker run -it --name redis-master redis /bin/bash 打开另外一个tty输入 $sudo docker run -it --name redis-slave1 --link redis-master:master redis /bin/bash 再打开一个tty $sudo docker run -it --name redis-slave2 --link redis-master:master redis /bin/bash 打开一个tty启动django $sudo docker run -it --name APP1 --link redis-master:db -v ~/Projects/Django/App1:/usr/src/app django /bin/bash 打开一个tty $sudo docker run -it --name APP2 --link redis-master:db -v ~/Projects/Django/App2:/usr/src/app django /bin/bash 打开一个tty启动Haproxy容器 $sudo docker run -it --name HAProxy --link APP1:APP1 --link APP2:APP2 -p 6301:6301 -v ~/Projects/HAProxy:/tmp haproxy /bin/bash
1
2
3
4
5
6
7
8
9
10
11
12
启动redis
    $sudo     docker run-it--name redis-master redis/bin/bash
打开另外一个tty输入
    $sudo     docker run-it--name redis-slave1--link redis-master:master redis/bin/bash
再打开一个tty
    $sudo     docker run-it--name redis-slave2--link redis-master:master redis/bin/bash
打开一个tty启动django
    $sudo     docker run-it--name APP1--link redis-master:db-v~/Projects/Django/App1:/usr/src/app django/bin/bash
打开一个tty
    $sudo     docker run-it--name APP2--link redis-master:db-v~/Projects/Django/App2:/usr/src/app django/bin/bash
打开一个tty启动Haproxy容器
    $sudo     docker run-it--name HAProxy--link APP1:APP1--link APP2:APP2-p6301:6301-v~/Projects/HAProxy:/tmp haproxy/bin/bash

4)节点内部的配置
配置redis主数据库的redis配置,由于容器的轻量化设计,在容器里面缺乏相应的文本编辑工具,所有借用volume来实现文件的编辑。

Java
使用 $sudo docker inspect 65cf 来查看容器信息,65cf是该容器的id的前缀,找到 "Mounts": [ { "Type": "volume", "Name": "42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967", "Source": "/var/lib/ docker/volumes/42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ],
1
2
3
4
5
6
7
8
9
10
11
12
13
使用$sudo     docker inspect65cf    来查看容器信息,65cf是该容器的id的前缀,找到
"Mounts":[
            {
                "Type":"volume",
                "Name":"42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967",
                "Source":"/var/lib/    docker/volumes/42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967/_data",
                "Destination":"/data",
                "Driver":"local",
                "Mode":"",
                "RW":true,
                "Propagation":""
            }
        ],

可以看到在主机/var/lib/ docker/volumes/42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967/_data映射到了容器的/data目录,因此进入主机的/var/lib/ docker/volumes/42a5213973bb5365db0e040515f48c63cdd5514473285723cd6c5ab36eae4967/_data目录,创建redis.conf文件,在网上找了该文件的内容,填入redis.conf然后修改以下几个参数
daemonize yes
pidfile /var/run/redis.pid
在容器中可以看到该文件,然后将该文件复制到运行环境
cp redis.conf /usr/local/bin/
cd /usr/local/bin/
./redis-server redis.conf
同理在redis slave上也是类似配置,最后在redis slave上的redis.conf
修改参数为
daemonize yes
pidfile /var/run/redis.pid
slaveof master 6379
最后都执行
./redis-server redis.conf
测试是否配置成功,

Java
在redis master上启动redis客户端,存储一个数据 redis-cli 127.0.0.1:6379> set master 65cf 127.0.0.1:6379> get master "65cf" 在redis slave上执行redis-cli,获取master的值 root@91961ee165f2:/usr/local/bin# redis-cli 127.0.0.1:6379> get master "65cf" root@da2af08abdeb:/usr/local/bin# redis-cli 127.0.0.1:6379> get master "65cf"
1
2
3
4
5
6
7
8
9
10
11
12
redis master上启动redis客户端,存储一个数据
    redis-cli
127.0.0.1:6379>set master65cf
127.0.0.1:6379>get master
"65cf"
redis slave上执行redis-cli,获取master的值
root@91961ee165f2:/usr/local/bin#redis-cli
127.0.0.1:6379>get master
"65cf"
root@da2af08abdeb:/usr/local/bin#redis-cli
127.0.0.1:6379>get master
"65cf"

4)APP容器节点Django的配置
安装python的redis支持包,

Java
在app1上执行 pip install redis 并且测试下 python Python 3.4.5 (default, Dec 14 2016, 18:54:20) [GCC 4.9.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import redis >>> print(redis.__file__) /usr/local/lib/python3.4/site-packages/redis/__init__.py
1
2
3
4
5
6
7
8
9
app1上执行
    pip install redis        并且测试下
    python
Python3.4.5(default,Dec142016,18:54:20)
[GCC4.9.2]on linux
Type"help","copyright","credits"or"license"formore information.
>>>importredis
>>>print(redis.__file__)
/usr/local/lib/python3.4/site-packages/redis/__init__.py

在容器中创建app

Java
cd /usr/src/app/ mkdir dockerweb cd dockerweb/ django-admin.py startproject redisweb cd redisweb/ python manage.py startapp helloworld # ls
1
2
3
4
5
6
7
cd/usr/src/app/
    mkdir     dockerweb
    cd     dockerweb/
    django-admin.py startproject redisweb
    cd redisweb/
    python manage.py startapp helloworld
    #ls

helloworld manage.py redisweb
切换至主机的/home/ubuntu/Projects/Django/App1可以看到刚刚创建的那些文件

Java
cd /home/ubuntu/Projects/Django/App1 ls dockerweb cd /home/ubuntu/Projects/Django/App1/ dockerweb/redisweb/helloworld
1
2
3
4
cd/home/ubuntu/Projects/Django/App1
    ls
        dockerweb
    cd/home/ubuntu/Projects/Django/App1/    dockerweb/redisweb/helloworld

切换至root用户

Java

$sudo su vi views.py 内容如下 from django.shortcuts import render from django.http import HttpResponse

# Create your views here. import redis

def hello(request): str=redis.__file__ str+="<br>" r = redis.Redis(host='db',port=6379,db=0) info=r.info() str+=("Set Hi<br>") r.set('Hi','Helloworld-APP1') str+=("Get Hi:%s <br>" % r.get(Hi)) str+=("Redis Info:<br>") str+=("Key:Info:Value") for key in info: str+=("%s:%s<br>" % (key, info[key])) return HttpResponse(str)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$sudo su
    vi views.py    内容如下
from django.shortcuts importrender
from django.http importHttpResponse
 
#Create your views here.
importredis
 
def hello(request):
    str=redis.__file__
    str+="<br>"
    r=redis.Redis(host='db',port=6379,db=0)
    info=r.info()
    str+=("Set Hi<br>")
    r.set('Hi','Helloworld-APP1')
    str+=("Get Hi:%s <br>"%r.get(Hi))
    str+=("Redis Info:<br>")
    str+=("Key:Info:Value")
    forkey ininfo:
        str+=("%s:%s<br>"%(key,info[key]))
    returnHttpResponse(str)

然后修改redisweb项目的配置文件setting.py,将helloworld添加进去。

Java
vi setting.py ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'helloworld', ]
1
2
3
4
5
6
7
8
9
10
11
vi setting.py
ALLOWED_HOSTS=['*']
INSTALLED_APPS=[
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld',
]

最后修改redisweb的urls.py,将其设置为访问应用url模式
vi urls.py 内容如下

Java

from django.conf.urls import url from django.contrib import admin from helloworld.views import hello

urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^helloworld$', hello), ]

1
2
3
4
5
6
7
8
from django.conf.urls importurl
from django.contrib importadmin
from helloworld.views importhello
 
urlpatterns=[
url(r'^admin/',admin.site.urls),
url(r'^helloworld$',hello),
]

主机下修改好了之后需要在容器里面执行以下:

Java
cd /usr/src/app/ dockerweb/redisweb python manage.py makemigrations python manage.py migrate
1
2
3
cd/usr/src/app/    dockerweb/redisweb
    python manage.py makemigrations
    python manage.py migrate

APP2也是类似的配置。
最后一步,启动APP1

Java

python manage.py runserver 0.0.0.0:8001 Performing system checks...

System check identified no issues (0 silenced). May 01, 2018 - 07:58:05 Django version 1.10.4, using settings 'redisweb.settings' Starting development server at http://0.0.0.0:8001/ Quit the server with CONTROL-C.

1
2
3
4
5
6
7
8
python manage.py runserver0.0.0.0:8001
Performing system checks...
 
System check identified no issues(0silenced).
May01,2018-07:58:05
Django version1.10.4,using settings'redisweb.settings'
Starting development server at http://0.0.0.0:8001/
Quit the server with CONTROL-C.

项目在以下地址:

https://pan.baidu.com/s/11hwF2qMzSZ_EyZenF7mtpg

密码:xuut

5)HAProxy容器节点配置
利用HAProxy进行负载均衡,在主机中,进入HAProxy目录。
vi haproxy.cfg 内容如下:

global log 127.0.0.1 local0 maxconn 4096 chroot /usr/local/sbin daemon nbproc 4 pidfile /usr/local/sbin/haproxy.pid

defaults log 127.0.0.1 local3 mode http option dontlognull option redispatch retries 2 maxconn 2000 balance roundrobin timeout connect 5000ms timeout client 50000ms timeout server 50000ms

listen redis_proxy 0.0.0.0:6301 stats enable stats uri /haproxy-stats server APP1 APP1:8001 check inter 2000 rise 2 fall 5 server APP2 APP2:8002 check inter 2000 rise 2 fall 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
global
    log127.0.0.1local0
    maxconn4096
    chroot/usr/local/sbin
    daemon
    nbproc4
    pidfile/usr/local/sbin/haproxy.pid
 
defaults
    log127.0.0.1local3
    mode http
    option dontlognull
    option redispatch
    retries2
    maxconn2000
    balance roundrobin
    timeout connect5000ms
    timeout client50000ms
    timeout server50000ms
 
listen redis_proxy0.0.0.0:6301
    stats enable
    stats uri/haproxy-stats
    server APP1 APP1:8001check inter2000rise2fall5
    server APP2 APP2:8002check inter2000rise2fall5

然后进入容器中,在/tmp目录下将haproxy.cfg复制到/usr/local/sbin/
cd /tmp/
ls
haproxy.cfg
cp haproxy.cfg /usr/local/sbin/
cd /usr/local/sbin/
ls
haproxy haproxy.cfg
利用该配置文件启动haproxy
./haproxy -f haproxy.cfg
此时可以通过以下链接进行测试

http://172.17.0.7:6301/helloworld

5、总结
通过搭建6个docker容器节点来实验HAProxy、Django、redis组成的服务,本例中采用web返回最简单的Helloworld来模拟常用的web应用,实际部署当中可以将Django换成Tomcat等java应用服务器,并且可以添加关系型数据库来持久化用户数据。从实验可以看出,实验 docker容器搭建起来非常方便灵活,占用资源少等特点。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK