Docker命令介绍及实战

对Docker的命令即组件关系作下梳理,以备不时之需。


   
子命令分类 子命令
Docker环境信息 info,version
容器生命周期管理 create,exec,kill,pause,restart,rm,run,start,stop,unpause
镜像仓库命令 login,logout,pull,push,search
镜像管理 build,images,import,load,rmi,save,tag,commit
容器运维操作 attach,export,inspect,port,ps,rename,stats,stop,wait,cp,diff
系统日志信息 events,history,logs


命令关系图:

Docker命令介绍及实战_第1张图片


命令实践:搭建第一个APP Stack

Docker的设计理念是希望用户能够保证一个容器只运行一个进程,即只提供一种服务。然而,对于用户而言,单一容器是无法满足需求的。通常用户需要利用多个容器,分别提供不同的服务,并在不同的容器间互连通信,最后形成一个Docker集群,以实现特定的功能。对于Docker而言,现在已经有了很多优秀的工具来帮助用户搭建和管理集群。下面通过示例搭建一个一台机器上的简化的Docker集群,基于Docker集群构建的应用称为Docker App Stack,即Docker应用栈。


  • 获取应用栈各节点所需镜像:

直接使用docker官网hub实在太慢,这里推荐使用DaoCloud的服务,真的好快。

参考文章:http://www.oschina.net/news/57894/daocloud

# docker pull ubuntu

# docker pull django

# docker pull haproxy

# docker pull redis


  • 应用栈容器节点启动

启动redis容器

# docker run -it --name redis-master redis /bin/bash

# docker run -it --name redis-slave1 --link redis-master:master redis /bin/bash

# docker run -it --name redis-slave2 --link redis-master:master redis /bin/bash


启动Django容器,即应用

$ sudo docker run -it --name APP1 --link redis-master:db -v ~/Projects/Django/APP1:/usr/src/app django /bin/bash

$ sudo docker run -it --name APP2 --link redis-master:db -v ~/Projects/Django/APP2:/usr/src/app django /bin/bash


启动HAProxy容器

$ sudo docker run -it --name HAProxy --link APP1:APP1 --link APP2:APP2 -p 6301:6301 -v ~/Projects/HAProxy:/tmp haproxy /bin/bash


查看集群启动情况:

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
8d3f339b8bad        haproxy             "/docker-entrypoint.s"   2 minutes ago       Up 2 minutes        0.0.0.0:6301->6301/tcp   HAProxy
cb7056eb047b        django              "/bin/bash"              4 minutes ago       Up 3 minutes                                 APP2
929c498fc10b        django              "/bin/bash"              5 minutes ago       Up 5 minutes                                 APP1
da9cbab4a734        redis               "docker-entrypoint.sh"   8 minutes ago       Up 8 minutes        6379/tcp                 redis-slave2
238b6931fc76        redis               "docker-entrypoint.sh"   17 minutes ago      Up 17 minutes       6379/tcp                 redis-slave1
60be2f9a1f2d        redis               "docker-entrypoint.sh"   18 minutes ago      Up 18 minutes       6379/tcp                 redis-master


集群示意图:


Docker命令介绍及实战_第2张图片



  • 应用栈容器节点配置

Redis-master配置

  • 查看对应容器挂载的Volumes目录:

# docker inspect -f "{{.Mounts}}" $(docker ps -a | grep redis-master | awk '{print $1}')
[{28d77df1f0fc827f7e48d9406ffe8321d50b0f641c6fb5648072aa74b38bf765 /var/lib/docker/volumes/28d77df1f0fc827f7e48d9406ffe8321d50b0f641c6fb5648072aa74b38bf765/_data /data local  true }]

可以看到宿主机中的"/var/lib/docker/volumes/28d77df1f0fc827f7e48d9406ffe8321d50b0f641c6fb5648072aa74b38bf765/_data"目录对应容器中的"/data"目录。


  • 拷贝redis.conf到容器中

# cd `docker inspect -f "{{.Mounts}}" $(docker ps -a | grep redis-master | awk '{print $1}') | awk '{print $2}'`
将一个redis.conf文件拷贝过来

# cp /etc/redis/redis.conf ./

  • 启动redis

切换到容器中:

# docker attach `docker ps -a | grep redis-master | awk '{print $1}'`


root@60be2f9a1f2d:/data# ls
redis.conf

将文件拷贝到/usr/loca/bin

创建redis启动需要的目录:

# mkdir -p /var/lib/redis

# mkdir -p /var/log/redis


启动

# redis-server redis.conf


注意:如果slave不能和master建立集群,需要修改redis.conf中的bind ip为容器的实际ip.默认的127.0.0.1可能不行。


确认

# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  20248  3232 ?        Ss   07:48   0:00 /bin/bash
root        20  0.0  0.2  33308  9064 ?        Ssl  08:16   0:00 redis-server 127.0.0.1:6379


Redis Slave配置

先拷贝redis.conf

# docker inspect -f '{{.Mounts}}' $(docker ps -a | grep redis-slave1 | awk '{print $1}')[{c13c1bd2660a5b25171a8d924a6af7279b23c56ff58cca64d145de9eda9cfa7c /var/lib/docker/volumes/c13c1bd2660a5b25171a8d924a6af7279b23c56ff58cca64d145de9eda9cfa7c/_data /data local  true }]

