docker

[toc]

一、什么是容器?

容器就是在隔离的环境运行的一个进程,如果进程停止,容器就会销毁

隔离的环境拥有自己的系统文件,ip地址,主机名等,linux,系统文件

程序:代码,命令
进程:正在运行的程序

二、容器和虚拟化的区别

kvm虚拟化:

需要硬件的支持,需要模拟硬件,可以运行不同的操作系统,启动时间分钟级(开机启动流程)

容器:

共用宿主机内核,容器的第一个进程直接运行服务,轻量级,损耗少,启动快,性能高

  • linux开机启动流程
bios开机硬件自检
根据bios设置的优先启动项boot  网卡 硬盘 u盘 光驱
读取mbr引导 2T  UEFI(gpt分区)    mbr硬盘分区信息,内核加载路径
加载内核
启动第一个进程/sbin/init  systemd
系统初始化完成
运行服务
  • 容器启动流程
共用宿主机内核:
第一个进程,服务nginx,httpd,mysql
  • 虚拟化
需要硬件的支持,需要模拟硬件,需要走开机流程,可以运行不同的操作系统
  • 总结
(1)与宿主机使用同一个内核,性能损耗小;
(2)不需要指令级模拟;
(3)容器可以在CPU核心的本地运行指令,不需要任何专门的解释机制;
(4)避免了准虚拟化和系统调用替换中的复杂性;
(5)轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享。

三、容器技术的发展过程

1):chroot技术,新建一个子系统(拥有自己完整的系统文件)
参考资料:https://www.ibm.com/developerworks/cn/linux/l-cn-chroot/
chang root

作业1:使用chroot监狱限制SSH用户访问指定目录和使用指定命令
https://linux.cn/article-8313-1.html
ls

2):linux容器(lxc)  linux container(namespaces 命名空间 隔离环境 及cgroups 资源限制)
cgroups  限制一个进程能够使用的资源。cpu,内存,硬盘io
kvm虚拟机:资源限制(1c 1G 20G)
  • lxc容器部署(需要使用epel源,过时技术)
#安装epel源
yum install epel-release -y

#编译epel源配置文件
vi  /etc/yum.repos.d/epel.repo
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/$basearch
#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7

