单爆手

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 一.需求分析:

 

 

 

 

 

 

 

 

 

 

 

 一发布系统申请上线

1.后端:

(1).apps/release/models.py:

python36env) [vagrant@CentOS devops]$ django-admin startapp release
(python36env) [vagrant@CentOS devops]$ mv release apps/
(python36env) [vagrant@CentOS devops]$ python manage.py makemigrations release
(python36env) [vagrant@CentOS devops]$ python manage.py migrate release

(2).release/views.py

复制代码
from django.contrib.auth import get_user_model
from rest_framework import viewsets, permissions, status
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework import filters
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


from .serializers import DeploySerializer
from .models import Deploy
from time import sleep

User = get_user_model()


class Pagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    page_query_param = "page"
    max_page_size = 100


class DeployViewset(viewsets.ModelViewSet):
    """
    create:
    申请上线
    list:
    获取上线列表
    retrieve:
    获取上线信息
    update:
    代码更新信息
    delete:
    取消上线
    """
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication, BasicAuthentication)
    permission_classes = (permissions.IsAuthenticated, permissions.DjangoModelPermissions)
    queryset = Deploy.objects.all()
    serializer_class = DeploySerializer
    pagination_class = Pagination
    filter_backends = (filters.SearchFilter, filters.OrderingFilter)
    search_fields = ('name',)
    ordering_fields = ('apply_time', 'deploy_time')

    def get_queryset(self):
        rate = self.request.GET.get('status', None)
        applicant = self.request.user
        role = applicant.groups.all().values('name')
        role_name = [r['name'] for r in role]
        queryset = super(DeployViewset, self).get_queryset()

        # 判断传来的status值判断是申请列表还是历史列表
        if rate and int(rate) <= 2:
            queryset = queryset.filter(status__lte=2)
        elif rate and int(rate) > 2:
            queryset = queryset.filter(status__gte=2)
        else:
            pass

        # 判断登陆用户是否是管理员,是则显示所有项目,否则只显示自己的项目
        if "sa" not in role_name:
            queryset = queryset.filter(applicant=applicant)
        return queryset

    # def partial_update(self, request, *args, **kwargs):
    #     pk = kwargs.get("pk")
    #     data = request.data
    #     data['assign_to'] = request.user
    #     print(data)
    #     if int(data['status']) == 3:
    #         print("1111")
    #         jenkins = JenkinsApi()
    #         number = jenkins.get_next_build_number(data['name'])
    #         jenkins.build_job(data['name'], parameters={'tag': data['version']})
    #         sleep(30)
    #         console_output = jenkins.get_build_console_output(data['name'], number)
    #         data['console_output'] = console_output
    #     Deploy.objects.filter(pk=pk).update(**data)
    #     return Response(status=status.HTTP_204_NO_CONTENT)
复制代码

(3).release/serializers.py

复制代码
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Deploy

User = get_user_model()


class DeploySerializer(serializers.ModelSerializer):
    """
    工单序列化类
    """
    # 获取当前登陆用户,并将其赋值给数据库中对应的字段
    applicant = serializers.HiddenField(
        default=serializers.CurrentUserDefault())
    apply_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
    complete_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)

    class Meta:
        model = Deploy
        fields = "__all__"

    def to_representation(self, instance):
        applicant_obj = instance.applicant
        reviewer_obj = instance.reviewer
        assign_to_obj = instance.assign_to
        status_value = instance.get_status_display()
        ret = super(DeploySerializer, self).to_representation(instance)
        ret['status'] = {
            "id": instance.status,
            "name": status_value
        }
        ret["applicant"] = {
                               "id": applicant_obj.id,
                               "name": applicant_obj.name
                           },
        ret["reviewer"] = {
                               "id": reviewer_obj.id,
                               "name": reviewer_obj.name
                           },

        if assign_to_obj:
            ret["assign_to"] = {
                                   "id": assign_to_obj.id,
                                   "name": assign_to_obj.name
                               },
        return ret
复制代码

(4).release/route.py

