本文工具准备:

  • Docker for Windows
  • Visual Studio 2015 与 Visual Studio Tools for Docker
  • 或 Visual Studio 2017 需要在安装时选择“容器开发支持”,如图:

Docker的思想是将不同的应用放在不同的容器中分开运行,如运行.NetCore Web的典型组合Nginx+.NETCore(kestrel),我们应该使用一个容器运行Nginx,另一个容器运行.NETCore App。

之前还陷入一个误区,一直在研究如何将dotnet与Nginx配置实现到一个Dockerfile中,后来了解到Docker Compose才知道这两者应该分开到不同的容器。

服务器端安装Docker与Docker Compose

此文

DotnetCore的Dockerfile

一般来说通过Visual Studio 2015 Tools for Docker给项目添加Docker支持后,项目中就会有Dockerfile与docker-compose.xml的初始模板。只需要修改其中的内容适应我们的项目即可。

Visual Studio的2017可以在新建项目时,或建立项目以后选择添加Docker支持。

Visual Studio 2017稍有不同的是其将docker-compose.yml文件作为解决方案级文件来管理。这对于组合多个项目是很有帮助的。如图:

本文最初编写时项目使用的Visual Studio 2015,所以docker-compose.yml还都是在Web项目中。但下文的设置对这两种组织方式都支持,稍微调整一下路径即可。

首先是默认Dockerfile的文件,我们将其配置为运行dotnet

  1. FROM microsoft/aspnetcore:1.0
  2. ENTRYPOINT ["dotnet", "orgname.projname.WebApi.dll"]
  3. ARG source=.
  4. WORKDIR /app
  5. EXPOSE 5000
  6. COPY $source /app

aspnetcore这个Iamge有1.0和1.1两个版本,根据项目所使用的.NETCore版本自行更换

单独测试下这个Dockerfile的image生成

  1. docker rmi orgname/projname.core:test
  2. docker build --rm -t orgname/projname.core:test -f Dockerfile .

测试下镜像作为容器运行:

  1. docker run --name projname.core.inst -p 5000:5000 orgname/projname.core:test

测试完成后,把所有测试产物,如镜像和容器,都删除。

  1. docker stop projname.core.inst
  2. docker rm -f projname.core.inst
  3. docker rmi orgname/projname.core:test

在刚开始编写Dockerfile打包镜像时,可能会反复进行生成,运行容器的步骤。为了方便测试,楼主把这些脚本整合成了一个buildtest.bat,如下。

  1. @echo on
  2. SET /p app=.NETCoreWeb(d)Nginx(n)
  3. SET /p job=生成并运行(r)清理(c)
  4. SET /p mode=交互运行(i)后台运行(b)
  5. if "%app%"=="d" (
  6. SET contName=projname.core.inst
  7. SET imagName=orgname/projname.core:test
  8. SET file=Dockerfile
  9. )
  10. if "%app=%"=="n" (
  11. SET contName=projname.core.pub.inst
  12. SET imagName=orgname/projname.core.pub:test
  13. SET file=Dockerfile-Nginx
  14. )
  15. if "%mode%"=="i" (
  16. SET operate=-it
  17. )
  18. if "%mode%"=="b" (
  19. SET operate=-d
  20. )
  21. if "%job%"=="r" (
  22. GOTO Build
  23. )
  24. if "%job%"=="c" (
  25. GOTO Clear
  26. )
  27. :Build
  28. docker stop %contName%
  29. docker rm -f %contName%
  30. docker rmi %imagName%
  31. docker build --rm -t %imagName% -f %file% .
  32. docker run %operate% --name %contName% -p 5000:5000 -e "ASPNETCORE_ENVIRONMENT=Staging" %imagName%
  33. GOTO End
  34. :Clear
  35. docker stop %contName%
  36. docker rm -f %contName%
  37. docker rmi %imagName%
  38. docker ps -a
  39. docker images
  40. GOTO End
  41. :End

楼主一般用Docker for Windows做测试,自然也就写了批处理的脚本,后来(这篇文章慢慢的攒了一段时间才最终完成)为了调试方便转投PowerShell。

包括这个脚本在内的本文提供的几个脚本都非常好用,谁用谁知道。

Nginx的Dockerfile

首先是Nginx的配置文件,这是比较重要的一个配置,Nginx的Docker Image生成到时候会复制这个文件到Nginx Docker Image内。