[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/$basearch/debug
#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1

[epel-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/epel/7/SRPMS
#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1

##安装lxc
yum install lxc-* -y
yum install libcgroup* -y
yum install bridge-utils.x86_64 -y


##桥接网卡
[root@controller ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 
echo 'TYPE=Ethernet
BOOTPROTO=none
NAME=eth0
DEVICE=eth0
ONBOOT=yes
BRIDGE=virbr0' >/etc/sysconfig/network-scripts/ifcfg-eth0


[root@controller ~]# cat /etc/sysconfig/network-scripts/ifcfg-virbr0 
echo 'TYPE=Bridge
BOOTPROTO=static
NAME=virbr0
DEVICE=virbr0
ONBOOT=yes
IPADDR=10.0.0.11
NETMASK=255.255.255.0
GATEWAY=10.0.0.254
DNS1=180.76.76.76' >/etc/sysconfig/network-scripts/ifcfg-virbr0

##启动cgroup
systemctl start cgconfig.service

##启动lxc
systemctl start lxc.service

##创建lxc容器
方法1:
lxc-create -t download -n centos6 -- --server mirrors.tuna.tsinghua.edu.cn/lxc-images -d centos -r 6 -a amd64
方法2:
lxc-create -t centos -n test

##为lxc容器设置root密码:
[root@controller ~]# chroot /var/lib/lxc/test/rootfs passwd
Changing password for user root.
New password: 
BAD PASSWORD: it is too simplistic/systematic
BAD PASSWORD: is too simple
Retype new password: 
passwd: all authentication tokens updated successfully.

##为容器指定ip和网关
vi /var/lib/lxc/centos7/config
lxc.network.name = eth0
lxc.network.ipv4 = 10.0.0.111/24
lxc.network.ipv4.gateway = 10.0.0.254

##启动容器
lxc-start -n centos7

四、docker介绍

Docker是通过进程虚拟化技术(namespaces及cgroups、cpu、内存、磁盘io等)来提供容器的资源隔离与安全保障等。
由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机(VM)额外的操作系统开销,提高资源利用率。
namespace  资源隔离
cgroups    进程的资源限制
kvm        虚拟磁盘文件,资源隔离
kvm        资源限制,--cpus --memory


docker 初期把lxc二次开发,libcontainer、top、htop

docker的主要目标是"Build,Ship and Run any App,Angwhere",构建,运输,处处运行
部署服务,环境问题
一次构建,处处运行
docker是一种软件的打包技术


构建:做一个docker镜像
运输:docker pull
运行:启动一个容器
每一个容器,他都有自己的系统文件rootfs.

kvm解决了硬件和操作系统之间的依赖
kvm独立的虚拟磁盘,xml配置文件

docker解决了软件和操作系统环境之间的依赖,能够让独立服务或应用程序在不同的环境中,得到相同的运行结果。
docker镜像有自己的文件系统。

docker容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。开发人员在自己笔记本上创建并测试好的容器,无需任何修改就能够在生产系统的虚拟机、物理服务器或公有云主机上运行。


docker容器环境
centos7.4   2G   10.0.0.11  docker01    host解析
centos7.4   2G   10.0.0.12  docker02    host解析

五、docker的安装

10.0.0.11:修改主机名和host解析
rm -fr /etc/yum.repos.d/local.repo
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo
yum install docker-ce -y
systemctl start  docker.service 
systemctl enable docker.service 

六、docker的主要组成部分

docker是传统的CS架构分为docker client和docker server,向mysql一样

命令:docker version
[root@docker ~]# docker version 
Client:
 Version:           18.09.8
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        0dd43dd87f
 Built:             Wed Jul 17 17:40:31 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.8
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       0dd43dd
  Built:            Wed Jul 17 17:10:42 2019
  OS/Arch:          linux/amd64
  Experimental:     false


docker系统命令:
docker system info(做监控用)
dockeer info      (简写)     

- docker主要组件有:镜像、容器、仓库, 网络,存储

启动容器必须需要一个镜像,仓库中只存储镜像
容器---镜像---仓库


docker初次体验:
安装Nginx步骤:
官网下载Nginx源码包wget  
tar 
创建Nginx用户 

编译安装
./config....
修改配置文件,
启动

七、启动第一个容器

##配置docker镜像加速
vi /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}   

docker run -d -p 80:80 nginx
run(创建并运行一个容器)
-d 放在后台
-p 端口映射
nginx docker镜像的名字


本地安装(做实验用)
wget http://192.168.12.201/docker_nginx1.15.tar.gz
docker image load -i docker_nginx1.15.tar.gz
docker run -d -p 80:80 nginx

八、docker的镜像管理

  • 镜像相关
查看所有的命令
[root@docker ~]# docker image 
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
  prune       Remove unused images
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rm          Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  • 搜索镜像
docker search [服务名称] 

例子:
[root@docker ~]# docker search centos

选镜像的建议:
1,优先考虑官方
2,stars数量多
  • 官方镜像创库地址

https://hub.docker.com/

  • 下载镜像
docker pull(push)
镜像加速器:阿里云加速器,daocloud加速器,中科大加速器,Docker
中国官方镜像加速:https://registry.docker-cn.com

官方pull      docker pull centos:6.8(没有指定版本,默认会下载最新版)
私有仓库pull    docker pull daocloud.io/huangzhichong/alpine-cn:latest 

##配置docker镜像加速
cat >/etc/docker/daemon.json <<END
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}   
END
  • 导入导出查看
查看镜像列表
    docker image  ls
导出镜像
    docker save  例子:docker save nginx:latest >/opt/docker-nginx.tar.gz
                       docker image save -o /opt/docker-nginx1.tar.gz  nginx:latest
导入镜像
    docker load  例子:docker load </opt/docker_centos6.9.tar.gz
                       docker image load  -i /opt/docker_centos6.9.tar.gz
删除镜像
    docker rmi   例子:docker rmi centos:6.9
                       docker image rm centos:6.9
将多个镜像导出
    docker save `docker image ls |tail -4 |awk  '{print $1":"$2}'` >/opt/docker_k8s.tar.gz
  • 阿里云docker镜像网站

https://cr.console.aliyun.com/cn-hangzhou/instances/repositories

九、docker的容器管理

  • 容器有关的操作
[root@docker ~]# docker container  
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  inspect     Display detailed information on one or more containers
  kill        Kill one or more running containers
  logs        Fetch the logs of a container
  ls          List containers
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  prune       Remove all stopped containers
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  run         Run a command in a new container
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes
  • 详细操作
创建并运行一个容器
docker run -d -p 80:80 nginx:latest  
run(创建并运行一个容器)
-d 放在后台
-p 端口映射
-v  源地址(宿主机):目标地址(容器)

进入到centos容器里面
docker run -it --name centos6 centos:6.9 /bin/bash
-it   分配交互式的终端
--name 指定容器的名字
/bin/sh覆盖容器的初始命令

启动容器***
    docker run image_name
    docker run -it image_name CMD
停止容器
    docker stop CONTAINER_ID
杀死容器
    docker kill container_name
查看容器列表
    docker ps
    docker ps –a 
进入容器(目的,调试,排错)
    docker container exec -it a487027c6d07 /bin/bash  (/bin/sh)
删除容器
    docker rm
批量删除容器
    docker rm -f `docker ps -a -q`
    
总结:docker容器内的第一个进程(初始命令)必须一直处于前台运行的状态(必须夯住),否则这个容器,就会处于退出状态!
业务在容器中运行:夯住,启动服务

十、docker容器的网络访问(端口映射)

docker0:172.17.0.1   jumpserver:172.17.0.2   nginx:172.17.0.3

指定映射(docker 会自动添加一条iptables规则来实现端口映射)
    -p hostPort:containerPort
    例子:docker run -d -p 80:80 nginx:latest 
    
    -p ip:hostPort:containerPort  多个容器都想使用80端口
    例子:ifconfig eth0:1 10.0.0.101/24 up
          docker run -d -p 10.0.0.11:80:80 nginx:latest 
          docker run -d -p 10.0.0.101:80:80 nginx:latest  
    
    -p ip::containerPort(随机端口)
    例子:docker run -d -p 10.0.0.11::80 nginx:latest
    
    -p hostPort:containerPort:udp
    -p  10.0.0.100::53:udp   使用宿主机的10.0.0.100这个ip地址的随机端口的udp协议映射容器的udp53端口
    -p 81:80 –p 443:443 可以指定多个-p

随机映射
    docker run -d -P (随机端口)

通过iptables来实现的端口映射

十一、docker的数据卷管理

第一种方法
docker container cp . 19bebe1d49ff:/usr/share/nginx/html
第二种方法(-v参数)
docker run -d -p 81:80 -v /srv:/usr/share/nginx/html nginx:latest
第三种方法(卷)
docker run -d -p 82:80 -v test:/usr/share/nginx/html nginx:latest
查看(卷)
docker volume inspect test

持久化
数据卷(文件或目录)
    -v 卷名:/data
    -v src(宿主机的目录):dst(容器的目录)
数据卷容器
    --volumes-from(跟某一个已经存在的容器挂载相同的卷)
    
基于nginx启动一个容器,监听80和81,访问80,出现nginx默认欢迎首页,访问81,出现小鸟。
cat >/opt/xiaoniao.conf <<EOF
server {
    listen       81;
    server_name  localhost;
    root         /opt;
    index  index.html index.htm;
    location / {
    }
}
EOF
docker run -d -p 80:80 -p 81:81 -v /opt/xiaoniao.conf:/etc/nginx/conf.d/xiaoniao.conf -v /srv:/opt nginx:latest 
docker ps -a -l

基于nginx多端口的多站点。
-p 80:80 -p 81:81 -v  xxx:xxx -v  xxx:xxxx

快捷键
ctrl +p 再按ctrl +q               临时退出
docker attach e44ab4833867        回到容器里面

十二、手动将容器保存为镜像

  • 制作一个ssh服务单服务镜像v1
连接centos6系统tty终端,并将1022端口映射到22端口
[root@docker ~]# docker run -it -p 1022:22 centos:6.9

centos6 Base源
[root@21ee1761f602 /]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

报错
WARNING: IPv4 forwarding is disabled. Networking will not work.
解决方案
[root@docker ~]# sysctl net.ipv4.ip_forward=1


下载ssh服务
[root@21ee1761f602 /]# yum install openssh-server -y

启动服务
[root@docker ~]# service sshd start

为root设置密码,并远程连接
[root@21ee1761f602 /]# echo  '123456'|passwd --stdin root
[root@docker ~]# ssh root@10.0.0.11 -p 1022

提交成镜像
[root@docker ~]# docker commit 21ee1761f602 centos6.9_ssh:v1

查看结果
[root@docker ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
centos6.9_ssh       v1                  120835cc897b        About a minute ago   309MB

测试,并连接
[root@docker ~]# docker run -d -p 3022:22 centos6.9_ssh:v1  /usr/sbin/sshd -D
[root@docker ~]# ssh root@10.0.0.11 -p 3022
[C:\~]$ ssh root@10.0.0.11 3022

总结步骤:
1、启动一个基础的容器(基于xxx操作系统)
2、把容器提交为镜像
3、测试镜像功能(即启动服务,又夯住的命令)
  • 制作双服务镜像,sshd + nginx v1版本
登录到centos 6.9_ssh映射端口
[root@docker ~]# docker run -it -p 1023:22 -p 82:80 centos6.9_ssh:v1 /bin/bash

配置repo源
[root@dc613a94f715 /]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo

安装nginx
[root@dc613a94f715 /]# yum install nginx -y

脚本1
[root@dc613a94f715 /]# cat >/init.sh<<EOF
#方法一
#!/bin/bash
#service sshd restar
#nginx -g 'daemon off;'
#方法二
service nginx start
/usr/sbin/sshd -D
EOF

脚本2(建议用)
[root@dc613a94f715 /]# cat >/init.sh<<EOF
#!/bin/bash
service nginx start
service sshd start
tail -f /etc/hosts
EOF
注释:以上脚本选一种

提交成镜像
[root@docker ~]# docker commit dc613a94f715 centos6.9_ssh_nginx:v1

检查
[root@docker ~]# docker images 
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
centos6.9_ssh_nginx   v1                  33510a033b82        2 minutes ago       506MB

测试,并连接
[root@docker ~]# docker run -d -p 83:80 -p 1024:22 centos6.9_ssh_nginx:v1 /bin/bash /init.sh
[root@docker ~]# ssh root@10.0.0.11 -p 1024
[root@docker ~]# curl -I 10.0.0.11:83  2>/dev/null|head  -3

[root@docker ~]# docker logs dc613a94f715    查看状态

十三、安装php项目kodexplorer

  • centos 7环境搭建
环境:
nginx+php

配置源
echo  '192.168.12.201  mirrors.aliyun.com' >>/etc/hosts
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

安装nginx php-fpm
yum install nginx php-fpm -y

备份nginx配置文件
grep -Ev '^$|#' /etc/nginx/nginx.conf.default  >/etc/nginx/nginx.conf
>/etc/nginx/nginx.conf

修改配置文件
vim /etc/nginx/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        root /code;
        location / {
        }
        index index.php index.html index.htm;
        location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /code$fastcgi_script_name;
        include        fastcgi_params;
       }
    }
}