from rest_framework.routers import DefaultRouter
from .views import DeployViewset

deploy_router = DefaultRouter()
deploy_router.register(r'deploy', DeployViewset, basename="deploy")

(5).release/task.py

(6).devops/urls.py

复制代码
from django.conf.urls import url, include
from rest_framework_jwt.views import obtain_jwt_token
from rest_framework.routers import DefaultRouter
from rest_framework.documentation import include_docs_urls
from groupUsers .views import GroupUsersViewset
from users.router import router as user_router
from workorder.router import workorder_router
from devops.settings import STATIC_ROOT
from release.router import deploy_router
from groups.router import group_router
from permissions.router import permission_router
from groupUsers.router import groupuser_router
from resources.router import router as resources_router

router = DefaultRouter()
router.registry.extend(user_router.registry)
router.registry.extend(workorder_router.registry)
router.registry.extend(group_router.registry)
router.registry.extend(groupuser_router.registry)
router.registry.extend(permission_router.registry)
router.registry.extend(deploy_router.registry)

urlpatterns = [
    url(r'^api/', include(router.urls)),
    url(r'^', include('resources.urls')),
    url(r'^api-auth/', include('rest_framework.urls')),
    url(r'^docs/', include_docs_urls("51reboot接口文档")),
    url('^projects/', include('projects.urls', namespace='projects')),
    url(r'^api-token-auth/', obtain_jwt_token),
]
复制代码

(7).apps/utils/jenkins_api.py

复制代码
import gitlab

from devops.settings import GITLAB_HTTP_URI, GITLAB_TOKEN
gl = gitlab.Gitlab(GITLAB_HTTP_URI, GITLAB_TOKEN)

def get_user_projects(request):
    """
    获取gitlab里所有的项目,和登录用户所拥有的项目,以及登录用户所拥有项目的项目成员
    :return: []
    """
    user_projects = []
    all_projects = gl.projects.list()
    print(request.user.username)
    print(all_projects)

    # 获取当前用户所有的项目
    for project in all_projects:
        print(project)
        for member in project.members.list():
            # if member.username == request.user.username:
            if member.username == "root":
                user_projects.append(project)
    print(user_projects)
    return user_projects


def get_project_versions(project_id):
    """
    获取某个项目的版本号
    :param project_id:
    :return:
    """
    project = gl.projects.get(project_id)
    tags = project.tags.list()
    print(tags)
    return tags
复制代码

效果如图:

2.前端

(1)src/api/release/release.js

复制代码
import request from '@/utils/request'

// 获取申请列表
export function getDeployList(params) {
  return request({
    url: '/api/deploy/',
    method: 'get',
    params
  })
}

// 申请项目上线
export function createDeploy(data) {
  return request({
    url: '/api/deploy/',
    method: 'post',
    data
  })
}

// 更新项目
export function updateDeploy(id, data) {
  return request({
    url: '/api/deploy/' + id + '/',
    method: 'patch',
    data
  })
}
复制代码

(2)src/router/index.js

复制代码
  {
    path: '/release',
    component: Layout,
    name: '代码上线',
    meta: { title: '代码上线', icon: 'user' },
    children: [
      {
        path: 'apply',
        name: '申请上线',
        component: () => import('@/views/release/apply/index'),
        meta: { title: '申请上线', icon: 'user' }
      },
      {
        path: 'list',
        name: '申请列表',
        component: () => import('@/views/release/list/index'),
        meta: { title: '申请列表', icon: 'tree' }
      },
      {
        path: 'history',
        name: '上线列表',
        component: () => import('@/views/release/history/index'),
        meta: { title: '上线列表', icon: 'tree' }
      }
    ]
  },
复制代码

(3)views/release/apply/index.vue

