python完整网站开发项目视频教程,图片wordpress主题,新网站的建设工作,网站开发php学校Docker通过一种打包和分发的软件#xff0c;完成传统容器的封装。这个用来充当容器分发角色的组件被称为镜像。Docker镜像是一个容器中运行程序的所有文件的捆绑快照。当使用Docker分发软件#xff0c;其实就是分发这些镜像#xff0c;并在接收的机器上创建容器。镜像在Dock…Docker通过一种打包和分发的软件完成传统容器的封装。这个用来充当容器分发角色的组件被称为镜像。Docker镜像是一个容器中运行程序的所有文件的捆绑快照。当使用Docker分发软件其实就是分发这些镜像并在接收的机器上创建容器。镜像在Docker生态系统中是可交付的基本单位。 镜像的创建方式有很多种如使用docker commit命令根据当前容器的更改创建一个新的镜像也可以使用docker save保存镜像或使用docker export导出镜像。但是最常用、最推荐的方式还是使用Dockerfile定义镜像然后使用docker build命令创建镜像。 Dockerfile使用基本的基于DSL语法的指令来定义一个Docker镜像之后就可以使用docker build命令基于该Dockerfile中的指令构建一个新的镜像。Dockerfile具有信息表达性且易于理解这些要归功于Dockerfile支持注释的简洁语法。Dockerfile构建程序自身使用缓存技术来解决快速开发和迭代带来的问题。这个构建过程可追踪且可重用。它们能够很简单地和现有的构建系统、持续构建和集成工具一起工作。
Dockerfile编写及使用
Dockerfile是一个文件它由构建镜像的指令组成用户可以使用Dockerfile来快速创建自定义的镜像。指令由Docker镜像构建者自上而下排列能够被用来修改镜像的任何信息。 Dockerfile具有信息表达性且易于理解这些都要归功于Dockerfile支持注释的简洁语法。开发者可以使用任何版本控制工具来跟踪Dockerfile文件的变动。维护多个版本的镜像就和管理多个Dockerfile一样简单。
基本结构
Dockerfile由一系列指令和其参数组成并且支持以#开头的注释行。每条指令都建议使用大写字母且后面跟随一个参数。Dockerfile中指令的基本使用可以参考笔者Dockerfile指令大全一文更详细的指令使用说明建议参考官网Dockerfile reference一文。 Dockerfile中的指令会按顺序从上到下执行所以应根据需要合理安排指令的顺序。Docker大体上按照如下流程执行Dockerfile中的指令 (1) Docker从基础镜像运行一个容器。 (2) 执行一条指令对容器做出修改。 (3) 执行类似docker commit的操作指令提交一个新的镜像层。 (4) Docker再基于刚提交的镜像运行一个新容器。 (5) 执行Dockerfile中的下一条指令直到所有指令都执行完毕。 如果Dockerfile由于某些原因(如指令执行失败)没有正常结束那么仍将得到一个可用的镜像只是最后一条指令执行失败这对日常的开发和调试是有帮助的。 一般而言 Dockerfile 主体内容分为四部分基础镜像信息、制作者信息、镜像操作指令和容器启动时执行指令。但是考虑到容器安全还有必要对其进行安全加固如配置用户或用户组等。此外构建基础镜像时有时还需要考虑继承的镜像需要执行的一些默认操作如创建一组默认的用户和用户组供子镜像使用。
基础镜像信息
在编写Dockerfile文件时第一个要考虑的事情就是创建一个基础镜像供他人使用或是基于基础镜像去构建一个新的镜像。这些诉求都可以通过FROM指令实现。一般情况下FROM指令是一个Dockerfile的第一条指令。 FROM指令用来指定一个父镜像以开始新的构建阶段。Dockerfile支持在一个文件中使用多个FROM指令以创建多个镜像。FROM的指令格式如下
FROM [–platform] [:||-] [AS ]
其中–platform参数用来指定镜像应用的平台主要应用于多平台场景如linux/amd64或linux/arm64等tag和digest用来指定需要引用的镜像的tag如果不指定则使用latest。如果一个Dockerfile中需要创建多个镜像会使用到多个FROM。如果下一个FROM指令中需要使用上一个FROM指令构建的镜像可以现在上一个FROM指令中定义别名也即使用AS 。 某些场景下不需要父镜像如构建一个操作系统镜像这时可以使用FROM scratch这个指令来表示不需要父镜像。
制作者信息
对于一个镜像无论是镜像开发者还是镜像的继承者有时需要直到这个镜像的作者相关的信息。对于这个需求可以通过MAINTAINER指令或LABEL指令来指定镜像作者信息。这里不推荐使用MAINTAINER指令更推荐LABEL指令。相比MAINTAINER指令LABEL指令会将这部分信息保存到元数据这个就可以通过docker image inspect命令方便的查询该部分信息。示例如下
$ docker image inspect --format{{json .Config.Labels}} target-image-name-or-id使用LABEL记录镜像制作者信息的示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# Maintainer: docker user docker_useremail.com
LABEL maintainer docker_userdocker_useremail.com...上述示例中首先使用FROM指令指明所基础镜像的名称接下来就是使用LABEL指令说明制作者信息。这里制作者信息并不是一个必须的信息但建议都添加上。注意这个Dockerfile只是编写了一部分还不算一个完整的Dockerfile。
镜像操作指令
Dockerfile文件的主体部分就是基于基础镜像的进一步操作如使用RUN指令执行特定的命令使用ADD/COPY指令将特定的产物复制到容器文件系统等等。如这里使用RUN指令下载软件包然后将构建上下文中的基于Java源码生成的JAR包复制到容器文件系统的示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# Maintainer: docker user docker_useremail.com
LABEL maintainer docker_userdocker_useremail.comRUN apt-get update \apt-get install -y libsnappy-dev \ rm -rf /var/cache/apt...上述示例中使用RUN指令下载特定的软件包并在下载完毕后删除了遗留的缓存。每运行一条RUN指令镜像添加新的一层所以这里是将在多个RUN指令执行的命令合并成了一行。同样的到这个阶段Dockerfile也只是编写了一部分还不算一个完整的Dockerfile。
容器启动时执行指令
容器启动时可以指定默认执行的命令或指定默认的可执行文件。这对于提供后端服务的应用来说很有必要。如需要在容器中运行一个Java Web应用可以在容器启动时指定可执行的shell脚本以运行一个Java应用。对于这个需求可以通过CMD指令或ENTRYPOINT指令来实现。 CMD指令和ENTRYPOINT指令均用来定义启动容器时需要执行的命令推荐优先使用ENTRYPOINT指令。对于同时出现CMD指令和ENTRYPOINT指令的场景遵循如何规则
No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entryCMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmdCMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
上表中对同时存在CMD指令和ENTRYPOINT指令的场景要根据指令使用的exec模式或shell模式进行如下划分如果ENTRYPOINT指令是shell模式则会忽略CMD指令如果ENTRYPOINT指令是exec模式CMD指令是exec模式则CMD指令的命令失效参数会追加到ENTRYPOINT指令上如果ENTRYPOINT指令是exec模式CMD指令是shell模式则先执行ENTRYPOINT指令再执行CMD指令。 使用示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# Maintainer: docker user docker_useremail.com
LABEL maintainer docker_userdocker_useremail.com# COPY and rename application jar file to the containers filesystem
COPY app-*.jar /app.jar# EXECUTE jar file
ENTRYPOINT [java, -jar, /app.jar]上述示例中使用COPY指令将构建上下文中的软件包复制到容器的文件系统。然后使用ENTRYPOINT声明容器启动时需要执行的命令。这样当容器启动时就可以运行JAR包从而启动这个应用。到这个阶段一个基本的Dockerfile文件就编写完了。
用户权限加固
默认情况下容器以root用户运行root用户权限太高对于业务应用来说存在安全风险如常见的容器逃离手段都是依赖于获得容器的root权限。对于用户权限分配来说最佳实践就是尽可能地消减用户的特权也即遵循最小权限原则。当一个Docker用户创建容器时是能够覆盖镜像的默认配置的。因此并不存在某个方法来完全防止容器以root用户运行。但是镜像的制作者可以创建非root用户并以非root用户来执行应用。 Dockerfile通过提供USER指令、docker run指令或docker create指令来设置用户和用户组从而限制用户的访问。推荐使用USER指令设置用户和用户组使用docker run命令后docker create指令来更改设置用户和用户组。这里重点介绍下使用USER指令设置用户和用户组。示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# Maintainer: docker user docker_useremail.com
LABEL maintainer docker_userdocker_useremail.com# Creat application directory
RUN mkdir -p /opt/app# COPY and rename application jar file and set new owner and mode to the containers filesystem
COPY --chown1000:1000 --chmod644 app-*.jar /opt/app/app.jar# SET new user id and group id
USER 1000:1000# EXECUTE jar file
ENTRYPOINT [java, -jar, /opt/app/app.jar]这里要注意把握设置用户UID和GID的时机。如果过早地设置可能导致当前用户没有权限完成Dockerfile中的其他指令。如需要执行一个root目录下的文件但是先使用USER指令设置了用户UID和GID则会导致当前用户权限过低导致root目录下的文件执行失败。示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# SET new user id and group id
USER 1000:1000# Creat application directory
RUN mkdir -p /opt/app因为/opt目录属于root用户所以不能在UID是1000的用户中在/opt目录创建新目录。 注意如果是编写一个基础镜像的Dockerfile文件则不建议遵循最小权限原则而是尽量提供root权限让业务镜像去考虑最小权限的问题。
注入下游镜像在构建时发生的操作
在构建基础镜像时有时需要考虑继承的镜像需要执行的一些默认操作如创建一组默认的用户和用户组供子镜像使用。对于这个需求可以通过ONBUILD指令实现。ONBUILD指令不会在包含它们的Dockerfile被构建时执行。这些指令会被记录在生成镜像的元数据ContainerConfig.OnBuild下。这个元数据会一直被保留直到生成的镜像被另外的Dockerfile作为基础镜像。这样当子镜像构建时ONBUILD后跟随的指令将会在FROM指令后下一条指令前被执行。示例如下
# Base image to use, this must be set as the first line
FROM ubuntu:18.04# Maintainer: docker user docker_useremail.com
LABEL maintainer docker_userdocker_useremail.com# ONBUILD command
ONBUILD RUN echo This is an ONBUILD trigger. # 其他的设置或命令
...编写Dockerfile文件
介绍完了编写Dockerfile的基本结构接下来就根据真实的业务场景介绍下如何编写特定于业务场景的Dockerfile文件。由于笔者目前主要参与的是Java Web后端应用的开发所以这里重点介绍下一个商用Java Web后端应用的Dockerfile的编写示例其他场景的Dockerfile编写示例还请自行学习。 首先是基础镜像的选择。对于一个业务服务来说为了保证业务服务不依赖内核的操作系统在基础镜像的选择上可以使用一个简化版本的操作系统。这个操作系统是一个精简版本只包含操作系统自带的一些功能。一些软件包的安装如python、jdk等均留给业务镜像去按需补充。接着是JRE的版本选择。注意在Java应用运行时只有JRE即可。目前主流的Java版本还是Java 8和Java 11。不同公司根据业务需要选择合适的JDK版本。对于基于Java的业务服务来说可以使用精简操作系统JRE构成的基础镜像。 Java Web后端应用依赖的基础镜像已经选择完毕接下来就是把Java Web后端应用依赖的工具安装到操作系统。对于不同的Java应用可能会使用到一些实用工具。如对网络服务来说可能使用nmap来进行网络发现。 考虑完Java Web后端应用依赖的工具下面要考虑的就是Java Web后端应用的lib的依赖。使用Maven进行打包时默认情况下不会将依赖包打入jar中。但是可以通过配置Maven插件来将依赖包和项目本身打包到一个jar文件中。这样无论是二方库还是三方库这部分依赖都会作为Java Web后端应用构建产物的一部分。对于基于Spring Boot构建的Java Web后端应用来说其依赖会自动打包到jar文件中无需特殊处理。 对于Java Web后端应用来说容器启动后需要启动一个进程在运行Java Web后端应用。这个应用会一直活跃直到容器意外中止或容器正常终止为止。也即是说容器启动后要立即执行Java Web后端应用。为了聚合启动Java Web后端应用相关的操作使用shell脚本来编写启动相关的命令。这样在容器启动时只需要执行下shell脚本即可。 编写一个Java Web后端应用的主要事项都已考虑完毕接下来简单描述下构建上下文的目录结构
--docker # docker目录存储docker镜像制作相关资源
----package # package目录存储业务应用打包相关资源
------start.sh # start.sh用来启动业务服务
------service.jar # service.jar业务服务代码构建的jar
-- app.dockerfile # app.dockerfile业务服务的Dockerfile描述构建镜像的过程介绍完构建上下文的目录结构接下来说明下app.dockerfile文件中的内容
# 使用centos操作系统 jre(Java 1.8)的基础镜像镜像仓库并不包含该镜像可以基于centos镜像制作一个包含jre的镜像
FROM centos_jre_1.8:centos8_jar8# 记录镜像的制作者方便后期的运维
LABEL maintainer custom_java_webcustom_java_webemail.com# jar包和运行jar包的shell脚本等复制到容器中
## 将构建上下文的package目录下的内容拷贝到/opt/app目录下注意这里并没有预先在容器的文件系统创建/opt/app/目录
COPY package /opt/app/
## 对于可执行文件在使用前赋予可执行权限
RUN chmod 544 /opt/app/start.sh \chmod 544 /opt/app/start.jar# 设置ENTRYPOINT来直接执行脚本
ENTRYPOINT [/opt/app/start.sh]这样一个Java Web应用的Dockerfile文件就编写完毕了。考虑到安全问题还有必要调整下用户使用USER指令改造后的Dockerfile文件如下
# 使用centos操作系统 jre(Java 1.8)的基础镜像镜像仓库并不包含该镜像可以基于centos镜像制作一个包含jre的镜像
FROM centos_jre_1.8:centos8_jar8# 记录镜像的制作者方便后期的运维
LABEL maintainer custom_java_webcustom_java_webemail.com# jar包和运行jar包的shell脚本等复制到容器中
## 将构建上下文的package目录下的内容拷贝到/opt/app目录下注意这里并没有预先在容器的文件系统创建/opt/app/目录
COPY package /opt/app/
## 对于可执行文件在使用前赋予可执行权限
RUN chown -R 1000:1000 /opt/app \ chmod 644 /opt/app \chmod 544 /opt/app/start.sh \chmod 544 /opt/app/start.jar# 设置用户及用户组
USER 1000:1000# 设置ENTRYPOINT来直接执行脚本
ENTRYPOINT [/opt/app/start.sh]在ENTRYPOINT指令中使用exec格式执行可执行文件时不会启动一个shell进程docker会直接运行可执行文件这里是start.sh。需要注意的是这里的start.sh脚本的第一行应该是#!/bin/sh或者其它希望用来执行脚本的解释器路径。start.sh脚本的示例如下
#!/bin/bash# 指定JAR包的路径
JAR_PATH/opt/app/service.jar# 使用nohup在后台启动JAR包并将输出重定向到日志文件
nohup java -jar $JAR_PATH 使用docker build命令生成镜像
编写完Dockerfile文件后接下来就是使用docker build命令构建镜像。docker build命令的基本格式如下
docker image build [OPTIONS] PATH | URL | -该命令将读取指定路径下(包括子目录)的Dockerfile并将该路径下所有数据作为构建上下文(Context)发送给 Docker服务器端。Docker服务端在校验Dockerfile格式通过后逐条执行其中定义的指令如果碰到ADD、COPY和RUN指令则会生成一层新的镜像。最终如果创建镜像成功会返回最终镜像的ID。 在构建过程中会有新层被加入到要产生的镜像中。这不仅意味着开发者能够从任意一步开始创建分支更重要的是构建过程能够缓存每一步的结果当运行完几个指令后如果下一条指令出现问题构建过程能够在问题被修复后从同一步重新启动。如果构建过程需要下载资源或包含某些需要消耗大量时间的任务那么缓存可以起到节省时间的效果。如果需要从零开始构建可以使用–no-cache选项来禁止缓存的使用。
将执行目录切换到上述目录结构的docker目录下上述示例的dockerfile文件就可以使用如下的docker build命令生成镜像
$ docker build -f app.docerfile -t service-image:202403102100 .在docker build命令执行完毕后如果镜像制作者可以看见Successfully built XXX字样则说明镜像构建成功。且会生成一个service-image的镜像镜像的版本是202403102100。可以使用docker images查看该镜像或使用docker start命令启动该镜像。
Dockerfile最佳实践
所谓Dockerfile最佳实践就是从需求出发来定制适合当前业务场景、高效方便的镜像。首先要尽量吃透每个指令的含义和执行效果多编写一些简单的例子进行测试弄清楚了再撰写正式的Dockerfile文件。此外Docker Hub官方仓库中提供了大量的优秀镜像和对应的Dockefile可以通过阅读它们来学习如何撰写高效的Dockerfile。 这里梳理一些实践经验。建议读者在生成镜像过程中尝试从如下角度进行思考完善所生成镜像 (1) 精简镜像用途尽量让每个镜像的用途都比较集中单一避免构造大而复杂、多功能的镜像。 (2) 选用合适的基础镜像容器的核心是应用。选择过大的父镜像(如Ubuntu系统镜像)会造成最终生成应用镜像的膝肿推荐选用瘦身过的应用镜像(如node:slim)或者较为小巧的系统镜像(如alpine、busybox或debian)。 (3) 提供必要的注释和维护者信息: Dockerfile也是一种代码需要考虑方便后续的扩展和他人的使用。 (4) 正确使用版本号使用明确的版本号信息如1.02.0而非依赖于默认的latest。通过版本号可以避免环境不一致导致的问题。 (5) 减少镜像层数如果希望所生成镜像的层数尽量少则要尽量合并RUN、ADD和COPY指令。通常情况下多个RUN指令可以合并为一条RUN指令。 (6) 恰当使用多步骤创建通过多步骤创建可以将编译和运行等过程分开保证最终生成的镜像只包括运行应用所需要的最小化环境。当然用户也可以通过分别构造编译镜像和运行镜像来达到类似的结果但这种方式需要维护多个Dockerfile。 (7) 使用.dockerignore文件使用该文件可以标记在执行docker build时忽略的路径和文件避免发送不必要的数据内容从而加快整个镜像创建过程。 (8) 及时删除临时文件和缓存文件特别是在执行 apt-get 指令后/var/cache/apt下面会缓存了一些安装包。 (9) 提高生成速度如合理使用 cache 减少内容目录下的文件或使用.dockerignore 文件指定等。 (10) 调整合理的指令顺序在开启cache的情况下内容不变的指令尽量放在前面这样可以尽量复用。 (11) 减少外部源的干扰如果确实要从外部引入数据需要指定持久的地址并带版本信息等让他人可以复用而不出错。
参考
《Docker技术入门与实战》 杨保华 戴王剑 曹亚仑 著 《Docker实战》 Jeff Nickoloff 著 胡震杨润青 黄帅 译 https://yiyan.baidu.com/ 文心一言 https://docs.docker.com/reference/dockerfile/ Dockerfile reference http://www.dockerinfo.net/3328.html 7 步精简 Docker 镜像 https://www.runoob.com/docker/docker-install-ubuntu.html Docker 安装 Ubuntu https://blog.csdn.net/u014163312/article/details/127330574 Maven打包所有依赖到一个可执行jar中 文章转载自: http://www.morning.gwqkk.cn.gov.cn.gwqkk.cn http://www.morning.ftcrt.cn.gov.cn.ftcrt.cn http://www.morning.gpxbc.cn.gov.cn.gpxbc.cn http://www.morning.dpqqg.cn.gov.cn.dpqqg.cn http://www.morning.gtdf.cn.gov.cn.gtdf.cn http://www.morning.qxjck.cn.gov.cn.qxjck.cn http://www.morning.bqwrn.cn.gov.cn.bqwrn.cn http://www.morning.bfjtp.cn.gov.cn.bfjtp.cn http://www.morning.xrpwk.cn.gov.cn.xrpwk.cn http://www.morning.cwyrp.cn.gov.cn.cwyrp.cn http://www.morning.dhrbj.cn.gov.cn.dhrbj.cn http://www.morning.jwsrp.cn.gov.cn.jwsrp.cn http://www.morning.hhpkb.cn.gov.cn.hhpkb.cn http://www.morning.bwygy.cn.gov.cn.bwygy.cn http://www.morning.xgcwm.cn.gov.cn.xgcwm.cn http://www.morning.bgdk.cn.gov.cn.bgdk.cn http://www.morning.rhsg.cn.gov.cn.rhsg.cn http://www.morning.psxwc.cn.gov.cn.psxwc.cn http://www.morning.hnmbq.cn.gov.cn.hnmbq.cn http://www.morning.jbpdk.cn.gov.cn.jbpdk.cn http://www.morning.mznqz.cn.gov.cn.mznqz.cn http://www.morning.sdhmn.cn.gov.cn.sdhmn.cn http://www.morning.qbfkz.cn.gov.cn.qbfkz.cn http://www.morning.tcxzn.cn.gov.cn.tcxzn.cn http://www.morning.jsmyw.cn.gov.cn.jsmyw.cn http://www.morning.rkqkb.cn.gov.cn.rkqkb.cn http://www.morning.jqmmf.cn.gov.cn.jqmmf.cn http://www.morning.lrgfd.cn.gov.cn.lrgfd.cn http://www.morning.mwnch.cn.gov.cn.mwnch.cn http://www.morning.hmnhp.cn.gov.cn.hmnhp.cn http://www.morning.attorneysportorange.com.gov.cn.attorneysportorange.com http://www.morning.brlgf.cn.gov.cn.brlgf.cn http://www.morning.xckrj.cn.gov.cn.xckrj.cn http://www.morning.qpzjh.cn.gov.cn.qpzjh.cn http://www.morning.rjxwq.cn.gov.cn.rjxwq.cn http://www.morning.qtsks.cn.gov.cn.qtsks.cn http://www.morning.hxftm.cn.gov.cn.hxftm.cn http://www.morning.wkmpx.cn.gov.cn.wkmpx.cn http://www.morning.mzcrs.cn.gov.cn.mzcrs.cn http://www.morning.whpsl.cn.gov.cn.whpsl.cn http://www.morning.mhxlb.cn.gov.cn.mhxlb.cn http://www.morning.hmdyl.cn.gov.cn.hmdyl.cn http://www.morning.mhnd.cn.gov.cn.mhnd.cn http://www.morning.qkgwx.cn.gov.cn.qkgwx.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.sgfgz.cn.gov.cn.sgfgz.cn http://www.morning.mfct.cn.gov.cn.mfct.cn http://www.morning.lrflh.cn.gov.cn.lrflh.cn http://www.morning.qpsdq.cn.gov.cn.qpsdq.cn http://www.morning.kjgrg.cn.gov.cn.kjgrg.cn http://www.morning.kxscs.cn.gov.cn.kxscs.cn http://www.morning.gzgwn.cn.gov.cn.gzgwn.cn http://www.morning.xpzgg.cn.gov.cn.xpzgg.cn http://www.morning.zwyuan.com.gov.cn.zwyuan.com http://www.morning.wgtnz.cn.gov.cn.wgtnz.cn http://www.morning.rytps.cn.gov.cn.rytps.cn http://www.morning.lmxzw.cn.gov.cn.lmxzw.cn http://www.morning.dbddm.cn.gov.cn.dbddm.cn http://www.morning.lflnb.cn.gov.cn.lflnb.cn http://www.morning.brlgf.cn.gov.cn.brlgf.cn http://www.morning.qbfwb.cn.gov.cn.qbfwb.cn http://www.morning.jtszm.cn.gov.cn.jtszm.cn http://www.morning.cjsrg.cn.gov.cn.cjsrg.cn http://www.morning.gfpyy.cn.gov.cn.gfpyy.cn http://www.morning.jrhcp.cn.gov.cn.jrhcp.cn http://www.morning.kzrg.cn.gov.cn.kzrg.cn http://www.morning.qxlgt.cn.gov.cn.qxlgt.cn http://www.morning.znmwb.cn.gov.cn.znmwb.cn http://www.morning.mtsgx.cn.gov.cn.mtsgx.cn http://www.morning.hbnwr.cn.gov.cn.hbnwr.cn http://www.morning.nbnpb.cn.gov.cn.nbnpb.cn http://www.morning.nlkjq.cn.gov.cn.nlkjq.cn http://www.morning.wcft.cn.gov.cn.wcft.cn http://www.morning.bqqzg.cn.gov.cn.bqqzg.cn http://www.morning.prddj.cn.gov.cn.prddj.cn http://www.morning.yqkxr.cn.gov.cn.yqkxr.cn http://www.morning.redhoma.com.gov.cn.redhoma.com http://www.morning.vattx.cn.gov.cn.vattx.cn http://www.morning.ymfzd.cn.gov.cn.ymfzd.cn http://www.morning.tsxg.cn.gov.cn.tsxg.cn