检查配置文件
nginx -t

创建站点目录 
mkdir /code

下载可道云
wget -P /code http://192.168.12.201/docker_image/kodexplorer4.40.zip
unzip -d /code /code/kodexplorer4.40.zip 

授权用户
chown -R nginx:nginx /code

修改php启动用户
cp /etc/php-fpm.d/www.conf{,.bak}
sed -i '/^user/c user = nginx' /etc/php-fpm.d/www.conf 
sed -i '/^group/c group = nginx' /etc/php-fpm.d/www.conf

安装php模块
yum install php-gd php-mbstring.x86_64 -y

启动服务
systemctl start php-fpm.service  nginx.service 

windows浏览器访问
10.0.0.100

[图片上传失败...(image-4a32d3-1564622978836)]

  • docker 环境搭建
进入容器
[root@docker ~]# docker run -it -p 1088:22 -p 88:80 -p 9088:9000 centos6.9_ssh:v1 /bin/bash

配置源
[root@dc613a94f715 /]# echo  '192.168.12.201  mirrors.aliyun.com' >>/etc/hosts
[root@dc613a94f715 /]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@dc613a94f715 /]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

安装nginx php-fpm
[root@dc613a94f715 /]# yum install nginx php-fpm -y

备份nginx配置文件
[root@dc613a94f715 /]# grep -Ev '^$|#' /etc/nginx/nginx.conf.default  >/etc/nginx/nginx.conf
[root@dc613a94f715 /]# >/etc/nginx/nginx.conf

