背景

标题说是三天速成,其实只是想装一下*而已,严格来说本菜其实一直都有去了解docker方面的相关知识,只是没有机会(其实就是自己懒)去真正操作而已,刚好最近公司需要用到,于是用了三天完成了理论到实践的蜕变。

docker, docker-compose, Kubernetes,k8s

对docker不太熟悉的小伙伴对这些名词是不是一脸懵逼?反正我是的,之前整天听人家提到这些名词,感觉很牛逼的样子。其实当你去了解的时候发现也就是几个名词而已。简单来说,docker就是一种虚拟化技术,可以看成一个超轻量级的虚拟机,当然跟虚拟机差别还是很大的,具体介绍自行问度娘。docker-compose是单机管理docker多个容器的工具,Kubernetes是分布式管理docker的工具,k8s是Kubernetes的缩写,因为省略了中间8个字母,所以叫k8s。

docker介绍

Image

如果你自己装个系统,那你对镜像一定不陌生。但是和 windows 的那种 iso 镜像相比,Docker 中的镜像是分层的,可复用的,而非简单的一堆文件迭在一起(类似于一个压缩包的源码和一个 git 仓库的区别)。如果按编程语言的概念来看的话。镜像可以看成一个class

Container

容器的存在离不开镜像的支持,他是镜像运行时的一个载体。依托 Docker 的虚拟化技术,给容器创建了独立的端口、进程、文件等“空间”,Container 就是一个与宿机隔离 “容器”。容器可宿主机之间可以进行 port、volumes、network 等的通信。如果按编程语言的概念来看的话。容器可以看成一个对象。容器启动的过程就是new一个新对象的过程

Repository

Docker 的仓库和 git 的仓库比较相似,拥有仓库名、tag。在本地构建完镜像之后,即可通过仓库进行镜像的分发。常用的 Docker hub 有 https://hub.docker.com/ 、 https://cr.console.aliyun.com/ 等。如果按编程语言的概念来看的话,仓库就是别人建好的轮子,你可以下载别人的封装好的包(镜像)来创建对象(容器)

开始部署

安装环境

部署方式选择了 docker 加 docker-compose,因此需要安装 docker 和 docker-compose。

docker 可以通过 sudo apt install docker-ce 命令安装。

docker-compose 可通过以下命令安装。

  1. 下载docker-compose:
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.22.0/docker-compose-`uname  -s`-`uname -m` > /usr/local/bin/docker-compose 
  1. 添加权限
sudo chmod +x /usr/local/bin/docker-compose

安装完成以后,输入 docker versiondocker-compose version 可查看是否安装成功。

部署分析

Docker在进程管理上有一些特殊之处,如果不注意这些细节中的魔鬼就会带来一些隐患。另外Docker鼓励“一个容器一个进程(one process per container)”的方式。这种方式非常适合以单进程为主的微服务架构的应用。然而由于一些传统的应用是由若干紧耦合的多个进程构成的,这些进程难以拆分到不同的容器中,所以在单个容器内运行多个进程便成了一种折衷方案;此外在一些场景中,用户期望利用Docker容器来作为轻量级的虚拟化方案,动态的安装配置应用,这也需要在容器中运行多个进程。而在Docker容器中的正确运行多进程应用将给开发者带来更多的挑战

按照一个进程一个容器原则,本次部署一共有下面几个容器(celery和uwsgi与web耦合较高未进行拆分)
总共五个容器:

  • Redis 容器:缓存服务
  • Mongo容器: 用户行为日志存储
  • Mysql 容器:数据存储
  • Django(uwsgi,celery)容器:处理动态请求
  • Nginx 容器:反向代理,处理静态资源

项目结构

目录结构
featech_v2_0 是 django 项目目录,deployment 文件夹放置了除 Django 容器外的三个容器配置信息以及其他挂载(容器和宿主机的共享卷)的其他文件。

  • Dockerfile:docker 环境文件
  • docker-compose.yml:编排容器文件
  • data:data文件夹主要挂载数据库的数据,因为数据库数据应该是独立于容器存在,不随着容器的销毁而销毁的。
  • conf: conf文件夹主要就是挂载对应进程的配置文件,这样当我们需要修改配置时就可以直接在宿主机操作而不用docker exec进入容器操作,方便灵活。
  • init: init文件加主要是挂载一些初始化数据脚本

构建django容器

dockerfile编写

# 使用python:3.7.3作为基础镜像
FROM python:3.7.3

# 设置 python 环境变量
ENV PYTHONUNBUFFERED 1

# 创建项目目录并将本地项目目录文件复制到容器
RUN mkdir /featech_v2_0
COPY ./featech_v2_0  /featech_v2_0

# 设置工作目录,后续容器的操作都是基于此目录
WORKDIR /featech_v2_0

# 设置pip源(科学上网者可忽略)
RUN pip config set global.index-url http://mirrors.aliyun.com/pypi/simple
RUN pip config set install.trusted-host mirrors.aliyun.com

# 升级pip并安装python依赖
RUN pip install -U pip
RUN pip install -r /featech_v2_0/requirement.txt