本文介绍普通的80端口的转发,配置如下:

  1. server {
  2. listen 8081;
  3. location / {
  4. proxy_pass http://core-app:5000;
  5. proxy_http_version 1.1;
  6. proxy_set_header Upgrade $http_upgrade;
  7. proxy_set_header Connection keep-alive;
  8. proxy_set_header Host $host;
  9. proxy_cache_bypass $http_upgrade;
  10. }
  11. }

注意 配置中的转发地址,不再是localhost,而是需要根据link所指定的服务/容器的别名来确定。这个link参数,在下面有示例。

这个涉及到Docker网络,这是个非常复杂的话题。

注意nginx.conf需要ANSI编码,且换行为Linux格式,否则导入容器中可能会报错。(可以使用Notepad++编辑,使用VS编辑可能会出问题)

还可以配置Nginx使用HTTPS,或者使用Nginx配置简单的负载均衡,如果以后楼主有机会研究的话会再写文章分享。

测试下Nginx的Docker Image的生成:

  1. docker build --rm -t orgname/projname.core.pub:test -f Dockerfile-Nginx .

启动容器来测试:

  1. docker run --name projname.core.pub.inst -p 8081:8081 --link projname.core.inst:core-app orgname/projname.core.pub:test

注意:link即指示链接到的之前创建的运行.net core的容器,冒号后面部分是指定别名。这个别名就是前文Ngnix配置文件中,所转发的地址。

如果启动Nginx容器后,可以通过Nginx访问.NET Core Web App,说明到此为止的配置都是正确的。

可以继续配置docker compose了。

清理测试产物:

  1. docker stop projname.core.pub.inst
  2. docker rm -f projname.core.pub.inst
  3. docker rmi orgname/projname.core.pub:test

将docker相关文件添加到项目发布文件

(VS2015)编辑project.json文件中publishOptions-include的数组,将Dockerfile、Dockerfile-Nginx、nginx.conf及docker-compose.yml添加到其中。

一般来说,按照之前步骤添加“Docker Support”后,插件会自动将相关文件添加到project.jsonpublishOptions中,这一步进行确认就好。

(VS2017)在解决方案资源管理器中将Dockerfile、Dockerfile-Nginx、nginx.conf及docker-compose.yml包含在项目中。“复制到输出目录”选择“如果较新则复制”。

发布项目

使用下面命令发布项目

  1. dotnet publish --framework netcoreapp1.0 --configuration release --output publish.linux

可以将这条命令保存为一个批处理文件,如publish.linux.bat,放到项目根目录下

编辑Docker Compose配置文件

docker compose配置文件基本上就之前用到的docker build和docker run命令的另一种表述形式

  1. version: '3'
  2. services:
  3. orgname.projname.webapi:
  4. image: orgname/projname.core:${TAG}
  5. build:
  6. context: .
  7. dockerfile: Dockerfile
  8. expose:
  9. - "5000"
  10. container_name: projname.core.inst
  11. environment:
  12. - ASPNETCORE_ENVIRONMENT=Development
  13. volumes:
  14. - ./log:/app/log:rw
  15. deploy:
  16. restart_policy:
  17. condition: always
  18. orgname.projname.webapi.pub:
  19. image: orgname/projname.core.pub:${TAG}
  20. build:
  21. context: .
  22. dockerfile: Dockerfile-Nginx
  23. ports:
  24. - "8081:8081"
  25. links:
  26. - orgname.projname.webapi:core-app
  27. container_name: projname.core.pub.inst
  28. volumes:
  29. orgname.projname.webapi:

注意,服务orgname.projname.webapi中,使用expose来暴露端口,因为我们不需要将端口暴露给docker外部。另外我们也将日志输出到挂在到Docker的主机目录,这样方便查看日志。

提示 强烈推荐使用version3版本的compose文件。version3中新增deploy选项,可以实现docker run --restart选项的作用控制容器在失败等情况下自动重启,从而保证服务的无人值守运行。compose选项详见此文档

构建Image

项目发布完成后,进入发布文件夹publish,执行下面的命令生成相关镜像

  1. docker-compose build

提示,可以在使用docker compose生成之前,分别使用docker build单独生成dotnet core和nginx的镜像进行测试,就像介绍Dockerfile那部分所述。