修改配置文件
[root@dc613a94f715 /]# vim /etc/nginx/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        root /code;
        location / {
        }
        index index.php index.html index.htm;
        location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /code$fastcgi_script_name;
        include        fastcgi_params;
       }
    }
}
EOF

检查配置文件
[root@dc613a94f715 /]# nginx -t

创建站点目录 
[root@dc613a94f715 /]# mkdir /code

将有道云传到docker容器里面
[root@docker ~]# docker container \cp -a /code/* dc613a94f715:/code

授权用户
[root@dc613a94f715 /]# chown -R nginx:nginx /code

修改php启动用户
[root@dc613a94f715 /]# cp /etc/php-fpm.d/www.conf{,.bak}
[root@dc613a94f715 /]# sed -i '/^user/c user = nginx' /etc/php-fpm.d/www.conf 
[root@dc613a94f715 /]# sed -i '/^group/c group = nginx' /etc/php-fpm.d/www.conf

安装php模块
[root@dc613a94f715 /]# yum install php-gd php-mbstring.x86_64 -y

脚本
[root@dc613a94f715 /]# cat >/init.sh<<EOF
#!/bin/bash
service sshd start
service nginx start
service php-fpm start
tail -f /etc/hosts
EOF

提交成镜像
[root@docker ~]# docker commit dc613a94f715 centos6.9_kedaoyun:v1

测试
[root@docker ~]# docker run -d -p 2223:22 -p 89:80 -p 9998:9000 centos6.9_kedaoyun:v1 /bin/bash /init.sh

[图片上传失败...(image-bfa8cd-1564622978836)]

十四、dockerfile自动构建docker镜像

类似ansible剧本,大小几kb
手动做镜像:大小几百M+

dockerfile 支持自定义容器的初始命令


dockerfile主要组成部分:
    基础镜像信息       FROM  centos:6.9
    制作镜像操作指令   RUN yum install openssh-server -y
    容器启动时执行指令 CMD ["/bin/bash"]