暴露端口8888
EXPOSE 8888

构建Nginx容器

Nginx容器dockerfile编写(这一步有点多余了,其实这里只是简单的创建了几个文件夹,完全可以放到docker-compose.yml中的command执行)

# nginx镜像
FROM daocloud.io/nginx

# 创建静态资源文件夹和ssl证书保存文件夹
RUN && mkdir -p /usr/share/nginx/html/static \
&& mkdir -p /usr/share/nginx/html/media \
&& mkdir -p /usr/share/nginx/ssl
  1. 修改Nginx配置文件

配置反向代理时,注意 host 一定要改为 web,web即是django容器的名称(在docker-compose.yml中配置)

server {
    listen 80; # 监听80端口
    server_name  127.0.0.1;  # 生产环境请换成域名
    location / {
        proxy_pass http://web:8000; # 反向代理 django容器8000端口,web为django容器名称,切记不要写域名或者ip
        proxy_set_header Host $host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /static/ {
        alias /usr/share/nginx/html/static/; #静态资源路径
    }
    location /media/ {
        alias /usr/share/nginx/html/media/; #上传文件路径
    }
}

利用 docker-compose 编排容器

编写 docker-compose.yml

version: '3'
services:
    redis:
        image: daocloud.io/redis:3
        container_name: featech_redis
        command: redis-server
        volumes:
          - ./deployment/redis/data:/data  # 挂载数据库数据文件夹
        ports:
          - "6373:6379"
        restart: always # always表容器运行发生错误时一直重启

    db:
        image: mysql:5.7
        container_name: featech_db
        ports:
            - "3303:3306"
        volumes:
            - ./deployment/mysql/data:/var/lib/mysql # 挂载数据库数据
        #    - ./deployment/mysql/conf/my.cnf:/etc/mysql/my.cnf # 挂载配置文件
            - ./deployment/mysql/init:/docker-entrypoint-initdb.d/ # 挂载数据初始化sql脚本

        environment:
            MYSQL_ROOT_PASSWORD: 13456  # 数据库密码
            MYSQL_DATABASE: abc  # 数据库名称
            LNAG: C.UTF-8
        command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
    web:
        build: .
        container_name: featech_v2_0
        
        # tty: true  如果web容器出错想进入容器做修改时,此配置可分配一个伪终端让容器先运行起来
        
        # 容器启动后启动通过uwsgi启动django应用并启动celery,这里我简单实用了nohup启动celery,可选择使用supervisor管理
        command uwsgi --ini uwsgi && nohup celery -A celery_tasks.sms.tasks worker -l info >> celery_log/celery.log 2>&1 &
        
        depends_on:
            - db
            - redis
            - mongo 
        links:
            - db
            - redis
            - mongo 
        volumes:
            - ./featech_v2_0:/featech_v2_0  # 挂载项目目录
        restart: always
        ports:
            - "8888:8888"
    nginx:
        build: deployment/nginx
        container_name: featech_nginx
        ports:
          - "80:80"
          - "443:443"
        expose:
          - "8888"
        volumes:
          - ./featech_v2_0/static:/usr/share/nginx/html/static # 挂载静态文件
          - ./featech_v2_0/frontEnd:/usr/share/nginx/html/frontEnd # 挂载静态文件
          - ./featech_v2_0/media:/usr/share/nginx/html/upload # 挂载上传文件
          - ./deployment/nginx/ssl:/usr/share/nginx/ssl # 挂载ssl证书目录
          - ./deployment/nginx/conf/conf.d:/etc/nginx/conf.d # 挂载配置文件
        links:
          - web
        depends_on:
          - web
        restart: always
    mongo:
        image: mongo:4.0
        container_name: featech_mongo
        hostname: mongo
        restart: always
        ports:
          - "27013:27017"
        environment:
          TZ: Asia/Shanghai
      #MONGO_INITDB_DATABASE: test
      #MONGO_INITDB_ROOT_USERNAME: root
      #MONGO_INITDB_ROOT_PASSWORD: 123456
        volumes:
          - /etc/localtime:/etc/localtime
          - ./deployment/mongo/data:/data/db
          - ./deployment/mongo/init:/docker-entrypoint-initdb.d/
        command: mongod

redis,db,web,nginx,mongo为容器名称。

  • image 表示拉取镜像名称,build会在给定目录下寻找 Dockerfile 并构建容器环境。
  • expose 表示将端口暴露给其他容器,但不暴露给主机(不同容器默认相互隔离)。
  • ports 表示将该容器端口映射到主机端口(从右往左读,例如ports: -
    “3303:3306”,是指把容器的3306端口映射到主机的3303端口),同时该容器端口也会对其他容器开放。
  • volumes
    表示挂载,就是将本机的文件和容器中的文件映射起来,容器和本地环境本来是隔离的,挂载相当于是凿了一个小洞,让两者数据可以互通。
  • links 表示将容器互联起来。
  • depends_on:表示依赖关系,因为容器的启动有先后顺序,django 容器依赖于 mysql 容器和 redis
    容器(django需要从数据库和缓存中读写数据),而 nginx 依赖于 django 容器(nginx 容器需要反向代理 django容器的8888端口)

构建、运行容器

修改配置host为容器名称

  • 在构建运行容器之前,需要修改 django 项目的 settings.py文件。

  • 将 数据库连接 HOST 改为 mysql 容器名称 db

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  # mysql驱动
        'NAME': 'fetach_v2_0',  # 数据库名称
        'USER': 'root',  # 登录帐号
        'PASSWORD': '19960331',  # 登录密码
        'HOST': 'db',  # 主机地址(容器部署)
        # 'HOST': '127.0.0.1',  # 主机地址
        'PORT': '3306',  # 端口
        'OPTIONS': {'charset': 'utf8mb4'},
    }
}