启动docker compose

确定compose生成好image后,就可以启动服务(容器)了:

  1. docker-compose start

可以使用下面的命令将Build、Start一起完成。

  1. docker-compose up

服务启动后,可以通过Nginx服务访问.NET Core App。

上面的命令会在前台运行并打印日志到控制台。

如果需要在后台运行“服务”,使用-d参数:

  1. docker-compose up -d

docker compose启动的也是普通的容器,通过docker ps也可以看到compose启动的容器。

如果需要停止docker compose启动的服务,使用:

  1. docker-compose down

注意:服务的容器将被删除,所有容器中的数据(非主机挂载到容器目录下)将丢失。

这一小节介绍的方式是在Docker for Windows中使用docker compose运行服务,而实际情况下我们需要在服务器去运行docker compose,具体方式后文有介绍。

其它相关命令:

查看compose相关服务运行状态:docker-compose ps

重启compose中的服务:docker-compose restart

环境

在程序开发中,在不同环境下使用不同的配置是很常见的情况。

如.NET Core就定义了三种默认的环境 - Development、Staging和Production。

体现在配置文件上,有appsettings.jsonappsettings.Staging.jsonappsettings.Production.json等文件

楼主一般将其分别用作开发、测试和生产环境的配置,相信大部分人也都是这么干的。

.NET Core Web应用会根据一个名为ASPNETCORE_ENVIRONMENT的环境变量来判断应用所处的环境。所以我们需要做的就是在生成镜像时将这个变量传入

docker compose的environment就是做这个用的,比如我们将docker-compose.yml文件中orgname.projname.webapi这个服务的定义改为:

  1. environment:
  2. - ASPNETCORE_ENVIRONMENT=Staging

则我们的.NETCore应用将以Staging环境运行,并使用appsettings.Staging.json这个配置文件。

然后我们利用VS Tool for Docker创建的其它两个文件(docker-compose.dev.debug.ymldocker-compose.dev.release.yml)来实现不同环境的配置分离(VS2017中这两个文件中的dev改为vs)。

其实那两个文件是用于VS集成的Docker调试和发布用的,不过我这里不打算依赖工具,而是通过命令行的形式完成工作。所以删除两个文件中原有的内容,并改为我们自己所需。

要使两个配置文件共同工作,最主要的还是靠docker compose对多配置文件的支持。其-f选项可以设置多次,docker compose会把其中的选项叠加。

如:

  1. docker-compose.exe -f docker-compose.yml -f docker-compose.dev.debug.yml build

下面来分别看下用于不同环境的配置文件

首先是docker-compose.dev.debug.yml

  1. version: '3'
  2. services:
  3. orgname.projname.webapi:
  4. environment:
  5. - ASPNETCORE_ENVIRONMENT=Staging
  6. env_file:
  7. - staging.env

其中的env_file指定的staging.env用于演示,由于我们的例子需要配置的环境变量很少,所以无需使用这个文件。文件的格式很简单,就是键值对的格式:

ENV=VAL

注意,这个文件要使用ANSI编码,不然会因为编码问题导致实际定义的变量和期望定义的变量不一致。

提示:可以使用下面的命令,确认compose执行时的配置

  1. docker-compose.exe -f docker-compose.yml -f docker-compose.dev.debug.yml config

这对于检查环境变量等设置是否正确很有帮助。在确认无误后再进行buildup操作。上面说得env文件的编码问题,就是通过config命令查出来的。(下文的composebuild.bat集成了这个检查的功能)

然后是docker-compose.dev.release.yml,内容也差不多:

  1. version: '3'
  2. services:
  3. orgname.projname.webapi:
  4. environment:
  5. - ASPNETCORE_ENVIRONMENT=Production

另外我们还要给测试和生产环境的image打上不同的tag。这个需要修改一下之前编辑的docker-compose.yml中服务定义中image那个配置:

  1. image: orgname/projname.core:${TAG}
  2. image: orgname/projname.core.pub:${TAG}

将它们的版本号都改为插值计算的方式。

docker compose可以由当前执行的环境中获取这些值的定义。比如shell中EXPORT的变量,或者cmd中SET的变量。

