云计算之k8s系列_第三回

云计算之k8s系列_第三回——docker实践

实践操作

用docker部署一个用python编写的web应用

[root@centos7 ~]# vim app.py
    from flask import Flask
    import socket
    import os

    app = Flask(__name__)

    @app.route('/')
    def hello():
        html = "<h3>Hello {name}!</h3>" \
            "<b>Hostname:</b> {hostname}<br/>"
        return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())


    if __name__=="__main__":
        app.run(host='0.0.0.0', port=80)

这个应用的依赖,并定义在了同目录下的requirements.txt文件中

[root@centos7 ~]# cat requirements.txt
    Flask

制作Dockerfile

[root@centos7 ~]# vim Dockerfile
    FROM    docker.io/python
    WORKDIR /app
    ADD .   /app
    RUN pip install --trusted-host pypi.python.org -r requirements.txt
    EXPOSE  80
    ENV NAME    World
    CMD [ "python" , "app.py" ]

使用Dockerfile制作这个镜像

[root@centos7 ~]# docker built -t helloworld .
[root@centos7 ~]# docker images

使用生成的镜像启动容器

[root@centos7 ~]# docker run -d -p 4000:80 helloworld
[root@centos7 ~]# ss -anptu | grep :4000
    tcp    LISTEN     0      1024     :::4000                 :::*                   users:(("docker-proxy-cu",pid=16548,fd=4))
[root@centos7 ~]# curl 127.0.0.1:4000
    <h3>Hello World!</h3><b>Hostname:</b> d7807cac63e5<br/>

注册docker hub账号,使用docker login登录上传镜像

#此处已有账号,不做注册,如果没有dockerhub账号的话,可以到官网注册
[root@centos7 docker]# docker login
    Username: daneiyunzhijia
    Password: 
    Login Succeeded
[root@centos7 docker]# docker tag helloworld daneiyunzhijia/helloworld:latest
[root@centos7 docker]# docker push daneiyunzhijia/helloworld:latest

进入刚刚创建的容器,创建文件,退出,并使用docker commit生成新的镜像

[root@centos7 docker]# docker exec -it c2 /bin/sh
# touch test.txt
# exit
[root@centos7 docker]# docker commit c2 daneiyunzhijia/helloworld:v2

思考:docker exec是怎么做到进入容器的?

一个进程的namespace在宿主机上是以一个文件的方式存在的。

[root@centos7 docker]# docker inspect c2 | grep Pid
        "Pid": 16722
[root@centos7 docker]# ls -l /proc/16722/ns
    total 0
    lrwxrwxrwx 1 root root 0 May 26 23:32 ipc -> ipc:[4026532233]
    lrwxrwxrwx 1 root root 0 May 26 23:11 mnt -> mnt:[4026532231]
    lrwxrwxrwx 1 root root 0 May 26 23:11 net -> net:[4026532293]
    lrwxrwxrwx 1 root root 0 May 26 23:32 pid -> pid:[4026532234]
    lrwxrwxrwx 1 root root 0 May 26 23:40 user -> user:[4026531837]
    lrwxrwxrwx 1 root root 0 May 26 23:32 uts -> uts:[4026532232]   

可以看到,一个进程的每种namespace,都在它对应的/proc/容器进程id/ns下有一个对应的虚拟文件,并且连接到一个真实的namespace文件上。有了这个功能,就可以加入到一个已经存在的namespace当中。

以上就是docker exec的实现原理:一个进程,可以选择加入到某个进程已有的namespace中,从而达到进入这个进程所在容器的目的。

一旦一个进程加入到另一个进程的namespace中,在宿主机的namespace文件上,也会有所体现。

如果创建容器时指定 --net=host,就意味着这个容器不会为进程启用network namespace。

docker commit

实际上就是在容器运行起来后,把最上层的“可读写层” , 加上原先容器镜像的只读层,打包组成一个新的镜像。当然,下面只读层在宿主机上是共享的,不会占用额外的空间。

copy-on-write: cow

在容器里对镜像rootfs所做的任何修改,都会被操作系统先复制到可读写层,然后在修改,这称为copy-on-write。

volume数据卷

volume机制,允许你将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作。

方法:冒号前面的部分对应宿主机目录,冒号后面的部分代表容器目录,不写冒号,代表宿主机和容器目录一样

#方法1
docker run -v /test centos ...
#方法2
docker run -v /home:/test ...

执行 -v 挂载操作时,容器进程已经创建了,所以,这个挂载只在容器可见,宿主机不可见,保证了容器的隔离性不会被volume打破。

所以,在一个正确的时机,进行一次绑定挂载,docker就可以成功地将一个宿主机上的目录或文件挂载到容器中。

docker 命令补充:

docker images           #查看已有的本地镜像
docker search rhel  #搜索docker镜像,本地和远程都会搜索
docker pull 镜像名 #下载镜像
docker push 镜像名 #上传镜像
docker load < busybox.tar   #导入镜像
docker save 镜像名  > busybox.tar  #保存镜像到本地文件
docker run -itd -v /a:/b -p 8080:80 镜像名 #使用镜像启动容器
docker ps -aq           #查看已经运行的和没有运行的容器
docker history          #查看镜像制作的历史
docker inspect          #查看容器或者镜像的详细信息
docker rmi 镜像名      #删除镜像
docker tag 镜像名  新名:v1   #修改镜像标签
docker run / stop / restart #启动/停止/重启容器
docker attach | exec            #进入容器
docker top                          #查看进程
docker rm                           #删除容器
docker commit 容器id  镜像名:标签  #使用容器,创建镜像
Dockerfile
    FROM                        #基础镜像
    MAINTAINER          #维护者
    EXPOSE                  #开放端口
    ENV                         #设置环境变量
    ADD                         #将本地文件加入到容器中
    RUN                         #在容器中执行命令
    WORKDIR             #定义工作目录
    CMD                     #容器启动时执行的命令
docker build -t imagename  .   #使用Dockerfile创建镜像

docker私有仓库

    docker pull registry
    vim /etc/docker/daemon.json
        {
            "insecure-registries": [ "仓库宿主机ip:5000" ]
        }
    docker run -d -p 5000:5000 registry
    docker tag 镜像   ip:5000/镜像:标签
    docker push ip:5000/镜像:标签

docker网络

网络模型:
    bridge
    host
    none
docker network create --driver bridge docker1
docker network list
docker run --network=docker1 -itd nginx 

docker 总结:

docker是分层显示地,最下层是docker镜像的只读层。在只读层纸上,是docker自己添加的init层,用来存放被临时修改过的/etc/hosts等文件。而rootfs之上是一个读写层,它以copy-on-write 的方式存放任何对只读层的修改,容器声明的volume的挂载点,也出现在这一层。

猜你喜欢

转载自blog.csdn.net/mx_steve/article/details/90601094