dockerfile常用指令:
    FROM 这个镜像的妈妈是谁?(指定基础镜像)
    MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)
    LABLE      描述,标签
    
    RUN 你想让它干啥(在命令前面加上RUN即可)
    ADD 给它点创业资金(会自动解压tar)  制作docker基础的系统镜像
    WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)
    VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)
    EXPOSE 它要打开的门是啥(指定对外的端口)(-P 随机端口)
    CMD 奔跑吧,兄弟!(指定容器启动后的要干的事情)(容易被替换)
    
dockerfile其他指令: 
    COPY 复制文件(不会解压)rootfs.tar.gz
    ENV  环境变量
    ENTRYPOINT  容器启动后执行的命令(无法被替换,启容器的时候指定的命令,会被当成参数)

参考其他的dockerfile
官方dockerfile或者时速云镜像广场

dockerfile 优化
1、使用.dockerignore 减少ADD copy 上传文件
2、尽可能合并,清理无用文件(yum缓存,源码包)
3、修改dockerfile,把变化的内容尽可能放在dockerfile结尾
  • dockerfile 网站

https://github.com/CentOS/CentOS-Dockerfiles

  • 自动构建sshd服务
mkdir -p /data/dockerfile/centos6.9_ssh

vim  /data/dockerfile/centos6.9_ssh/dockerfile
FROM centos:6.9
RUN echo  '192.168.12.201  mirrors.aliyun.com' >>/etc/hosts
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
RUN yum install openssh-server -y
RUN /etc/init.d/sshd restart
RUN echo 123456|passwd --stdin root
CMD ["/usr/sbin/sshd","-D"]

docker build --network=host -t centos6.9_ssh:v3 /data/dockerfile/centos6.9_ssh/

测试
docker run -d -p 2022:22 centos6.9_ssh:v3
ssh root@10.0.0.11 -p 2022
  • 自动构建sshd+nginx服务
cp -a /data/dockerfile/centos6.9_ssh /data/dockerfile/centos6.9_ssh_nginx

vim  /data/dockerfile/centos6.9_ssh_nginx/dockerfile
FROM centos:6.9
RUN echo  '192.168.12.201  mirrors.aliyun.com' >>/etc/hosts
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
RUN yum install openssh-server nginx -y
RUN /etc/init.d/sshd start
RUN echo 123456|passwd --stdin root
ADD init.sh /init.sh
CMD ["/bin/bash","/init.sh"]

cd /data/dockerfile/centos6.9_ssh_nginx/

cat >init.sh<<EOF
#!/bin/bash
service nginx restart
service sshd  restart
tail -f /etc/hosts
EOF

docker build --network=host -t centos6.9_ssh_nginx:v4 /data/dockerfile/centos6.9_ssh_nginx/

测试
docker run -d -p 3022:22 -p 86:80 centos6.9_ssh_nginx:v4
ssh root@10.0.0.11 -p  3022
curl -I 10.0.0.11:86 2>/dev/null|head -3 
  • 自动构建可道云项目
mkdir -p /dockerfile/kd

vim /dockerfile/kd/dockerfile
FROM centos:6.9
RUN echo  '192.168.12.201  mirrors.aliyun.com' >>/etc/hosts
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
RUN yum install php-fpm php-mbstring php-gd nginx -y
ADD nginx.conf /etc/nginx/
RUN sed -i '/^user/c user = nginx' /etc/php-fpm.d/www.conf
RUN sed -i '/^group/c group = nginx' /etc/php-fpm.d/www.conf
RUN mkdir /code
ADD kd.tar.gz /code
RUN chown -R nginx:nginx /code
EXPOSE 81
ADD init.sh /code/init.sh
ENTRYPOINT ["/bin/bash","/code/init.sh"]

cd /dockerfile/kd/

cat >init.sh<<EOF
#!/bin/bash
service nginx  restart
service php-fpm  restart
tail -f /etc/hosts
EOF

制作成镜像
docker build --network=host -t centos6.9_kd:v1 .

测试
docker run -d -p 88:80 centos6.9_kd:v1

浏览器访问
10.0.0.11:88

十五、docker镜像的分层(kvm 链接克隆,写时复制的特性)

  • docker实现zabbix互联
镜像分层的好处:复用,节省磁盘空间,相同的内容只需加载一份到内存。
修改dockerfile之后,再次构建速度快


容器间的互联(--link 是单方向的!!!)
    docker run -d -p 80:80 nginx
    docker run -it --link quirky_brown:web01 qstack/centos-ssh /bin/bash
    ping web01  
    
lb  --->    nginx  172.17.0.4 --> db01   172.17.0.3
                              --> nfs01  172.17.0.2

上传软件包
rz -E 

批量导入到docker容器里面
for n in `ls *.gz`;do docker load -i $n;done