将缓存配置中的 host 改为 redis 容器名称 redis(如果你配置了redis作为缓存的话,没配置的话请忽略)

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://redis:6379',  # redis(容器)
        # 'LOCATION': '127.0.0.1:6379',
        'OPTIONS': {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100},
            'SOCKET_TIMEOUT': 10,
        },
    },
}

将celery配置中间人的redis中间人改为 redis 容器名称 redis(如果你的celery中间人选择了redis的话)
生产环境部署请将 settings.py 中的 DEBUG = True 改为 DEBUG = False以关闭debug模式。

broker_url = "redis://redis/2"
result_backend = "redis://redis/3"

使用Docker-compose构建项目

经过以上的努力,基本准备齐备了,我们可以构造我们的镜像了。

docker-compose build

经过一阵儿下载或者构建,就能看到成功构建镜像的信息了。
构建完成后,就有了web服务的镜像了,我们现在使用docker-compose来启动服务。

docker-compose up -d

这个过程可能也需要执行一阵儿,取决于你的网速,它会下载相应的镜像,并且根据下载的镜像和刚才我们通过dockerfile构建的镜像构造容器,并运行容器。完成后可以使用docker-compose ps和docker-compose images来查看我们生成的容器和镜像

 docker-compose ps
    Name                   Command               State                         Ports                       
-----------------------------------------------------------------------------------------------------------
featech_db      docker-entrypoint.sh mysql ...   Up      0.0.0.0:3303->3306/tcp, 33060/tcp                 
featech_mongo   docker-entrypoint.sh mongod      Up      0.0.0.0:27013->27017/tcp                          
featech_nginx   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp, 8000/tcp
featech_redis   docker-entrypoint.sh redis ...   Up      0.0.0.0:6373->6379/tcp                            
featech_v2_0    python3                          Up      0.0.0.0:8888->8888/tcp   
 docker-compose images
  Container        Repository        Tag       Image Id       Size  
--------------------------------------------------------------------
featech_db      mysql               5.7      a4fdfd462add   448.1 MB
featech_mongo   mongo               4.0      78b4116161e4   418.6 MB
featech_nginx   my_docker_nginx     latest   8704e0b5b7b8   132.1 MB
featech_redis   daocloud.io/redis   3        87856cc39862   75.99 MB
featech_v2_0    featech_web         v2       243c6dd41d00   1.656 GB

也可使用docker-compose来停止和开始服务,其他更具体的使用方法,请参考官方文档吧。

保存容器

如果服务一切正常,我们就要把当前的容器保存起来,为部署到新平台上做准备。注意: 这里要使用save保存镜像,使用save是包括容器之间的连接状态等信息的,如果用export导出镜像到生产环境是不能使用docker-compose恢复服务的。

docker save -o mysql.tar mysql:5.7

docker save -o featech_web.tar featech_web:latest
......

复制代码当以上命令执行成功后会在当前目录生成对应tar文件,再加上Dockerfile和docker-compose.yml等文件放在一起准备迁移到生产机器上。
安装生产环境的 Docker-ce 和 docker-compose
使用scp或者其他工具把mysql.tar、mysite.tar、Docker-compose.yml以及项目文件夹发送到生产服务器,并找一个合适的文件夹存放这些文件,保持原来的目录结构。
我们先把镜像恢复到生产服务器上

docker load -i mysql.tar
docker load -i mysite_web.tar
......

复制代码等待一小会儿执行完成,可以看到当前服务器已经有对应镜像了。

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
featech_web          latest              3989acbcc3c9        2 days ago          983MB
mysql              	 5.7                 e47e309f72c8        3 weeks ago         372MB
......

复制代码在执行构建容器以前我们还要对docker-compose.yml做个简单的修改。这次build的服务改为从镜像运行就行了,内容大致如下:

version: '3'
services:
    db:
      ...
    web:
    	#build: .
      	image: featech_web:latest
      ...

只要更改web中的build项删除,并加上一个image项,内容就是我们拷贝过来的那个镜像。稍后我们就可以构建容器并启动服务了。

 docker-compose up -d
Name                  Command               State                 Ports              
----------------------------------------------------------------------------------------
featech_web   bash -c python manage.py m ...   Up      0.0.0.0:8888->8888/tcp           
featech_db     docker-entrypoint.sh mysqld      Up      0.0.0.0:3303->3306/tcp, 33060/tcp
启动成功!

参考链接

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