在Windows下,我们借助如下的批处理(composebuild.bat)来帮助定义这个变量,并执行docker compose命令:

  1. @echo off
  2. SET /p mode=测试(t)发布(p)
  3. SET /p job=检查(c)生成(b)运行(u)清理(r)
  4. if "%job%"=="c" (
  5. SET operate=config
  6. )
  7. if "%job%"=="b" (
  8. SET operate=build
  9. )
  10. if "%job%"=="u" (
  11. SET operate=up
  12. )
  13. if "%mode%"=="t" (
  14. SET TAG=test
  15. )
  16. if "%mode%"=="p" (
  17. SET TAG=1.0.0
  18. )
  19. if "%job%"=="r" (
  20. docker rmi orgname/projname.core.pub:%TAG%
  21. docker rmi orgname/projname.core:%TAG%
  22. GOTO End
  23. )
  24. if "%mode%"=="t" (
  25. SET fileyml=docker-compose.dev.debug.yml
  26. GOTO Build
  27. )
  28. if "%mode%"=="p" (
  29. SET fileyml=docker-compose.dev.release.yml
  30. GOTO Build
  31. )
  32. :Build
  33. docker-compose -f docker-compose.yml -f %fileyml% %operate%
  34. :End

这个脚本有一个小问题,在后续章节,会介绍将Image推送到注册中心,而推送到注册中心需要一个tag操作。而这个脚本删除这些被tag的Image,只会解除tag,而不删除Image,最终导致本地残留很多无tag的Image。可以全部工作结束后使用下面的PowerShell命令,统一删除:

  1. Get-ContainerImage | ? {$_.RepoTags -eq $null} | foreach { Remove-ContainerImage $_.ID }

运行这个命令需要安装Docker-PowerShell,可参见此文

运行这个批处理,选一下需要运行的选项便可以通过docker compose在不同的环境下生成镜像或启动服务。

注意:所有这些文件都记得加入project.json中(VS2015),包含到项目并复制到输出目录(VS2017)

添加到镜像仓库

这是可选步骤,也可以在把Dockerfile和发布文件上传到服务器并在服务器上生成镜像。见总结。

可以使用Harbor构建一个私有Docker仓库。Harbor相对于Docker官方库就像GitLab相对于GitHub。Harbor的安装和基本使用参见此文

Docker的Image进行分层存储,所以第一次push到私有仓库的上传量比较大,之后将只是推送改变的层。数据传输量比较小。

push操作的操作的基本部分在那篇介绍Docker的文章中有介绍。这里我们只是给出脚本,可以按照提示执行即可,嗯,这是一个PowerShell脚本(ImagesPush.ps1),不再是批处理了。

  1. $reghost="register-host"
  2. $regport="register-port"
  3. $dockerregister="$($reghost):$($regport)"
  4. echo "测试(t)发布(p)"
  5. $operation=Read-Host
  6. Switch($operation)
  7. {
  8. "t" {$tag="test"}
  9. "p" {$tag="1.0.0"}
  10. }
  11. #docker login $dockerregister
  12. docker tag orgname/projname.core:$tag $dockerregister/orgnameprojname/projname.core:$tag
  13. docker tag orgname/projname.core.pub:$tag $dockerregister/orgnameprojname/projname.core.pub:$tag
  14. docker push $dockerregister/orgnameprojname/projname.core:$tag
  15. docker push $dockerregister/orgnameprojname/projname.core.pub:$tag

从镜像仓库获取并启动服务

通过Docker启动服务,docker-compose.yml是必备的。(我们执行docker-compose命令的目录下必须有这个文件,不然分分钟报错。)

我们之前那个docker-compose.yml文件所创建容器的镜像是通过Build Dockerfile来得到的,这里我们要新建这样的一个docker-compose.yml,其使用一个现成的Image来启动容器。

我们新建一个名为docker-compose.server.yml的文件(不要怀疑名字错了)。

  1. version: '3'
  2. services:
  3. orgname.projname.webapi:
  4. image: {REG}/orgnameprojname/projname.core:{TAG}
  5. expose:
  6. - "5000"
  7. container_name: projname.core.inst
  8. environment:
  9. - ASPNETCORE_ENVIRONMENT={ENV}
  10. volumes:
  11. - ./log:/app/log:rw
  12. deploy:
  13. restart_policy:
  14. condition: always
  15. orgname.projname.webapi.pub:
  16. image: {REG}/orgnameprojname/projname.core.pub:{TAG}
  17. ports:
  18. - "8081:8081"
  19. links:
  20. - orgname.projname.webapi:core-app
  21. container_name: projname.core.pub.inst
  22. volumes:
  23. orgname.projname.webapi:

与之前文件的最大不同,这个配置没有了build这个小节。

而镜像就需要从注册中心拉取,直接上脚本(ImagesPull.ps1),然后稍作解释:

  1. $reghost="register-host"
  2. $regport="register-port"
  3. $dockerregister="$($reghost):$($regport)"
  4. echo "Test(t) Publish(p)"
  5. $operation=Read-Host
  6. Switch($operation)
  7. {
  8. "t" {$tag="test";$envstr="Staging"}
  9. "p" {$tag="1.0.0";$envstr="Production"}
  10. }
  11. docker login $dockerregister
  12. docker pull $dockerregister/orgnameprojname/projname.core:$tag
  13. docker pull $dockerregister/orgnameprojname/projname.core.pub:$tag
  14. ni docker-compose.yml -ItemType File -Force
  15. (get-content docker-compose.server.yml) -replace "{TAG}","$($tag)" -replace "{REG}","$($dockerregister)" -replace "{ENV}","$($envstr)" | set-content docker-compose.yml
  16. # remove old container
  17. docker-compose down
  18. docker-compose up

是的,这是一个PowerShell脚本,PowerShell现在也可以用Linux,虽然还处在测试状态。在CentOS7.3中有一堆显示方面的bug,中文支持也没有(所以上面的脚本没有中文),主要功能方面还是很正常的。

Linux上安装PowerShell可见此文档

脚本中,首先登录镜像仓库并下载镜像,然后按照用户输入将docker-compose.server.yml进行插值得到需要的docker-compose.yml文件,最后启动docker compose。

网络

网络方面,Docker-Conpose为应用创建一个子网络,Docker-Compose将每个Service作为一个容器实例,并加入到这个网络中,网络中的容器可以彼此访问。

容器间以容器名称作为主机名来互相访问。

Docker网络这块水很深,楼主对这个了解几乎没有。

总结

借用此部分墙裂推荐Cmder这个神奇,虽然时不时的会有光标错位,中文重叠等问题,但绝对是取代自带控制台的必备工具。

最后总结一下,在上面的所有配置文件准备妥当后,每次修改得到新版本后只需要执行下列步骤:

方式1:

  1. 执行publish.linux.bat生成项目发布文件
  2. 运行buildtest.bat验证Dockerfile正常工作
  3. 运行composebuild.bat根据提示选择在测试环境还是发布环境下验证配置、生成镜像
  4. 使用ImagesPush.ps1将生成的镜像发布到Harbor
  5. 在服务器上使用ImagesPull.ps1拉取镜像并使用compose启动服务。(先要把docker-compose.server.yml放到与ImagesPull.ps1服务器端相同目录下)

方式2:

  1. 执行publish.linux.bat生成项目发布文件,将所有文件上传到服务器
  2. 在服务器端使用composebuild.bat来运行服务。(目前楼主没有使用这种方法,所以没有将这个脚本用shell或者powershell重写)

如果您有更好的实现方法,欢迎评论区指点一二。