复制代码
<template>
  <div class="apply">
    <el-form ref="form" :model="form" :rules="rules" label-width="180px">
      <el-form-item label="选择项目:" prop="name">
        <el-select v-model="form.name" placeholder="请选择项目类型" style="width: 60%;" @change="getTag">
          <el-option
            v-for="item in project_list"
            :key="item.index"
            :label="item.name"
            :value="item.name"/>
        </el-select>
      </el-form-item>

      <el-form-item label="项目版本:" prop="version">
        <el-select v-model="form.version" value-key="label" placeholder="请选择项目版本" style="width: 60%;" @change="getTaginfo">
          <el-option
            v-for="item in tag_list"
            :key="item.index"
            :label="item.name"
            :value="item.name"/>
        </el-select>
      </el-form-item>

      <el-form-item label="版本信息:" prop="info">
        <el-input v-model="form.info" style="width: 60%;"/>
      </el-form-item>

      <el-form-item label="指派给:" prop="assign_to">
        <el-select v-model="form.reviewer" filterable placeholder="请选择项目处理人" style="width: 60%;">
          <el-option
            v-for="item in sa_list"
            :key="item.index"
            :label="item.name"
            :value="item.id"/>
        </el-select>
      </el-form-item>

      <el-form-item label="上线详情:" prop="detail">
        <el-input :rows="8" v-model="form.detail" type="textarea"  style="width: 60%;"/>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="onSubmit">申请上线</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>

import { getGroupMemberList } from '@/api/group'
import { getProjectList, getProjectTag } from '@/api/project/project'
import { createDeploy } from '@/api/release/release'
export default {
  data() {
    return {
      form: {
        name: '',
        version: '',
        info: '',
        detail: '',
        reviewer: ''
      },
      rules: {
        name: [
          { required: true, message: '请输入项目名称', trigger: 'blur' }
        ],
        version: [
          { required: true, message: '请输入项目版本', trigger: 'blur' }
        ],
        info: [
          { required: true, message: '请输人项目内容', trigger: 'blur' }
        ],
        reviewer: [
          { required: true, message: '请输人项目执行人', trigger: 'blur' }
        ]

      },
      sa_list: [],
      project_list: [],
      tag_list: [],
      state: 0
    }
  },

  watch: {
    state() {
      getGroupMemberList(6).then(res => {
        this.sa_list = res.members
        console.log(this.sa_list)
      })

      getProjectList().then(res => {
        this.project_list = res
        console.log(this.project_list)
      })
    }

  },

  created() {
    this.state = 1
  },

  methods: {
    /* 获取某个项目的tag列表*/
    getTag(name) {
      let obj = {}
      obj = this.project_list.find((item) => {
        return item.name === name
      })
      const params = { 'project_id': obj.id }
      getProjectTag(params).then(res => {
        this.tag_list = res
        console.log(this.tag_list)
      })
    },
    /* 跟进tag名获取message */
    getTaginfo(name) {
      let obj = {}
      obj = this.tag_list.find((item) => {
        return item.name === name
      })
      console.log(obj)
      this.form.info = obj.info
    },
    /* 申请上线 */
    onSubmit() {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        const params = Object.assign({}, this.form)
        console.log(params)
        createDeploy(params).then(res => {
          this.$message({
            message: '申请上线成功',
            type: 'success'
          })
          this.$router.push({ path: '/release/list' })
        })
      })
    }
  }

}
</script>

<style scoped>
.line{
  text-align: center;
}
.apply{
    margin-top:2cm;
}
</style>
复制代码

(4)views/release/list/form.vue

复制代码
<template>
  <div class="deploy-form">
    <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="demo-form">

      <el-form-item label="项目名称" prop="name">
        <el-input v-model="form.name" readonly/>
      </el-form-item>

      <el-form-item label="项目版本" prop="version">
        <el-input v-model="form.version" readonly/>
      </el-form-item>

      <el-form-item label="项目描述" prop="info">
        <el-input v-model="form.info" readonly/>
      </el-form-item>

      <el-form-item label="项目详情" prop="detail">
        <el-input v-model="form.detail" type="textarea" rows="8" readonly/>
      </el-form-item>

      <el-form-item>
        <div class="btn-wrapper">
          <el-button size="small" type="primary" @click="submitForm">下一步</el-button>
        </div>
      </el-form-item>

    </el-form>
  </div>