root@ubuntu:/home/zhangxa# cp /etc/redis/redis.conf /var/lib/docker/volumes/c13c1bd2660a5b25171a8d924a6af7279b23c56ff58cca64d145de9eda9cfa7c/_data/


对于从数据库,修改以下几个参数:

# cat redis.conf  | grep slave
slaveof master 6379

由于我们使用了--link参数,因此容器能够解析master的IP。我们可以看下docker自动添加了域名:

# cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.2    master 60be2f9a1f2d redis-master
172.17.0.3    238b6931fc76

最后启动redis-server

# redis-server redis.conf
root@238b6931fc76:/data# ps aux | grep redis
root        21  0.5  0.2  35404  9348 ?        Ssl  08:30   0:00 redis-server 127.0.0.1:6379

同理完成另外一个Slave2的配置


测试R

测试Redis数据库配置


在master容器上redis-cli

> set master "aaa"
OK
172.17.0.2:6379> get master
"aaa"


在slave上测试

# redis-cli
127.0.0.1:6379> get master
"aaa"

APP容器节点配置

进入容器APP1

# docker attach $(docker ps -a | grep APP1| awk '{print $1}')

安装python redis模块

# pip install redis
Collecting redis
  Downloading redis-2.10.5-py2.py3-none-any.whl (60kB)
    100% |████████████████████████████████| 61kB 129kB/s
Installing collected packages: redis
Successfully installed redis-2.10.5


验证安装:

 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
>>>


创建webapp

我们在创建容器时已经挂载了宿主机的~/Projects/APP1目录,


在容器内创建app应用。

# cd /usr/src/
root@929c498fc10b:/usr/src# ls
app
root@929c498fc10b:/usr/src# cd app
root@929c498fc10b:/usr/src/app# mkdir dockerweb
root@929c498fc10b:/usr/src/app# cd dockerweb/
root@929c498fc10b:/usr/src/app/dockerweb# django-admin.py startproject redisweb
root@929c498fc10b:/usr/src/app/dockerweb# ls
redisweb

# python manage.py startapp helloworld
root@cb7056eb047b:/usr/src/app/dockerweb/redisweb# ls
helloworld  manage.py  redisweb
root@cb7056eb047b:/usr/src/app/dockerweb/redisweb#


在对应的宿主机内编写:

# cd dockerweb/redisweb/helloworld/
root@ubuntu:/home/zhangxa/Projects/Django/APP2/dockerweb/redisweb/helloworld# ls
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py

#vim 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+="
" r = redis.Redis(host='db', port=6379, db=0) info = r.info() str+=("Set Hi
") r.set('Hi','HelloWorld-APP1') str+=("Get Hi: %s
" % r.get('Hi')) str+=("Redis Info:
") str+=("Key: Info Value") for key in info: str+=("%s: %s
" % (key, info[key])) return HttpResponse(str)

需要注意的是,我们连接redis数据库时,使用了--link参数创建的db连接来代替具体的IP地址;同理对于APP2使用相同的db连接即可。


接着继续编辑redisweb项目的setting.py,加入'helloworld'

# cd ../redisweb/
root@ubuntu:/home/zhangxa/Projects/Django/APP2/dockerweb/redisweb/redisweb# ls
__init__.py  __pycache__  settings.py  urls.py  wsgi.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld',
]

然后编辑urls.py,引入helloworld的hello视图:

from helloworld.views import hello

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

进入容器的/usr/src/app/dockerweb/redisweb目录完成项目的生成:

# docker attach $(docker ps -a | grep APP2 | cut -d ' ' -f 1)

# python manage.py makemigrations
No changes detected

# python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

另外一个APP也是同样的配置过程。这样就完成了Docker App Stack应用栈的配置。

在启动Web app服务时,可以指定服务器的端口和IP。为了通过HAProxy容器节点接受外网所有的公共IP地址访问,实现均衡负载,需要指定服务器的IP地址和端口。对于APP1使用8001端口,APP2使用8002端口,同时都使用0.0.0.0地址。以APP1为例,启动服务过程如下:

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

System check identified no issues (0 silenced).
March 19, 2017 - 11:56:42
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.



HAProxy节点的配置

# docker inspect -f '{{.Mounts}}' $(docker ps -a | grep HA | cut -d ' ' -f 1)
[{ /home/zhangxa/Projects/HAProxy /tmp   true rprivate}]

利用容器启动时挂载的Volume将HAProxy的启动配置文件复制进容器中,在主机的Volume目录~/Projects/HAProxy目录下:

# cd $(docker inspect -f '{{.Mounts}}' $(docker ps -a | grep HA | cut -d ' ' -f 1) | cut -d ' ' -f 2 )

vim 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 
    bind    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


随后,进入容器的/tmp目录下,将配置文件拷贝到HAProxy的工作目录下:

# cp /tmp/haproxy.cfg /usr/local/sbin
root@8d3f339b8bad:/# cd /usr/local/sbin

启动haproxy

# haproxy -f haproxy.cfg

然后在本地主机上就可以通过haproxy的地址进行访问web服务了http://172.17.0.7:6301/helloworld.

还可以在另外主机上通过本地主机IP访问,因此在创建容器时我们暴露了容器的内部端口http://192.168.17.133:6301/helloworld

我们还可以尝试干掉一台APP1后,仍然能够继续通过APP2访问。









你可能感兴趣的