使用docker运行zabbix-server(命令行执行)
docker run --name mysql-server -t \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      -d mysql:5.7 \
      --character-set-server=utf8 --collation-server=utf8_bin

docker run --name zabbix-java-gateway -t \
      -d zabbix/zabbix-java-gateway:latest

docker run --name zabbix-server-mysql -t \
      -e DB_SERVER_HOST="mysql-server" \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      -e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
      --link mysql-server:mysql \
      --link zabbix-java-gateway:zabbix-java-gateway \
      -p 10051:10051 \
      -d zabbix/zabbix-server-mysql:latest

docker run --name zabbix-web-nginx-mysql -t \
      -e DB_SERVER_HOST="mysql-server" \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      --link mysql-server:mysql \
      --link zabbix-server-mysql:zabbix-server \
      -p 80:80 \
      -d zabbix/zabbix-web-nginx-mysql:latest

windows 访问测试
10.0.0.11
用户:Admin
密码:zabbix


监控100主机(在100主机安装)
wget http://192.168.12.201/docker_image/zabbix-agent-3.2.0-1.el7.x86_64.rpm
rpm -Uvh zabbix-agent-3.2.0-1.el7.x86_64.rpm

修改配置文件里面server标签
vim /etc/zabbix/zabbix_agentd.conf


监控报警:微信报警,alpine      
yum 安装zabbix好使

[图片上传失败...(image-91c278-1564622978836)]

十六、docker registry(私有仓库)

  • 私有仓库
wget http://192.168.12.201/docker_image/registry.tar.gz
docker load -i registry.tar.gz
普通的registry
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry  registry:latest
给镜像打标签
docker tag alpine:latest 10.0.0.11:5000/alpone:latest
将镜像上传到私有仓库里面
docker push  10.0.0.11:5000/alpone:latest


如果遇到报错:
The push refers to repository [10.0.0.11:5000/centos6.9_ssh]
Get https://10.0.0.11:5000/v2/: http: server gave HTTP response to HTTPS client

解决方法:
vim  /etc/docker/daemon.json
{
  "insecure-registries": ["10.0.0.11:5000"]
}
systemctl restart docker
=================================================================================

删除镜像
1)进入docker registry的容器中
docker exec -it registry /bin/sh
2) 删除repo
rm -fr /var/lib/registry/docker/registry/v2/repositories/nginx
3) 清楚掉blob
registry garbage-collect /etc/docker/registry/config.yml
=================================================================================

带认证的registry
yum install httpd-tools -y
mkdir /opt/registry-var/auth/ -p
htpasswd -Bbn oldboy 123456 >> /opt/registry-var/auth/htpasswd
docker run -d -p 5000:5000 -v /opt/registry-var/auth/:/auth/ -v /opt/myregistry:/var/lib/registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry

提示:上传下载镜像都需要登陆哦

docker login 10.0.0.11:5000
oldboy
123456

docker logout 10.0.0.11:5000登出
  • 参考文档

https://www.qstack.com.cn/archives/350.html

十七、docker-compose(单机版的容器编排工具)

  • 官方文档

https://docs.docker.com/compose/compose-file/

  • docker-compose实现wordpress项目
yum install -y docker-compose(需要epel源)


##详细指令
http://www.jianshu.com/p/2217cfed29d7


[root@docker /data]# mkdir /data/docker-compose/wordpress -p
[root@docker /data]# vim /data/docker-compose/wordpress/docker-compose.yaml
version: '3'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
       - web_data:/var/www/html
     ports:
       - "80:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
    web_data:


#先进入目录才能启动
cd /data/docker-compose/wordpress
#启动
docker-compose up
#后台启动
docker-compose up -d
#停止(一般不用,会移除镜像)
docker-compose down -d

#建议用
docker-compose start
docker-compose stop
docker-compose restart

[图片上传失败...(image-47d96-1564622978836)]

  • docker-compose实现zabbix项目
[root@docker /data]# mkdir /data/docker-compose/zabbix -p
[root@docker /data]# vim /data/docker-compose/zabbix/docker-compose.yaml
version: '3'

services:
   mysql-server:
     image: mysql:5.7
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: root_pwd
       MYSQL_DATABASE: zabbix
       MYSQL_USER: zabbix
       MYSQL_PASSWORD: zabbix_pwd
     command: --character-set-server=utf8
   zabbix-java-gateway:
     image: zabbix/zabbix-java-gateway:latest
     restart: always
   zabbix-server:
     depends_on:
       - mysql-server
     image: zabbix/zabbix-server-mysql:latest
     ports:
       - "10051:10051"
     restart: always
     environment:
       DB_SERVER_HOST: mysql-server
       MYSQL_DATABASE: zabbix
       MYSQL_USER: zabbix
       MYSQL_PASSWORD: zabbix_pwd
       MYSQL_ROOT_PASSWORD: root_pwd
       ZBX_JAVAGATEWAY: zabbix-java-gateway
   zabbix-web:
     depends_on:
       - mysql-server
       - zabbix-server
     image: zabbix/zabbix-web-nginx-mysql:latest
     ports:
       - "80:80"
     restart: always
     environment:
       DB_SERVER_HOST: mysql-server
       MYSQL_DATABASE: zabbix
       MYSQL_USER: zabbix
       MYSQL_PASSWORD: zabbix_pwd
       MYSQL_ROOT_PASSWORD: root_pwd