</template>

<script>

export default {
  name: 'DeployForm',
  props: {
    form: { // 接受父组件传递过来的值渲染表单
      type: Object,
      default() {
        return {
          name: '',
          info: '',
          version: '',
          detail: '',
          status: ''
        }
      }
    }
  },

  data() {
    return {
      rules: {
        name: [
          { required: true, message: '请输入处理结果', trigger: 'blur' }
        ]
      }
    }
  },

  methods: {
    submitForm() {
      this.$refs.form.validate(valid => {
        if (!valid) {
          return
        }
        this.$emit('submit', this.form)
      })
    }
  }
}
</script>

<style lang='scss' scoped>
.deploy-form {
  position: relative;
  display: block;
  .btn-wrapper{
    text-align: right;
  }
}
</style>
复制代码

(5)views/release/list/index.vue

复制代码
<template>
  <div class="release">
    <div>
      <!--搜索-->
      <el-col :span="8">
        <el-input v-model="params.search" placeholder="搜索" @keyup.enter.native="searchClick">
          <el-button slot="append" icon="el-icon-search" @click="searchClick"/>
        </el-input>
      </el-col>
    </div>

    <!--表格-->
    <deploy-list :value="release" @edit="handleEdit" @delete="handleDelete"/>

    <!--模态窗-->
    <el-dialog
      :visible.sync="dialogVisibleForEdit"
      title="上线进度"
      width="50%">
      <el-steps :active="active" finish-status="success" simple style="margin-top: 20px">
        <el-step title="申请" />
        <el-step title="审核" />
        <el-step title="灰度" />
        <el-step title="上线" />
      </el-steps>
      <br>
      <deploy-form
        ref="releaseForm"
        :form="currentValue"
        @submit="handleSubmitEdit"/>
    </el-dialog>

    <!--分页-->
    <center>
      <el-pagination
        :page-size="pagesize"
        :total="totalNum"
        background
        layout="total, prev, pager, next, jumper"
        @current-change="handleCurrentChange"/>
    </center>
  </div>
</template>

<script>
import { getDeployList, updateDeploy } from '@/api/release/release'
import DeployList from './table'
import DeployForm from './form'

export default {
  name: 'Release',
  components: {
    DeployList,
    DeployForm
  },

  data() {
    return {
      dialogVisibleForEdit: false,
      currentValue: {},
      release: [],
      totalNum: 0,
      pagesize: 10,
      active: 1,
      params: {
        page: 1,
        search: '',
        ordering: '-deploy_time',
        status: 0
      }
    }
  },

  created() {
    this.fetchData()
  },

  methods: {
    fetchData() {
      getDeployList(this.params).then(
        res => {
          this.release = res.results
          console.log(this.release)
          this.totalNum = res.count
        })
    },
    handleCurrentChange(val) {
      this.params.page = val
      this.fetchData()
    },
    searchClick() {
      this.fetchData()
    },

    /* 处理上线申请,弹出模态窗、提交数据、取消 */
    handleEdit(value) {
      this.currentValue = { ...value }
      this.dialogVisibleForEdit = true
      this.params.status = this.currentValue.status.id
      this.active = this.params.status + 1
    },

    handleSubmitEdit(value) {
      const { id, ...params } = value
      console.log(params)
      const formdata = { 'status': this.params.status + 1, 'name': params.name, 'version': params.version }
      updateDeploy(id, formdata).then(res => {
        this.$message({
          message: '更新成功',
          type: 'success'
        })
      })
      this.fetchData()
      this.dialogVisibleForEdit = false
    },

    /* 取消 */
    handleDelete(id) {
      console.log(id)
      const data = { 'status': 4 }
      updateDeploy(id, data).then(res => {
        this.$message({
          message: '取消成功',
          type: 'success'
        })
        this.fetchData()
      },
      err => {
        console.log(err.message)
      })
    }

  }

}
</script>

<style lang='scss' scoped>
.release {
  padding: 10px;
}
</style>
复制代码