.NET遇上Docker - 使用Docker Compose组织Ngnix和.NETCore运行的更多相关文章

  1. 当DOCKER遇上ESXI

    特别是你要为DOCKER窗口设置静态IP,且和公司局域网打成一片的时候, 苦逼的测试就会开始,我差不多前前后后测试了四五天,一百多个容器报废. NETNS,NSENTER,PIPWORK,各种镜像合下 ...

  2. .NET遇上Docker - Harbor的安装与基本使用

    Harbor是一个开源企业级Docker注册中心,可以用于搭建私有的Docker Image仓库.可以实现权限控制等. 安装Harbor 首先,需要安装Docker和Docker Compose,参考 ...

  3. .NET遇上Docker - Docker集成Cron定时运行.NETCore(ConsoleApp)程序.md

    配置项目的Docker支持 对于VS中Docker的配置,依旧重复一些废话. 给项目添加Docker支持,VS2015可以直接使用Docker for VS插件,VS2017在安装时选择容器支持.VS ...

  4. Docker,Docker Compose,Docker Swarm,Kubernetes之间的区别

    Dcoker Docker 这个东西所扮演的角色,容易理解,它是一个容器引擎,也就是说实际上我们的容器最终是由Docker创建,运行在Docker中,其他相关的容器技术都是以Docker为基础,它是我 ...

  5. 物联网架构成长之路(24)-Docker练习之Compose容器编排

    0.前言 一开始学的之后,是想一步到位直接上Kubernetes(K8s)的,后面没想到,好像有点复杂,有些概念不是很懂.因此学习东西还是要循序渐进,慢慢来.先了解单机编排技术Docker Compo ...

  6. Docker三剑客之 Compose

    简介 Docker-Compose 是 Docker 的一种编排服务,是一个用于在 Docker 上定义并运行复杂应用的工具,可以让用户在集群中部署分布式应用. 通过 Docker-Compose 用 ...

  7. 在 Ubuntu 16.04 LTS 上 离线安装 Docker / Docker-compose

    前情提要 今天上班后,突然接到现场的工程师的电话: XXX的现场环境组的的局域网,上不了互联网.bla bla bla..... 如果需要安装其他软件的话,只能是自己带过去安装... 听完现场工程师的 ...

  8. Docker入门-docker compose的使用

    Compose简介 Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排.其代码目前在https://github.com/docker/compose 上开源. ...

  9. Docker 0x13: Docker 构建集群/服务/Compose/分布式服务栈

    目录 Docker 构建集群/服务/Compose/分布式服务栈 集群 初始化集群服务 安装docker-machine 管理节点和工作节点 docker集群构建完成 集群中部署应用 集群服务访问特性 ...

随机推荐

  1. C#计算表达式(仿计算器功能)

    一.用MSScriptControl在C#中执行JavaScript代码javascript中有个eval方法用过的人都知道他的方便和强大之处.在C#中,我们也可以通过Com组件来执行一段javasc ...

  2. 小白能学好UI设计吗

    许多童鞋在接触UI培训前会有很多疑问,我是干快递的,我能学好UI设计吗,UI培训要学些什么,电脑操作我好像什么都不会,除了打游戏,我适合学UI设计吗--有这些想法呢是人之常情,但是我们反过来想一想,有 ...

  3. 最近新版本的pangolin出现了点问题,我把可用的旧版本上传到了github

    经测试该版本编译没有问题. 下载地址:https://github.com/zzx2GH/Pangolin.git

  4. 使用java.util.Properties类读写配置文件

    J2SE 1.5 以前的版本要求直接使用 XML 解析器来装载配置文件并存储设置,虽说也并非难事,相比 java.util.Properties却要做额外的解析工作.而java.util.Proper ...

  5. 重回博客 谈一谈Node中的异步和单线程

    重回博客,这个帐号之前注册后就只发了一篇博客.听朋友建议,决定一周两次更新. 第一篇谈论一下最近想的比较多的异步的问题. 传统多线程异步 传统的异步是多线程的,当要同时做两件事的时候,他们是执行在不同 ...

  6. IIS HTTP 错误 500.19 - Internal Server Error HTTP 错误 401.3 - Unauthorized 解决办法

    前言:IIS是一个强大的服务器管理器,当遇到 IIS HTTP 错误 500.19 - Internal Server Error  HTTP 错误 401.3 - Unauthorized 的解决办 ...

  7. 【Unity编程】四元数(Quaternion)与欧拉角

    版权声明:本文为博主原创文章,欢迎转载.请保留博主链接:http://blog.csdn.net/andrewfan 欧拉旋转.四元数.矩阵旋转之间的差异 除了欧拉旋转以外,还有两种表示旋转的方式:矩 ...

  8. 关于Trie KMP AC自动机

    个人认为trie,KMP,AC自动机是思想非常明确的,AC自动机的性质是与KMP算法的思想类似的(失配后跳转) 而KMP是线性的,AC自动机是在tire树上跑KMP,为方便那些不会用指针的小朋友(我也 ...

  9. Yahoo前端优化十四条军规

    相信互联网已经越来越成为人们生活中不可或缺的一部分.Ajax,flex等等富客户端的应用使得人们越加“幸福”地体验着许多原先只能在C/S实 现的功能. 比如Google机会已经把最基本的office应 ...

  10. 常见排序算法-Python实现

    常见排序算法-Python实现 python 排序 算法 1.二分法     python    32行 right = length-  :  ]   ):  test_list = [,,,,,, ...