#启动
cd /data/docker-compose/zabbix
docker-compose up -d

指定名字启动
docker-compose -f docker-compose.yaml  up -d

[图片上传失败...(image-deb92e-1564622978836)]

十八、重启docker服务,容器全部退出的解决办法

方法一:docker run  --restart=always

方法二:"live-restore": true
docker server配置文件/etc/docker/daemon.json参考
{
 "registry-mirrors": ["http://b7a9017d.m.daocloud.io"],
 "insecure-registries":["10.0.0.11:5000"],
 "live-restore": true
}

十九、Docker Machine安装docker服务

Docker Machine 二进制  10.0.0.11
10.0.0.12 免密码登陆  从docker的官网下载二进制的包,去安装docker
10.0.0.13 免密码登陆

ansible:
shell

二十、Docker网络类型

None:不为容器配置任何网络功能,                      --netwoek=none
Container:与另一个运行中的容器共享Network Namespace,--netwoek container:容器id(K8S)
Host:与宿主机共享Network Namespace,                 --network=host
Bridge:Docker设计的NAT网络模型                       --network=Bridge

查看:
docker inspect 8193487ce52f |grep -i network

用法:
docker run  --network=none -it centos:6.9   /bin/bash 
docker run --network container:8193487ce52f  -it centos:6.9  /bin/bash

二十一、Docker跨主机容器之间的通信macvlan

默认一个物理网卡,只有一个物理地址,虚拟多个mac地址

##创建macvlan网络
docker network create --driver macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=eth0 macvlan_1
##设置eth0的网卡为混杂模式
ip link set eth1 promisc on
##创建使用macvlan网络的容器
docker run -it --network macvlan_1 --ip=10.0.0.200 busybox
##删除
docker network rm macvlan_1 


作业1:用PIPEWORK为docker容器配置独立IP
作业2:docker跨主机容器间的通信flannel
  • 实现macvlan步骤
环境:两台装好docker的虚拟机

两台机器执行
docker network create --driver macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=eth0 macvlan_1

两台电下载镜像包并测试
wget http://192.168.12.201/docker_image/docker_busybox.tar.gz
docker  load  -i   docker_busybox.tar.gz

docker01执行
docker run -it  --network  macvlan_1  --ip=10.0.0.222   busybox:latest

docker02执行
docker run -it  --network  macvlan_1  --ip=10.0.0.223   busybox:latest


测试结果
dcoker01执行
/ # ping 10.0.0.223
PING 10.0.0.223 (10.0.0.223): 56 data bytes
64 bytes from 10.0.0.223: seq=0 ttl=64 time=1.718 ms
64 bytes from 10.0.0.223: seq=1 ttl=64 time=0.675 ms
64 bytes from 10.0.0.223: seq=2 ttl=64 time=0.660 ms

docker02执行
/ # ping 10.0.0.222
PING 10.0.0.222 (10.0.0.222): 56 data bytes
64 bytes from 10.0.0.222: seq=0 ttl=64 time=1.050 ms
64 bytes from 10.0.0.222: seq=1 ttl=64 time=1.349 ms

二十二、Dcoker跨主机容器通信之overlay

  • 参考文档

http://www.cnblogs.com/CloudMan6/p/7270551.html

  • 实现overlay步骤
环境:3台装好docker的虚拟机
注释:主机名字不能一样


dock03安装docker
wget http://192.168.12.201/docker_image/docker_rpm.tar.gz
tar xf /root/docker_rpm.tar.gz 
rpm -Uvh *.rpm
systemctl enable docker
systemctl start docker
wget http://192.168.12.201/docker_image/docker_progrium_consul.tar.gz
docker load -i docker_progrium_consul.tar.gz
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap

dock01执行
vim  /etc/docker/daemon.json
{
  "hosts":["tcp://0.0.0.0:2376","unix:///var/run/docker.sock"],
  "cluster-store": "consul://10.0.0.13:8500",
  "cluster-advertise": "10.0.0.11:2376"
}

dock02执行
vim  /etc/docker/daemon.json
{
  "hosts":["tcp://0.0.0.0:2376","unix:///var/run/docker.sock"],
  "cluster-store": "consul://10.0.0.13:8500",
  "cluster-advertise": "10.0.0.12:2376"
}