(6)views/release/list/table.vue

复制代码
<template>
  <div class="deploy-list">
    <el-table
      :data="value"
      border
      stripe
      style="width: 100%">

      <el-table-column type="expand">
        <template slot-scope="props">
          <span><pre>版本描述:{{ props.row.info }}</pre></span>
          <span><pre>发布信息:{{ props.row.detail }}</pre></span>
        </template>
      </el-table-column>

      <el-table-column
        label="项目名称"
        prop="name"/>

      <el-table-column
        label="项目版本"
        prop="version"/>

      <el-table-column
        label="申请人"
        prop="applicant[0].name"/>

      <el-table-column
        label="审核人"
        prop="reviewer[0].name"/>

      <el-table-column
        label="状态"
        prop="status.name"/>

      <el-table-column
        :formatter="dateFormat"
        label="申请时间"
        prop="apply_time"
      />

      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="primary"
            @click="handleEdit(scope.row)">处理</el-button>

          <el-button
            size="mini"
            type="danger"
            @click="handleDelete(scope.row)">取消</el-button>
        </template>
      </el-table-column>

    </el-table>
  </div>
</template>

<script>
import moment from 'moment'

export default {
  name: 'DeployList',
  props: {
    value: {
      type: Array,
      default: function() {
        return []
      }
    }
  },
  methods: {
    /* 点击编辑按钮,将子组件的事件传递给父组件 */
    handleEdit(value) {
      this.$emit('edit', value)
    },

    /* 删除 */
    handleDelete(value) {
      const id = value.id
      const name = value.name
      this.$confirm(`取消上线: ${name}, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$emit('delete', id)
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },
    dateFormat: function(row, column) {
      const date = row[column.property]
      if (date === undefined) {
        return ''
      }
      return moment(date).format('YYYY-MM-DD HH:mm:ss')
    }

  }
}
</script>

<style lang='scss'>
</style>
复制代码

 效果如图:

 报错--前端post请求报400错误:认证失败Uncaught (in promise) Error: Request failed with status code 400

一般是前后端交互的方法参数不一致,发生此错误需要仔细检查前端传递的参数数据的参数名、参数数目、参数类型是否与后端保持一致。

 

 

 

 

 三.Jenkins api

复制代码
jenkins部署:
jdk安装:
[root@VM_0_5_centos ~]#tar -zxvf jdk-8u261-linux-x64.tar.gz -C /usr/local/java/
[root@VM_0_5_centos ~]#vi /etc/profile
export JAVA_HOME=/usr/local/java/jdk1.8.0_261
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
[root@VM_0_5_centos ~]#source /etc/profile
[root@VM_0_5_centos ~]# java -version
安装配置:
各种报错参考此文档https://www.ddkiss.com/archives/167.html
[root@VM_0_5_centos ~]# rpm -ivh jenkins-2.99-1.1.noarch.rpm
[root@VM_0_5_centos ~]# vi /etc/sysconfig/jenkins
JENKINS_USER="root"JENKINS_PORT="8088"
修改目录权限:
[root@VM_0_5_centos ~]# chown -R root:root /var/lib/jenkins
[root@VM_0_5_centos ~]# chown -R root:root /var/cache/jenkins
[root@VM_0_5_centos ~]# chown -R root:root /var/log/jenkins

[root@VM_0_5_centos ~]# vi /etc/init.d/jenkins
第一个java路径就是我自己加的!
candidates="
/usr/local/java/jdk1.8.0_261/bin/java
/etc/alternatives/java
/usr/lib/jvm/java-1.8.0/bin/java
/usr/lib/jvm/jre-1.8.0/bin/java
/usr/lib/jvm/java-1.7.0/bin/java
/usr/lib/jvm/jre-1.7.0/bin/java
/usr/bin/java
"
[root@VM_0_5_centos ~]# systemctl start jenkins
[root@VM_0_5_centos ~]# systemctl status jenkins
放通腾讯云服务器8088端口:
(1)进入控制台页面-->安全组--->添加安全组

(2)点击刚创建的规则id--点关联实例---新增关联

 

 

 这就就可直接在你windows机器访问腾讯云的jenkins服务了!!如下图:

复制代码

 jenkins要安装Git Parameter插件---支持参数化构建。如下图

 

 

 

 

 

 2.jenkins api使用

 

 

 

复制代码
(python36env) [vagrant@CentOS devops]$ pip install python-jenkins
python36env) [vagrant@CentOS devops]$ ipython
In [1]: import jenkins                                                     
In [2]: JENKINS_URL = "http://120.53.122.**:8088"                          
In [3]: JENKINS_USERNAME = 'root'                                          
In [4]: JENKINS_PASSWORD = '181818jn'                                      
In [5]: server = jenkins.Jenkins(JENKINS_URL, username = JENKINS_USERNAME, 
   ...: password = JENKINS_PASSWORD)                                       
In [6]: server.get_job_info("51reboot") 
In [9]:server.build_job("51reboot1", parameters={'tag': "version1.0"}) 
In [10]: server.build_job("51reboot1", parameters={'tag': "version1.1"})

In [13]: server.get_build_console_output("51reboot1", 2) 

In [14]: server.get_job_info('51reboot1')['nextBuildNumber']
Out[14]: 3

 

复制代码

(1)devops/settings.py:

JENKINS_URL = "http://120.53.122.**:8088"
JENINS_TOKEN = "9b6bd371a9ba47511a0f04184e1076df"
JENKINS_USERNAME = 'root'
JENKINS_PASSWORD = '18181**'

(2)apps/utils/jenkis_api.py:

复制代码
from jenkins import Jenkins
from devops.settings import JENKINS_URL, JENKINS_USERNAME, JENKINS_PASSWORD


class JenkinsApi:
    def __init__(self):
        self.url = JENKINS_URL
        self.username = JENKINS_USERNAME
        self.password = JENKINS_PASSWORD
        self.server = self.connect()

    def connect(self):
        """
        连接jenkins(实例化jenkins)
        :return:
        """
        server = Jenkins(self.url, username=self.username, password=self.password)
        return server

    def get_next_build_number(self, name):
        """
        获取下一次构建号
        :param name: 任务名称(项目名称)
        :return: "int" number
        """
        return self.server.get_job_info(name)['nextBuildNumber']

    def build_job(self, name, parameters=None):
        """
        构建任务
        :param name: "str" 任务名称
        :param parameters: "dict" 参数
        :return: "int" queue number
        """
        return self.server.build_job(name=name, parameters=parameters)

    def get_build_console_output(self, name, number):
        """
        获取终端输出结果
        :param name: "str" 任务名称
        :param number: "str" 构建号
        :return: "str" 结果
        """
        return self.server.get_build_console_output(name, number)
复制代码

 (3)apps/release/views.py:

复制代码
from utils.jenkins_api import JenkinsApi
from .serializers import DeploySerializer
from .models import Deploy
from time import sleep

User = get_user_model()

class Pagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    page_query_param = "page"
    max_page_size = 100

class DeployViewset(viewsets.ModelViewSet):
   .......
    def partial_update(self, request, *args, **kwargs):
        pk = kwargs.get("pk")
        data = request.data
        data['assign_to'] = request.user
        print(data)
        if int(data['status']) == 3:
            print("1111")
            jenkins = JenkinsApi()
            number = jenkins.get_next_build_number(data['name'])
            jenkins.build_job(data['name'], parameters={'tag': data['version']})
            sleep(30)
            console_output = jenkins.get_build_console_output(data['name'], number)
            data['console_output'] = console_output
        Deploy.objects.filter(pk=pk).update(**data)
        return Response(status=status.HTTP_204_NO_CONTENT)
复制代码

效果如图:

 四.部署

 参考:https://segmentfault.com/a/1190000004232816--如下说明

 

(1)devops/settings.py:

DEBUG = False
ALLOWED_HOSTS = ["*"]

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")

(2)devops/urls.py:

复制代码
from django.views.static import serve
from restfuldemo.settings import STATIC_ROOT

urlpatterns = [
    url(r'^api/', include(router.urls)),
    url(r'^', include('resources.urls')),
    url(r'^api-auth/', include('rest_framework.urls')),
    url(r'^docs/', include_docs_urls("51reboot接口文档")),
    url('^projects/', include('projects.urls', namespace='projects')),
    url(r'^login/', obtain_jwt_token),
    url(r'^api-token-auth/', obtain_jwt_token),
    url(r'^static/(?P<path>.*)$', serve, {"document_root": STATIC_ROOT}),
]
复制代码
(3)(python36env) [vagrant@CentOS devops]$ ls
apps  dashboard  devops  manage.py
(python36env) [vagrant@CentOS devops]$ mkdir static
(python36env) [vagrant@CentOS devops]$ ./manage.py collectstatic
(python36env) [vagrant@CentOS devops]$ ls static/
admin  rest_framework

这样就能正常访问了,如下图:

 

(4)gunicorn部署:
(python36env) [vagrant@CentOS devops]$ pip install -U gunicorn
(python36env) [vagrant@CentOS devops]$ gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009
[2020-07-26 07:03:54 +0200] [4300] [INFO] Using worker: sync
[2020-07-26 07:03:54 +0200] [4303] [INFO] Booting worker with pid: 4303.......
(python36env) [vagrant@CentOS devops]$ gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
(python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
//(python36env) [vagrant@CentOS devops]$ killall gunicorn

报错:ERR_CONNECTION_REFUSED

(python36env) [vagrant@CentOS devops]$ curl 127.0.0.1:8009/api/
{"detail":"身份认证信息未提供。"}

(5)devops/conf/devops_nginx.conf

复制代码
upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8004; # for a web port socket (we'll use this first)
}
# configuration of the server

server {
    listen      80;
    server_name 127.0.0.1;
    # 指向django的static目录
    location /static {
        alias /vagrant/devops/devops/static;
    }
    location / {
        uwsgi_pass 127.0.0.1:8009;
        include uwsgi_params;
    }
    error_log /tmp/devops8_error.log;
    access_log /tmp/devops8_access.log;
}
复制代码

(6)devops/conf/devops_uwsgi.ini

复制代码
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /vagrant/devops/devops
# Django's wsgi file
module          = devops.wsgi
# the virtualenv (full path)

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = 0.0.0.0:8009
# ... with appropriate permissions - may be needed
# chmod-socket    = 664
# clear environment on exit
vacuum          = true
virtualenv = /home/vagrant/python36env

# pid file path
pidfile         = /tmp/devops.pid
# background process and specify the log file
daemonize       = /tmp/devops.log
# log file max size(KB)
log-maxsize     = 50000000
复制代码

 

复制代码
(python36env) [vagrant@CentOS devops]$pip install uwsgi
(python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
vagrant   4579     1  1 08:05 ?        00:00:00 /home/vagrant/python36env/bin/python /home/vagrant/python36env/bin/gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
vagrant   4582  4579 17 08:05 ?        00:00:01 /home/vagrant/python36env/bin/python /home/vagr
(python36env) [vagrant@CentOS devops]$ kill -HUP 4579
(python36env) [vagrant@CentOS devops]$ ps -ef|grep gun
vagrant   4579     1  0 08:05 ?        00:00:00 /home/vagrant/python36env/bin/python /home/vagrant/python36env/bin/gunicorn devops.wsgi:application -w 4 -b 0.0.0.0:8009 -D
(python36env) [vagrant@CentOS devops]$ cd conf
(python36env) [vagrant@CentOS conf]$ ls
devops_nginx.conf  devops_uwsgi.ini
(python36env) [vagrant@CentOS conf]$ uwsgi -i devops_uwsgi.ini
(python36env) [vagrant@CentOS conf]$ ps -ef|grep 8009
复制代码

1

2

3

posted on   单爆手  阅读(1449)  评论(1编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示