docker01和docker02
vim /usr/lib/systemd/system/docker.service
systemctl daemon-reload 
systemctl restart docker

任意一台,创建overlay网络
docker network create -d overlay --subnet 172.16.1.0/24 --gateway 172.16.1.254 ol1

启动容器测试
docker run -it --network ol1 --name docker01 busybox /bin/sh
docker run -it --network ol1 --name docker02 busybox /bin/sh
  • 修改配置文件截图

[图片上传失败...(image-26eab-1564622978836)]

  • 执行成功截图

[图片上传失败...(image-3e5359-1564622978836)]

二十三、docker企业级镜像仓库harbor(vmware 中国团队)

  • 实现步骤
第一步:安装docker和docker-compose
第二步:下载harbor-offline-installer-v1.3.0.tgz
第三步:上传到/opt,并解压
第四步:修改harbor.cfg配置文件
hostname = 10.0.0.11
harbor_admin_password = 123456
第五步:执行install.sh
========================================================================

docker 01执行
rz -E harbor-offline-installer-v1.8.0.tgz
tar xf harbor-offline-installer-v1.8.0.tgz -C  /opt
docker load < /opt/harbor/harbor.v1.8.0.tar.gz

修改配置文件
vim /opt/harbor/harbor.yml

执行脚本
cd /opt/harbor
. /opt/harbor/install.sh 


docker 02执行
修改配置文件
vim /etc/docker/daemon.json 

测试
docker tag fuck_php56:latest 10.0.0.11/library/fuck_php56:latest
docker push 10.0.0.11/library/fuck_php56:latest
  • 修改配置文件/opt/harbor/harbor.yml

[图片上传失败...(image-62db92-1564622978836)]

  • 修改配置文件/etc/docker/daemon.json

[图片上传失败...(image-4d8f92-1564622978836)]

  • docker私有仓库导入企业仓库脚本(批量导入)
#!/bin/bash
docker_name=`curl http://10.0.0.12:5000/v2/_catalog 2>/dev/null|jq '.repositori
es[]'|tr '"' '\0'`
for n in $docker_name
do
    for i in `curl http://10.0.0.12:5000/v2/${n}/tags/list 2>/dev/null|jq '.tag
s[]'|tr '"' '\0'`
    do
        docker pull 10.0.0.12:5000/${n}:${i}
        docker tag 10.0.0.12:5000/${n}:${i} www.duanyang.vip/library/${n}:${i}
        docker push www.duanyang.vip/library/${n}:${i}
    done
done

二十四、k8s的安装方法

kubernetes 二进制安装 安装最新版,步骤繁琐!!
https://github.com/minminmsn/k8s1.13/blob/master/kubernetes/kubernetes1.13.1%2Betcd3.3.10%2Bflanneld0.10%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2.md

kubeadm 安装(网络原因)
https://www.qstack.com.cn/archives/425.html

minikube 安装(网络原因)

yum 安装(最容易 1.5)

go编译安装(大神级别)

k8s-master 管理者
kubelet --docker 启动容器
kubelet --docker



####制作一个只支持sshd服务的镜像
1):启动一个容器,并修改
docker run -it -p 1022:22 centos:6.8 /bin/bash
yum install openssh-server -y
echo 'root:123456'|chpasswd
/etc/init.d/sshd start
测试:ssh远程登录

2):将修改后的容器,保存为镜像
docker commit friendly_swartz centos6-ssh

3)测试新镜像,sshd是否可用
docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D
ssh root@10.0.0.11 -p 1122


####制作了一个支持sshd和httpd双服务的镜像
1):启动一个容器,并修改
docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D
yum install httpd -y
/etc/init.d/httpd start

vi /init.sh
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D

chmod +x /init.sh
2):将修改后的容器,保存为镜像
docker commit 11bf5984784a centos6-httpd

3)测试新镜像,检测sshd和httpd是否可用
docker run -d -p 1222:22 -p 80:80 centos6-httpd:latest /init.sh

作业:使用Dockerfile完成kodexplorer网盘项目

课前回顾:
Linux容器是与系统其他部分隔离开的一系列进程,从另一个系统镜像rootfs运行,并由该镜像提供支持进程所需的全部文件。
容器镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。

1:chroot,ldd
2:lxc namespace(6大命名空间)和cgroup
3:docker和kvm区别,docker镜像基础操作,docker容器日常操作,commit制作镜像,dockfile来自动构建镜像

####docker私有仓库registry
1)启动registry容器
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry  registry

2)修改/etc/docker/daemon.json配置文件
{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries": ["10.0.0.11:5000"]
}

3)重启docker服务
systemctl restart docker

4)为镜像打标签
docker tag centos:6.8 10.0.0.11:5000/oldboy/centos:6.8

5)push推送镜像
docker push 10.0.0.11:5000/oldboy/centos:6.8
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容