前言:
Docker是1种小型虚拟主机,那么Docker和KVM虚拟机主机之间有什么区别和联系?Docker的应用场景是什么呢?
Docker的本质是基于
- Linux内核的Namespace和Cgroup特性,Namespace实现了环境隔离、Cgroup实现了系统资源限制
- UnionFS实现了镜像分层打包。
Docker比虚拟机:更加轻量级、秒级即可启动、只要操作系统支持LXC技术,有doker服务,就可以跨主机到处运行。
Docker镜像的分层设计思想,给我感觉就是非常灵活,非常适用于To B的产品的部署;
一、Docker是什么以及和KVM的区别
1.Docker概念
Docker基于Linux内核的2大特性实现
- Namespace:隔离进程的UTS、IPC、PID、Network、Mount、User系统资源。
- Cgroup:ControlGroups把进程放到组里面,通过对组设置权限,进而限制进程对系统资源的使用。
2.Docker的设计理念
快速地构建(build)、运输(ship)、运行(running)系统环境
1个容器=1个在前台运行的进程。如果我就想在同1个容器里运行多个进程呢?那就让1个supervisor管理N个进程。
3.docker的架构
docker是C/S 架构 docker server 是服务端,我们执行的docker命令就是操作客户端;
[root@localhost zhanggen]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE ----------------------------------------------------------- [root@localhost zhanggen]# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) Active: active (running) since Wed 2019-03-20 15:19:16 CST; 6min ago Docs: https://docs.docker.com Main PID: 55180 (dockerd) Memory: 75.6M CGroup: /system.slice/docker.service └─55180 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
f
4.论docker and kvm
Docker Server 挂了所有的docker容器都会挂掉 (kvm的管理软件 和libvirtd完全隔离)
kvm是在内核级别完全虚拟化出来的虚拟机 虚拟机之间完全隔离
docker 容器是在操作系统层面进行的资源的隔离
Docker和KVM都可以进行状态的回滚
5.docker的优势和应用场景
简化了系统配置、减少了代码和系统环境间的依赖性(运行别人的代码还要部署别人的运行环境)
代码流水线管理 代码开发---->代码测试----》代码到生产 一个docker容器搞定
减少开发部署系统环境工作,提高开发效率。
docker容器和虚拟机相比可以快速得运行起来
面向产品:把自己的系统运行环境+代码打包进docker容器,直接完产品交付;
面向开发:做为一个python开发我再也不用去装什么Python3、pip、Nginx了,我只关心我的代码怎么写?
面向测试:测试的时候不用搭建多套系统环境了
面向运行:环境一致性,系统环境可以回滚
面向架构:自动化扩容
{ "registry-mirrors": ["https://pee6w651.mirror.aliyuncs.com"] }
查看docker日志
这个很关键,遇到报错一定不要心浮气躁,也不要直接去百度搜索报错内容, 科学的做法是:看日志-----》锁定问题-----》解决问题
[root@localhost zhanggen]# journalctl -xe Mar 20 14:28:31 localhost.localdomain polkitd[582]: Registered Authentication Agent for unix-process:55506:719734 (system bus name :1.510 [/ Mar 20 14:28:31 localhost.localdomain systemd[1]: Starting Docker Storage Setup... -- Subject: Unit docker-storage-setup.service has begun start-up -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit docker-storage-setup.service has begun starting up. Mar 20 14:28:31 localhost.localdomain container-storage-setup[55512]: INFO: Volume group backing root filesystem could not be determined Mar 20 14:28:31 localhost.localdomain systemd[1]: Started Docker Storage Setup. -- Subject: Unit docker-storage-setup.service has finished start-up -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit docker-storage-setup.service has finished starting up. -- -- The start-up result is done. Mar 20 14:28:31 localhost.localdomain systemd[1]: Starting Docker Application Container Engine... -- Subject: Unit docker.service has begun start-up -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit docker.service has begun starting up. Mar 20 14:28:31 localhost.localdomain dockerd-current[55557]: unable to configure the Docker daemon with file /etc/docker/daemon.json: inval Mar 20 14:28:31 localhost.localdomain systemd[1]: docker.service: main process exited, code=exited, status=1/FAILURE Mar 20 14:28:31 localhost.localdomain systemd[1]: Failed to start Docker Application Container Engine. -- Subject: Unit docker.service has failed -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit docker.service has failed. -- -- The result is failed. Mar 20 14:28:31 localhost.localdomain systemd[1]: Unit docker.service entered failed state. Mar 20 14:28:31 localhost.localdomain systemd[1]: docker.service failed. Mar 20 14:28:31 localhost.localdomain polkitd[582]: Unregistered Authentication Agent for unix-process:55506:719734 (system bus name :1.510,
查看docker版本
[root@localhost zhanggen]# docker version Client: Version: 1.13.1 API version: 1.26 Package version: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
源码安装
#!/bin/bash project_volume=/mingde_project image_name="modelsystem:2.0" container_name="modelsystem" read -r -p "Are you sure that docker have not been installed? [Yes/No] " confirmation1 echo $confirmation1 if [[ "$confirmation1" != "Yes" ]];then echo "Bye Bye.." exit 0 fi \cp -rf ../plugins/docker/* /usr/bin/ \cp -rf ../plugins/docker.service /usr/lib/systemd/system/ mkdir -p $project_volume && \cp -rf ../project/* $project_volume systemctl daemon-reload systemctl start docker echo "Docker have installed successfully" for i in ../images/*;do docker load < $i;done #docker/docker load < ../images/modelsystem.tar check_conflict=$(docker ps -a -q --filter ancestor=$image_name) if [[ $check_conflict != "" ]] then docker rm -f $(docker ps -a -q --filter ancestor=$image_name) fi docker run -d -p 8099:8099 -v $project_volume:/mingde --name $container_name $image_name
卸载docker
#!/bin/sh /usr/bin/systemctl daemon-reload echo '关闭docker服务....' echo '删除docker.service...' echo '删除docker文件...' rm -rf /mingde_project rm -rf /usr/lib/systemd/system/docker.service for file in ../plugins/docker/* do rm -rf /usr/bin/${file##*/} done #rm -rf /usr/lib/systemd/system/docker.service #rm -rf /usr/bin/containerd #rm -rf /usr/bin/containerd-shim #rm -rf /usr/bin/ctr #rm -rf /usr/bin/docker #rm -rf /usr/bin/dockerd #rm -rf /usr/bin/docker-init #rm -rf /usr/bin/docker-proxy #rm -rf /usr/bin/runc echo '删除docker文件...' echo '重新加载配置文件' /usr/bin/systemctl daemon-reload echo '卸载成功...'
7.离线二进制安装docker
目前我们主要开展To B业务,客户环境大多都是在内网,那么离线安装docker就成了我需要解决的问题;
我的要求:最大限度地保持客户环境安装目录的整洁和规范,把dockerd做成系统服务,可通过systemctl 进行启停管理并开机自启动。
以下是我的部署方案:
- 把docker二进制包都放在了自定义的目录下(/mingde/docker)而不是/usr/bin,
- 在/etc/profile.d目录下新增系统环境变量配置;
- 在systemd的docker.service中新增Environment=PATH=$PATH:/mingde/docker配置,以便让sysytemd启动dockerd前,可以加载到我在步骤2设置的系统环境变量。
/etc/profile.d/docker.sh
export PATH=$PATH:/mingde/docker
export PATH
/etc/systemd/system/docker.service
[Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker Environment=PATH=$PATH:/mingde/docker ExecStart=/mingde/docker/dockerd --selinux-enabled=false --iptables=false ExecReload=/bin/kill -s HUP $MAINPID # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Uncomment TasksMax if your systemd version supports it. # Only systemd 226 and above support this version. #TasksMax=infinity TimeoutStartSec=0 # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process # restart the docker process if it exits prematurely Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target
最后重新加载systemd,然后把dockerd服务变成系统服务。
[root@localhost docker]# ls containerd containerd-shim ctr docker dockerd docker-init docker-proxy runc [root@localhost docker]# pwd /mingde/docker [root@localhost docker]# systemctl daemon-reload [root@localhost docker]# systemctl start docker [root@localhost docker]# systemctl enable docker Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /etc/systemd/system/docker.service. [root@localhost docker]# reboot
把redis也做成可以被systemct启动的进程
/etc/systemd/system/redis.service
[Unit] Description=redis After=network.target [Service] PIDFile=/var/run/redis_6379.pid ExecStart=/mingde/redis-4.0.10/src/redis-server /mingde/redis-4.0.10/redis.conf ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
8.docker的组件
docker的组件分为:镜像image、容器container 、仓库(repository)
镜像:所有的docker容器都是由镜像启动构建的
仓库:集中存放镜像,用户同网络访问仓库获得想要镜像 DockerHub,就是GitHub一样;
容器:就是由镜像创建的实例(简化版的Linux环境)
9.加速镜像源访问
"https://ustc-edu-cn.mirror.aliyuncs.com", "http://hub-mirror.c.163.com", "https://registry.aliyuncs.com"
二、docker快速入门
从docker的三大组件开始快速入门docker;
1.docker镜像管理
去docker Hub 上搜素镜像
[root@localhost zhanggen]# docker search centos NAME DESCRIPTION STARS OFFICIAL AUTOMATED centos The official build of CentOS. 5261 [OK] ansible/centos7-ansible Ansible on Centos7 121 [OK] jdeathe/centos-ssh CentOS-6 6.10 x86_64 / CentOS-7 7.5.1804 x86… 109 [OK] consol/centos-xfce-vnc Centos container with "headless" VNC session… 83 [OK] imagine10255/centos6-lnmp-php56 centos6-lnmp-php56 52 [OK] centos/mysql-57-centos7 MySQL 5.7 SQL database server 49 tutum/centos Simple CentOS docker image with SSH access 44 gluster/gluster-centos Official GlusterFS Image [ CentOS-7 + Glust… 40 [OK] openshift/base-centos7 A Centos7 derived base image for Source-To-I… 39 centos/postgresql-96-centos7 PostgreSQL is an advanced Object-Relational … 37 kinogmt/centos-ssh CentOS with SSH 26 [OK] centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 22 openshift/jenkins-2-centos7 A Centos7 based Jenkins v2.x image for use w… 20 centos/php-56-centos7 Platform for building and running PHP 5.6 ap… 20 pivotaldata/centos-gpdb-dev CentOS image for GPDB development. Tag names… 10 openshift/wildfly-101-centos7 A Centos7 based WildFly v10.1 image for use … 6 openshift/jenkins-1-centos7 DEPRECATED: A Centos7 based Jenkins v1.x ima… 4 darksheer/centos Base Centos Image -- Updated hourly 3 [OK] pivotaldata/centos-mingw Using the mingw toolchain to cross-compile t… 2 pivotaldata/centos Base centos, freshened up a little with a Do… 2 pivotaldata/centos-gcc-toolchain CentOS with a toolchain, but unaffiliated wi… 1 blacklabelops/centos CentOS Base Image! Built and Updates Daily! 1 [OK] openshift/wildfly-81-centos7 A Centos7 based WildFly v8.1 image for use w… 1 smartentry/centos centos with smartentry 0 [OK] jameseckersall/sonarr-centos Sonarr on CentOS 7
去docker hub上下载镜像
[root@localhost zhanggen]# docker pull centos Using default tag: latest latest: Pulling from library/centos 8ba884070f61: Pull complete Digest: sha256:8d487d68857f5bc9595793279b33d082b03713341ddec91054382641d14db861 Status: Downloaded newer image for centos:latest [root@localhost zhanggen]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 9f38484d220f 6 days ago 2
docker镜像保存为文件(镜像导出)
[root@localhost zhanggen]# docker save -o Centos.tart centos [root@localhost zhanggen]# ls Centos.tart Desktop Documents Downloads Music Pictures Public Templates Videos
文件还原为docker镜像(镜像导入)
[root@localhost zhanggen]# docker load --input Centos.tar Loaded image: centos:latest [root@localhost zhanggen]#
删除docker镜像
[root@localhost zhanggen]# docker rmi -f centos Untagged: centos:latest Untagged: centos@sha256:8d487d68857f5bc9595793279b33d082b03713341ddec91054382641d14db861 [root@localhost zhanggen]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 9f38484d220f 6 days ago 202MB [root@localhost zhanggen]# docker pull centos Using default tag: latest latest: Pulling from library/centos Digest: sha256:8d487d68857f5bc9595793279b33d082b03713341ddec91054382641d14db861 Status: Downloaded newer image for centos:latest [root@localhost zhanggen]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 9f38484d220f 6 days ago 202MB [root@localhost zhanggen]#
2.docker容器管理
镜像的管理就是这些,主要还是自己可以构建镜像。
docker run -d -p 3306:3306 --privileged=true --name=MysqlServer --restart=always -e MYSQL_ROOT_PASSWORD=zhanggen@123 -v $PWD/logs:/var/log/docker -v $PWD/data:/var/lib/mysql -v $PWD/my.cnf:/etc/mysql/my.cnf -v /etc/localtime:/etc/localtime:ro mysql:5.7
------------------------------------------------------
[root@localhost zhanggen]# docker run centos /bin/echo 'Hellow World!' WARNING: IPv4 forwarding is disabled. Networking will not work. Hellow World!! [root@localhost zhanggen]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost zhanggen]#
PS:为什么 我运行了一个 echo 程序 docker容器就马上停止了?
因为docker容器默认会在docker容器的前台运行1个进程,这个进程结束docker,容器也随之停止了;(也许这就是它的一次性设计理念吧。。)
是不是很纳闷 为什么docker运行的进程退出,容器怎么就退出了? 这就是docker的理念---不可变基础设施理念!
docker就是给进程做隔离使用的,不同于虚拟机,虚拟机才是给操作系统做隔离使用的;
docker只是个容器 不是虚拟机!
[root@261f12e2d6e4 /]# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 78 model name : Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz stepping : 3 microcode : 0x88 cpu MHz : 2591.294 cache size : 4096 KB physical id : 0 siblings : 1 core id : 0 cpu cores : 1 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch arat fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid mpx rdseed adx smap clflushopt xsaveopt xsavec bogomips : 5184.39 clflush size : 64 cache_alignment : 64 address sizes : 43 bits physical, 48 bits virtual power management:
运行新的docker --name (容器名称) mydocker -t (terminal 打开一个终端) -i (std input 打开标准输入 )
[root@localhost zhanggen]# docker run --name mydocker -t -i centos /bin/bash
WARNING: IPv4 forwarding is disabled. Networking will not work.
[root@261f12e2d6e4 /]#
启动一个关闭的docker容器
[root@localhost zhanggen]# docker start mydocker mydocker [root@localhost zhanggen]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 261f12e2d6e4 centos "/bin/bash" About an hour ago Up 7 seconds mydocker d0dd5f7a79e8 centos "/bin/echo 'hellow I…" About an hour ago Exited (0) About an hour ago sharp_chandrasekhar
进如正在运行的容器看看
[root@localhost zhanggen]# docker attach mydocker
[root@261f12e2d6e4 /]#
删除所有容器
[root@localhost zhanggen]# docker rm -f e627d59e818c e627d59e818c [root@localhost zhanggen]# docker rm -f d0dd5f7a79e8 d0dd5f7a79e8 [root@localhost zhanggen]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost zhanggen]#
[root@localhost /]# docker rm $(docker ps -aq) eecdba33cb61 b2da31fc0100 06afb1402c3e [root@localhost /]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@localhost /]#
删除已经停止的容器和镜像
docker rm `docker ps -a|grep Exited|awk '{print $1}'` docker rmi `docker images | grep "none" | awk '{print $3}'`
3.进入正在运行中docker容器的2种最佳方式
查看正在运行容器的进程
[root@localhost zhanggen]# docker inspect -f "{{.State.Pid}}" mydocker 64721
通过进程ID反复进入docker容器
[root@localhost zhanggen]# nsenter -t 64721 -m -u -i -n -p -bash: __vte_prompt_command: command not found [root@261f12e2d6e4 /]#
为什么通过 nsenter -t 64721 -m -u -i -n -p 进入docker容器exit之后不退出?
其实就是多开了一个bash进程
[root@localhost zhanggen]# nsenter -t 64721 -m -u -i -n -p -bash: __vte_prompt_command: command not found [root@261f12e2d6e4 /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 08:43 pts/0 00:00:00 /bin/bash root 28 0 0 08:49 pts/0 00:00:00 -bash #其实就是多开了1个bash进程 root 42 28 0 08:52 pts/0 00:00:00 ps -ef -bash: __vte_prompt_command: command not found [root@261f12e2d6e4 /]# exit logout [root@localhost zhanggen]# nsenter -t 64721 -m -u -i -p -bash: __vte_prompt_command: command not found [root@261f12e2d6e4 /]#
docker exec 在不进入docker容器前提下 执行1个命令(一个程序)
root@localhost zhanggen]# docker exec mydocker whoami root [root@localhost zhanggen]# docker exec mydocker pwd / [root@localhost zhanggen]# docker exec mydocker ls anaconda-post.log bin dev etc
比如我们使用了某个镜像启动了docker容器,但是没有运行成功,需要额外安装一些依赖。
[root@VM-0-5-centos /]# docker run -d -p 8092:8099 -v /modManagerProject:/mingde --name ModManagerProject modelsystem:2.0 0ddfa1ad08f8b210df4f60da96d2c35ec78cdf4ddc55de66cd20a6eea7dc5110 [root@VM-0-5-centos /]# docker exec ModManagerProject pip install Flask-SQLAlchemy==2.5.1 [root@VM-0-5-centos /]# docker exec ModManagerProject pip install flask_cors [root@VM-0-5-centos /]# docker exec ModManagerProject ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:37 ? 00:00:00 /bin/sh -c sh /root/scripts/run.sh root 6 1 0 07:37 ? 00:00:00 sh /root/scripts/run.sh root 7 6 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 8 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 9 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 10 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 11 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 12 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 13 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 14 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 15 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 16 7 0 07:37 ? 00:00:00 uwsgi --ini /mingde/uwsgi/uwsgi.ini root 35 0 0 07:39 ? 00:00:00 ps -ef [root@VM-0-5-centos /]# docker exec ModManagerProject uwsgi --reload /mingde/uwsgi/uwsgi.ini [root@VM-0-5-centos /]# docker stop ModManagerProject ModManagerProject [root@VM-0-5-centos /]# docker start ModManagerProject ModManagerProject
通过dcker exec 打开bash程序之间进入docker容器
[root@localhost zhanggen]# docker exec -it mydocker /bin/bash [root@261f12e2d6e4 /]# exit exit [root@localhost zhanggen]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 9f38484d220f 6 days ago 202MB [root@localhost zhanggen]#
在宿主机后台运行docker容器
[root@localhost zhanggen]# docker run --name my_nginx -d nginx WARNING: IPv4 forwarding is disabled. Networking will not work. 3aafe4fe15248ec4cd526a1873b6fc1e50b9c87926f6504755ebd021f76f5d61 [root@localhost zhanggen]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3aafe4fe1524 nginx "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 80/tcp my_nginx [root@localhost zhanggen]#
4.DockerPortainer
Docker提供了图形化界面的方式来管理docker容器;
docker pull portainer/portainer
2.2 启动portainer
#创建文件存储文件 docker volume create portainer_data #创建并启动容器 --restart=always 开机自动启动` docker run -d -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
二、docker的网络访问
As a senior Web application developer,how to access it if I`ve I developed a Web application in docker container.
我在docker里面写了个Django程序,我怎么访问它的8001端口呢?这就需要给docker容器开通网络访问功能;
docker安装之后会自动创建一个 docker0的桥接网卡
[root@localhost zhanggen]# ifconfig docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:b4ff:fe4c:7745 prefixlen 64 scopeid 0x20<link> ether 02:42:b4:4c:77:45 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3 bytes 258 (258.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions
docker的网络就是通过docker0这个网桥进行 NAT 转换到docker容器的
配置centos7开启IPV4转发并重启网卡
net.ipv4.ip_forward=1
开启随机端口访问
[root@localhost zhanggen]# vim /usr/lib/sysctl.d/00-system.conf [root@localhost zhanggen]# docker run -d -P nginx 06afb1402c3eb177dbae8b72cd94be90c63713ce73a1bac7ab8f85ecdae50caa [root@localhost zhanggen]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 06afb1402c3e nginx "nginx -g 'daemon of…" 11 seconds ago Up 9 seconds 0.0.0.0:32769->80/tcp zen_hellman
指定端口进行访问
[root@localhost zhanggen]# docker run --name mydocker -d -p 8001:80 nginx b2da31fc010033f378e0930a2b77cec498ba6cbc1d288353562e3d0c6b23ae3c [root@localhost zhanggen]#
三、docker的数据管理
说到docker的数据管理,首先得清楚docker镜像的分层存储结构?
docker镜像是采用分层结构存储的,Docker镜像是只读、不可写的,docker容器在docker镜像之上是可写的,用户在docker容器的基础上操作之后commit 修改成只读镜像,盖了一层再来一层....
As I mentioned docker 采用的是一种开箱 既用-->用完--->即仍 的一次性理念,那么在docker运行中产生的一些日志..如何持久化?有一下两种方式;
1.数据卷
我们把宿主机中的一个目录mount 到docker容器的一个目录里面,docker容器运行中产生的数据写得宿主机的目录里;
[root@localhost zhanggen]# docker run -d --name nginx-volume -v /data nginx
70d688ad2c40e4490d05da0fa8bdbc0cc342315f1bbc61e7a63d4422832512c5
如果你想知道docker容器的 /data目录到底挂载到宿主机的哪个目录上了?
[root@localhost zhanggen]# docker run -d --name nginx-volume -v /data nginx 70d688ad2c40e4490d05da0fa8bdbc0cc342315f1bbc61e7a63d4422832512c5 [root@localhost zhanggen]# docker inspect -f {{.Mounts}} nginx-volume [{volume 4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data /data local true }] [root@localhost zhanggen]# ls Centos.tart Desktop Documents Downloads Music Pictures Public Templates Videos [root@localhost zhanggen]# cd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data [root@localhost _data]# pwd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data [root@localhost _data]# ls [root@localhost _data]#
root@localhost _data]# docker inspect -f {{.Mounts}} nginx-volume [{volume 4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data /data local true }] [root@localhost _data]# pwd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data [root@localhost _data]# touch 草你妈王X聪 [root@localhost _data]# docker exec -it nginx-volume /bin/bash root@70d688ad2c40:/# ls bin boot data dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@70d688ad2c40:/# cd d data/ dev/ root@70d688ad2c40:/# cd data/ root@70d688ad2c40:/data# ls FUCK_WANGSICHONGTAMA ?????????????????? root@70d688ad2c40:/data#
在生产环境我们一般会自己创建一个目录 在挂载到docker目录里
[root@localhost _data]# docker run -d --name nginx-volume -v /data/docker/volume-nginx/:/data nginx 09fc60548e01040805d6de92ace28062055a91eb832129b075e7e2605c149b45 [root@localhost _data]# docker exec -it nginx-volume /bin/bash root@09fc60548e01:/# ls bin boot data dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@09fc60548e01:/# cd data/ root@09fc60548e01:/data# ls root@09fc60548e01:/data# echo 'sss' > Martin.txt root@09fc60548e01:/data# ls Martin.txt root@09fc60548e01:/data# cat Martin.txt sss root@09fc60548e01:/data# exit exit [root@localhost _data]# pwd /var/lib/docker/volumes/4fbd49850452bcca0a867f09776f716b137c5f13f5a8b8a3a5e84e26496f9fcd/_data [root@localhost _data]# cd /data/docker/volume-nginx/ [root@localhost volume-nginx]# ls Martin.txt [root@localhost volume-nginx]# cat Martin.txt sss [root@localhost volume-nginx]#
2.数据卷容器
在容器是否运行、关闭的状态下,容器之间都可以共享容器卷数据;(NFS)
使用--volumes-from 指定要和哪个容器共享容器卷
[root@localhost volume-nginx]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 09fc60548e01 nginx "nginx -g 'daemon of…" 16 minutes ago Up 16 minutes 80/tcp nginx-volume [root@localhost volume-nginx]# docker run -it --name volume-test --volumes-from nginx-volume centos /bin/bash [root@c16407be0cf4 /]# ls data/ Martin.txt [root@c16407be0cf4 /]# exit exit [root@localhost volume-nginx]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 09fc60548e01 nginx "nginx -g 'daemon of…" 18 minutes ago Up 18 minutes 80/tcp nginx-volume [root@localhost volume-nginx]# docker exec -it nginx-volume /bin/bash root@09fc60548e01:/# ls data/ Martin.txt root@09fc60548e01:/#
生成环境:一般都会起 1个专门的容器挂载到宿主机的1个目录上,以后其他容器都 通过 --volumes-from 该容器 的形式来达到容器卷数据共享的效果;
四、docker镜像的构建
docker镜像是docker可以传播的介质,那么如何制作自己的docker镜像?分为如下2种方式:
手动构建
自己在容器里面做操作,操作完毕之后,commit成自己的镜像,
Dockerfile构建
以文件的形式执行力里面的命令进行快速构建,比较自动化化,相比容器较为轻量也更易于传播;
最后还会谈谈我在生产环境中使用dockerfile的经验。
1.手动创建镜像
docker run --name mynginx -it centos #使用基础镜像 centos 运行1个名为 mynginx 的容器
exit 退出容器
docker ps -a #查看刚刚exit的容器
docker commit -m 'MyNginx' cd35 zhanggen/mynginx:v1 #commit把停止的容器提交到本地分支
docker images #制作完成 docker run --name mynginxv1 -d -p 81:80 zhanggen/mynginx:v1 nginx #启动
PS:麻蛋发现自己制作的docker镜像启动不起来咋办?
查看容器启动的报错日志----》重新进入容器-----》检查操作,修改---》重新提交本地分支-----》重新启动
docker ps -a #查看启动失败的镜像ID docker logs container_id #查看报错日志 docker run -it zhanggen/mynginx:v1 /bin/bash #重新运行 该镜像进去修改 docker commit -m 'MyNginx' cd35 zhanggen/mynginx:v1 #修改完毕重新提交到本地分支 docker run --name mynginxv1 -d -p 81:80 zhanggen/mynginx:v1 nginx #重新启动镜像
2.Docker file构建
Docker file语法
OM centos MAINTAINER Martin.Zhang RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm RUN yum install -y nginx && yum clean all RUN echo "daemon off;" >> /etc/nginx/nginx.conf ADD index.html /usr/share/nginx/html/index.html EXPOSE 80 CMD ["nginx"]
<html> <body> <h1>ssssssssss!!!!</h1> </body> </html>
[root@localhost nginx]# pwd /dockerfile/nginx [root@localhost nginx]# ls Dockerfile index.html [root@localhost nginx]# docker build -t mynginx:v2 . Sending build context to Docker daemon 3.072kB Step 1/8 : FROM centos ---> 9f38484d220f Step 2/8 : MAINTAINER Martin.Zhang ---> Running in be6d86ffa2a9 Removing intermediate container be6d86ffa2a9 ---> 0dc16c8dadcc Step 3/8 : RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm ---> Running in 3ce6b480a0a2 warning: /var/tmp/rpm-tmp.qHH8Wh: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY Retrieving http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm Preparing... ######################################## Updating / installing... epel-release-7-11 ######################################## Removing intermediate container 3ce6b480a0a2 ---> 6b2b42a8e360 Step 4/8 : RUN yum install -y nginx && yum clean all ---> Running in 3e228aab6696 Loaded plugins: fastestmirror, ovl Determining fastest mirrors * base: mirrors.aliyun.com * epel: mirrors.aliyun.com * extras: mirrors.aliyun.com * updates: mirrors.aliyun.com Resolving Dependencies --> Running transaction check ---> Package nginx.x86_64 1:1.12.2-2.el7 will be installed --> Processing Dependency: nginx-all-modules = 1:1.12.2-2.el7 for package: 1:nginx-1.12.2-2.el7.x86_64 --> Processing Dependency: nginx-filesystem = 1:1.12.2-2.el7 for package: 1:nginx-1.12.2-2.el7.x86_64 --> Processing Dependency: nginx-filesystem for package: 1:nginx-1.12.2-2.el7.x86_64 --> Processing Dependency: openssl for package: 1:nginx-1.12.2-2.el7.x86_64 --> Processing Dependency: libprofiler.so.0()(64bit) for package: 1:nginx-1.12.2-2.el7.x86_64 --> Running transaction check ---> Package gperftools-libs.x86_64 0:2.6.1-1.el7 will be installed ---> Package nginx-all-modules.noarch 1:1.12.2-2.el7 will be installed --> Processing Dependency: nginx-mod-http-geoip = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch --> Processing Dependency: nginx-mod-http-image-filter = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch --> Processing Dependency: nginx-mod-http-perl = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch --> Processing Dependency: nginx-mod-http-xslt-filter = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch --> Processing Dependency: nginx-mod-mail = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch --> Processing Dependency: nginx-mod-stream = 1:1.12.2-2.el7 for package: 1:nginx-all-modules-1.12.2-2.el7.noarch ---> Package nginx-filesystem.noarch 1:1.12.2-2.el7 will be installed ---> Package openssl.x86_64 1:1.0.2k-16.el7_6.1 will be installed --> Processing Dependency: openssl-libs(x86-64) = 1:1.0.2k-16.el7_6.1 for package: 1:openssl-1.0.2k-16.el7_6.1.x86_64 --> Processing Dependency: make for package: 1:openssl-1.0.2k-16.el7_6.1.x86_64 --> Running transaction check ---> Package make.x86_64 1:3.82-23.el7 will be installed ---> Package nginx-mod-http-geoip.x86_64 1:1.12.2-2.el7 will be installed --> Processing Dependency: GeoIP for package: 1:nginx-mod-http-geoip-1.12.2-2.el7.x86_64 --> Processing Dependency: libGeoIP.so.1()(64bit) for package: 1:nginx-mod-http-geoip-1.12.2-2.el7.x86_64 ---> Package nginx-mod-http-image-filter.x86_64 1:1.12.2-2.el7 will be installed --> Processing Dependency: gd for package: 1:nginx-mod-http-image-filter-1.12.2-2.el7.x86_64 --> Processing Dependency: libgd.so.2()(64bit) for package: 1:nginx-mod-http-image-filter-1.12.2-2.el7.x86_64 ---> Package nginx-mod-http-perl.x86_64 1:1.12.2-2.el7 will be installed --> Processing Dependency: perl >= 5.006001 for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(:MODULE_COMPAT_5.16.3) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(Exporter) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(XSLoader) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(constant) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(strict) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: perl(warnings) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 --> Processing Dependency: libperl.so()(64bit) for package: 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 ---> Package nginx-mod-http-xslt-filter.x86_64 1:1.12.2-2.el7 will be installed --> Processing Dependency: libxslt.so.1(LIBXML2_1.0.11)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 --> Processing Dependency: libxslt.so.1(LIBXML2_1.0.18)(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 --> Processing Dependency: libexslt.so.0()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 --> Processing Dependency: libxslt.so.1()(64bit) for package: 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 ---> Package nginx-mod-mail.x86_64 1:1.12.2-2.el7 will be installed ---> Package nginx-mod-stream.x86_64 1:1.12.2-2.el7 will be installed ---> Package openssl-libs.x86_64 1:1.0.2k-16.el7 will be updated ---> Package openssl-libs.x86_64 1:1.0.2k-16.el7_6.1 will be an update --> Running transaction check ---> Package GeoIP.x86_64 0:1.5.0-13.el7 will be installed ---> Package gd.x86_64 0:2.0.35-26.el7 will be installed --> Processing Dependency: libpng15.so.15(PNG15_0)(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libjpeg.so.62(LIBJPEG_6.2)(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libpng15.so.15()(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libjpeg.so.62()(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libfreetype.so.6()(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libfontconfig.so.1()(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libXpm.so.4()(64bit) for package: gd-2.0.35-26.el7.x86_64 --> Processing Dependency: libX11.so.6()(64bit) for package: gd-2.0.35-26.el7.x86_64 ---> Package libxslt.x86_64 0:1.1.28-5.el7 will be installed ---> Package perl.x86_64 4:5.16.3-294.el7_6 will be installed --> Processing Dependency: perl(Socket) >= 1.3 for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Scalar::Util) >= 1.10 for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl-macros for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(threads::shared) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(threads) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Time::Local) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Time::HiRes) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Storable) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Socket) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Scalar::Util) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Pod::Simple::XHTML) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Pod::Simple::Search) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Getopt::Long) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Filter::Util::Call) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(File::Temp) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(File::Spec::Unix) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(File::Spec::Functions) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(File::Spec) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(File::Path) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Cwd) for package: 4:perl-5.16.3-294.el7_6.x86_64 --> Processing Dependency: perl(Carp) for package: 4:perl-5.16.3-294.el7_6.x86_64 ---> Package perl-Exporter.noarch 0:5.68-3.el7 will be installed ---> Package perl-constant.noarch 0:1.27-2.el7 will be installed ---> Package perl-libs.x86_64 4:5.16.3-294.el7_6 will be installed --> Running transaction check ---> Package fontconfig.x86_64 0:2.13.0-4.3.el7 will be installed --> Processing Dependency: fontpackages-filesystem for package: fontconfig-2.13.0-4.3.el7.x86_64 --> Processing Dependency: dejavu-sans-fonts for package: fontconfig-2.13.0-4.3.el7.x86_64 ---> Package freetype.x86_64 0:2.8-12.el7_6.1 will be installed ---> Package libX11.x86_64 0:1.6.5-2.el7 will be installed --> Processing Dependency: libX11-common >= 1.6.5-2.el7 for package: libX11-1.6.5-2.el7.x86_64 --> Processing Dependency: libxcb.so.1()(64bit) for package: libX11-1.6.5-2.el7.x86_64 ---> Package libXpm.x86_64 0:3.5.12-1.el7 will be installed ---> Package libjpeg-turbo.x86_64 0:1.2.90-6.el7 will be installed ---> Package libpng.x86_64 2:1.5.13-7.el7_2 will be installed ---> Package perl-Carp.noarch 0:1.26-244.el7 will be installed ---> Package perl-File-Path.noarch 0:2.09-2.el7 will be installed ---> Package perl-File-Temp.noarch 0:0.23.01-3.el7 will be installed ---> Package perl-Filter.x86_64 0:1.49-3.el7 will be installed ---> Package perl-Getopt-Long.noarch 0:2.40-3.el7 will be installed --> Processing Dependency: perl(Pod::Usage) >= 1.14 for package: perl-Getopt-Long-2.40-3.el7.noarch --> Processing Dependency: perl(Text::ParseWords) for package: perl-Getopt-Long-2.40-3.el7.noarch ---> Package perl-PathTools.x86_64 0:3.40-5.el7 will be installed ---> Package perl-Pod-Simple.noarch 1:3.28-4.el7 will be installed --> Processing Dependency: perl(Pod::Escapes) >= 1.04 for package: 1:perl-Pod-Simple-3.28-4.el7.noarch --> Processing Dependency: perl(Encode) for package: 1:perl-Pod-Simple-3.28-4.el7.noarch ---> Package perl-Scalar-List-Utils.x86_64 0:1.27-248.el7 will be installed ---> Package perl-Socket.x86_64 0:2.010-4.el7 will be installed ---> Package perl-Storable.x86_64 0:2.45-3.el7 will be installed ---> Package perl-Time-HiRes.x86_64 4:1.9725-3.el7 will be installed ---> Package perl-Time-Local.noarch 0:1.2300-2.el7 will be installed ---> Package perl-macros.x86_64 4:5.16.3-294.el7_6 will be installed ---> Package perl-threads.x86_64 0:1.87-4.el7 will be installed ---> Package perl-threads-shared.x86_64 0:1.43-6.el7 will be installed --> Running transaction check ---> Package dejavu-sans-fonts.noarch 0:2.33-6.el7 will be installed --> Processing Dependency: dejavu-fonts-common = 2.33-6.el7 for package: dejavu-sans-fonts-2.33-6.el7.noarch ---> Package fontpackages-filesystem.noarch 0:1.44-8.el7 will be installed ---> Package libX11-common.noarch 0:1.6.5-2.el7 will be installed ---> Package libxcb.x86_64 0:1.13-1.el7 will be installed --> Processing Dependency: libXau.so.6()(64bit) for package: libxcb-1.13-1.el7.x86_64 ---> Package perl-Encode.x86_64 0:2.51-7.el7 will be installed ---> Package perl-Pod-Escapes.noarch 1:1.04-294.el7_6 will be installed ---> Package perl-Pod-Usage.noarch 0:1.63-3.el7 will be installed --> Processing Dependency: perl(Pod::Text) >= 3.15 for package: perl-Pod-Usage-1.63-3.el7.noarch --> Processing Dependency: perl-Pod-Perldoc for package: perl-Pod-Usage-1.63-3.el7.noarch ---> Package perl-Text-ParseWords.noarch 0:3.29-4.el7 will be installed --> Running transaction check ---> Package dejavu-fonts-common.noarch 0:2.33-6.el7 will be installed ---> Package libXau.x86_64 0:1.0.8-2.1.el7 will be installed ---> Package perl-Pod-Perldoc.noarch 0:3.20-4.el7 will be installed --> Processing Dependency: perl(parent) for package: perl-Pod-Perldoc-3.20-4.el7.noarch --> Processing Dependency: perl(HTTP::Tiny) for package: perl-Pod-Perldoc-3.20-4.el7.noarch --> Processing Dependency: groff-base for package: perl-Pod-Perldoc-3.20-4.el7.noarch ---> Package perl-podlators.noarch 0:2.5.1-3.el7 will be installed --> Running transaction check ---> Package groff-base.x86_64 0:1.22.2-8.el7 will be installed ---> Package perl-HTTP-Tiny.noarch 0:0.033-3.el7 will be installed ---> Package perl-parent.noarch 1:0.225-244.el7 will be installed --> Finished Dependency Resolution Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: nginx x86_64 1:1.12.2-2.el7 epel 530 k Installing for dependencies: GeoIP x86_64 1.5.0-13.el7 base 1.5 M dejavu-fonts-common noarch 2.33-6.el7 base 64 k dejavu-sans-fonts noarch 2.33-6.el7 base 1.4 M fontconfig x86_64 2.13.0-4.3.el7 base 254 k fontpackages-filesystem noarch 1.44-8.el7 base 9.9 k freetype x86_64 2.8-12.el7_6.1 updates 380 k gd x86_64 2.0.35-26.el7 base 146 k gperftools-libs x86_64 2.6.1-1.el7 base 272 k groff-base x86_64 1.22.2-8.el7 base 942 k libX11 x86_64 1.6.5-2.el7 base 606 k libX11-common noarch 1.6.5-2.el7 base 164 k libXau x86_64 1.0.8-2.1.el7 base 29 k libXpm x86_64 3.5.12-1.el7 base 55 k libjpeg-turbo x86_64 1.2.90-6.el7 base 134 k libpng x86_64 2:1.5.13-7.el7_2 base 213 k libxcb x86_64 1.13-1.el7 base 214 k libxslt x86_64 1.1.28-5.el7 base 242 k make x86_64 1:3.82-23.el7 base 420 k nginx-all-modules noarch 1:1.12.2-2.el7 epel 16 k nginx-filesystem noarch 1:1.12.2-2.el7 epel 17 k nginx-mod-http-geoip x86_64 1:1.12.2-2.el7 epel 23 k nginx-mod-http-image-filter x86_64 1:1.12.2-2.el7 epel 26 k nginx-mod-http-perl x86_64 1:1.12.2-2.el7 epel 36 k nginx-mod-http-xslt-filter x86_64 1:1.12.2-2.el7 epel 26 k nginx-mod-mail x86_64 1:1.12.2-2.el7 epel 54 k nginx-mod-stream x86_64 1:1.12.2-2.el7 epel 76 k openssl x86_64 1:1.0.2k-16.el7_6.1 updates 493 k perl x86_64 4:5.16.3-294.el7_6 updates 8.0 M perl-Carp noarch 1.26-244.el7 base 19 k perl-Encode x86_64 2.51-7.el7 base 1.5 M perl-Exporter noarch 5.68-3.el7 base 28 k perl-File-Path noarch 2.09-2.el7 base 26 k perl-File-Temp noarch 0.23.01-3.el7 base 56 k perl-Filter x86_64 1.49-3.el7 base 76 k perl-Getopt-Long noarch 2.40-3.el7 base 56 k perl-HTTP-Tiny noarch 0.033-3.el7 base 38 k perl-PathTools x86_64 3.40-5.el7 base 82 k perl-Pod-Escapes noarch 1:1.04-294.el7_6 updates 51 k perl-Pod-Perldoc noarch 3.20-4.el7 base 87 k perl-Pod-Simple noarch 1:3.28-4.el7 base 216 k perl-Pod-Usage noarch 1.63-3.el7 base 27 k perl-Scalar-List-Utils x86_64 1.27-248.el7 base 36 k perl-Socket x86_64 2.010-4.el7 base 49 k perl-Storable x86_64 2.45-3.el7 base 77 k perl-Text-ParseWords noarch 3.29-4.el7 base 14 k perl-Time-HiRes x86_64 4:1.9725-3.el7 base 45 k perl-Time-Local noarch 1.2300-2.el7 base 24 k perl-constant noarch 1.27-2.el7 base 19 k perl-libs x86_64 4:5.16.3-294.el7_6 updates 688 k perl-macros x86_64 4:5.16.3-294.el7_6 updates 44 k perl-parent noarch 1:0.225-244.el7 base 12 k perl-podlators noarch 2.5.1-3.el7 base 112 k perl-threads x86_64 1.87-4.el7 base 49 k perl-threads-shared x86_64 1.43-6.el7 base 39 k Updating for dependencies: openssl-libs x86_64 1:1.0.2k-16.el7_6.1 updates 1.2 M Transaction Summary ================================================================================ Install 1 Package (+54 Dependent packages) Upgrade ( 1 Dependent package) Total download size: 21 M Downloading packages: Delta RPMs disabled because /usr/bin/applydeltarpm not installed. warning: /var/cache/yum/x86_64/7/base/packages/fontpackages-filesystem-1.44-8.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY Public key for fontpackages-filesystem-1.44-8.el7.noarch.rpm is not installed Public key for freetype-2.8-12.el7_6.1.x86_64.rpm is not installed warning: /var/cache/yum/x86_64/7/epel/packages/nginx-all-modules-1.12.2-2.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY Public key for nginx-all-modules-1.12.2-2.el7.noarch.rpm is not installed -------------------------------------------------------------------------------- Total 608 kB/s | 21 MB 00:35 Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 Importing GPG key 0xF4A80EB5: Userid : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>" Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5 Package : centos-release-7-6.1810.2.el7.centos.x86_64 (@CentOS) From : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 Importing GPG key 0x352C64E5: Userid : "Fedora EPEL (7) <epel@fedoraproject.org>" Fingerprint: 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5 Package : epel-release-7-11.noarch (installed) From : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 Running transaction check Running transaction test Transaction test succeeded Running transaction Warning: RPMDB altered outside of yum. Updating : 1:openssl-libs-1.0.2k-16.el7_6.1.x86_64 1/57 Installing : fontpackages-filesystem-1.44-8.el7.noarch 2/57 Installing : 2:libpng-1.5.13-7.el7_2.x86_64 3/57 Installing : freetype-2.8-12.el7_6.1.x86_64 4/57 Installing : dejavu-fonts-common-2.33-6.el7.noarch 5/57 Installing : dejavu-sans-fonts-2.33-6.el7.noarch 6/57 Installing : fontconfig-2.13.0-4.3.el7.x86_64 7/57 Installing : 1:make-3.82-23.el7.x86_64 8/57 Installing : 1:openssl-1.0.2k-16.el7_6.1.x86_64 9/57 Installing : libX11-common-1.6.5-2.el7.noarch 10/57 Installing : gperftools-libs-2.6.1-1.el7.x86_64 11/57 Installing : libXau-1.0.8-2.1.el7.x86_64 12/57 Installing : libxcb-1.13-1.el7.x86_64 13/57 Installing : libX11-1.6.5-2.el7.x86_64 14/57 Installing : libXpm-3.5.12-1.el7.x86_64 15/57 Installing : libxslt-1.1.28-5.el7.x86_64 16/57 Installing : 1:nginx-filesystem-1.12.2-2.el7.noarch 17/57 Installing : GeoIP-1.5.0-13.el7.x86_64 18/57 Installing : libjpeg-turbo-1.2.90-6.el7.x86_64 19/57 Installing : gd-2.0.35-26.el7.x86_64 20/57 Installing : groff-base-1.22.2-8.el7.x86_64 21/57 Installing : 1:perl-parent-0.225-244.el7.noarch 22/57 Installing : perl-HTTP-Tiny-0.033-3.el7.noarch 23/57 Installing : perl-podlators-2.5.1-3.el7.noarch 24/57 Installing : perl-Pod-Perldoc-3.20-4.el7.noarch 25/57 Installing : perl-Encode-2.51-7.el7.x86_64 26/57 Installing : perl-Text-ParseWords-3.29-4.el7.noarch 27/57 Installing : 1:perl-Pod-Escapes-1.04-294.el7_6.noarch 28/57 Installing : perl-Pod-Usage-1.63-3.el7.noarch 29/57 Installing : 4:perl-libs-5.16.3-294.el7_6.x86_64 30/57 Installing : 4:perl-macros-5.16.3-294.el7_6.x86_64 31/57 Installing : 4:perl-Time-HiRes-1.9725-3.el7.x86_64 32/57 Installing : perl-Exporter-5.68-3.el7.noarch 33/57 Installing : perl-constant-1.27-2.el7.noarch 34/57 Installing : perl-Time-Local-1.2300-2.el7.noarch 35/57 Installing : perl-Carp-1.26-244.el7.noarch 36/57 Installing : perl-Storable-2.45-3.el7.x86_64 37/57 Installing : perl-PathTools-3.40-5.el7.x86_64 38/57 Installing : perl-Scalar-List-Utils-1.27-248.el7.x86_64 39/57 Installing : 1:perl-Pod-Simple-3.28-4.el7.noarch 40/57 Installing : perl-File-Temp-0.23.01-3.el7.noarch 41/57 Installing : perl-File-Path-2.09-2.el7.noarch 42/57 Installing : perl-threads-shared-1.43-6.el7.x86_64 43/57 Installing : perl-threads-1.87-4.el7.x86_64 44/57 Installing : perl-Filter-1.49-3.el7.x86_64 45/57 Installing : perl-Socket-2.010-4.el7.x86_64 46/57 Installing : perl-Getopt-Long-2.40-3.el7.noarch 47/57 Installing : 4:perl-5.16.3-294.el7_6.x86_64 48/57 Installing : 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 49/57 Installing : 1:nginx-mod-http-geoip-1.12.2-2.el7.x86_64 50/57 Installing : 1:nginx-mod-stream-1.12.2-2.el7.x86_64 51/57 Installing : 1:nginx-mod-mail-1.12.2-2.el7.x86_64 52/57 Installing : 1:nginx-mod-http-image-filter-1.12.2-2.el7.x86_64 53/57 Installing : 1:nginx-1.12.2-2.el7.x86_64 54/57 Installing : 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 55/57 Installing : 1:nginx-all-modules-1.12.2-2.el7.noarch 56/57 Cleanup : 1:openssl-libs-1.0.2k-16.el7.x86_64 57/57 Verifying : perl-HTTP-Tiny-0.033-3.el7.noarch 1/57 Verifying : fontconfig-2.13.0-4.3.el7.x86_64 2/57 Verifying : 1:nginx-mod-http-xslt-filter-1.12.2-2.el7.x86_64 3/57 Verifying : perl-threads-shared-1.43-6.el7.x86_64 4/57 Verifying : 4:perl-Time-HiRes-1.9725-3.el7.x86_64 5/57 Verifying : 1:nginx-mod-http-geoip-1.12.2-2.el7.x86_64 6/57 Verifying : groff-base-1.22.2-8.el7.x86_64 7/57 Verifying : perl-Exporter-5.68-3.el7.noarch 8/57 Verifying : perl-constant-1.27-2.el7.noarch 9/57 Verifying : perl-PathTools-3.40-5.el7.x86_64 10/57 Verifying : 2:libpng-1.5.13-7.el7_2.x86_64 11/57 Verifying : dejavu-fonts-common-2.33-6.el7.noarch 12/57 Verifying : fontpackages-filesystem-1.44-8.el7.noarch 13/57 Verifying : 1:nginx-mod-stream-1.12.2-2.el7.x86_64 14/57 Verifying : libjpeg-turbo-1.2.90-6.el7.x86_64 15/57 Verifying : 1:perl-parent-0.225-244.el7.noarch 16/57 Verifying : GeoIP-1.5.0-13.el7.x86_64 17/57 Verifying : 4:perl-libs-5.16.3-294.el7_6.x86_64 18/57 Verifying : perl-Encode-2.51-7.el7.x86_64 19/57 Verifying : perl-File-Temp-0.23.01-3.el7.noarch 20/57 Verifying : 1:perl-Pod-Simple-3.28-4.el7.noarch 21/57 Verifying : perl-Getopt-Long-2.40-3.el7.noarch 22/57 Verifying : 1:nginx-all-modules-1.12.2-2.el7.noarch 23/57 Verifying : libxcb-1.13-1.el7.x86_64 24/57 Verifying : perl-Time-Local-1.2300-2.el7.noarch 25/57 Verifying : 4:perl-macros-5.16.3-294.el7_6.x86_64 26/57 Verifying : 4:perl-5.16.3-294.el7_6.x86_64 27/57 Verifying : libXpm-3.5.12-1.el7.x86_64 28/57 Verifying : perl-Text-ParseWords-3.29-4.el7.noarch 29/57 Verifying : 1:openssl-1.0.2k-16.el7_6.1.x86_64 30/57 Verifying : 1:nginx-filesystem-1.12.2-2.el7.noarch 31/57 Verifying : perl-Carp-1.26-244.el7.noarch 32/57 Verifying : libxslt-1.1.28-5.el7.x86_64 33/57 Verifying : libX11-1.6.5-2.el7.x86_64 34/57 Verifying : perl-Storable-2.45-3.el7.x86_64 35/57 Verifying : dejavu-sans-fonts-2.33-6.el7.noarch 36/57 Verifying : 1:nginx-mod-mail-1.12.2-2.el7.x86_64 37/57 Verifying : perl-Scalar-List-Utils-1.27-248.el7.x86_64 38/57 Verifying : gd-2.0.35-26.el7.x86_64 39/57 Verifying : 1:perl-Pod-Escapes-1.04-294.el7_6.noarch 40/57 Verifying : 1:nginx-mod-http-image-filter-1.12.2-2.el7.x86_64 41/57 Verifying : perl-Pod-Usage-1.63-3.el7.noarch 42/57 Verifying : 1:openssl-libs-1.0.2k-16.el7_6.1.x86_64 43/57 Verifying : 1:nginx-1.12.2-2.el7.x86_64 44/57 Verifying : perl-Pod-Perldoc-3.20-4.el7.noarch 45/57 Verifying : perl-podlators-2.5.1-3.el7.noarch 46/57 Verifying : libXau-1.0.8-2.1.el7.x86_64 47/57 Verifying : perl-File-Path-2.09-2.el7.noarch 48/57 Verifying : perl-threads-1.87-4.el7.x86_64 49/57 Verifying : gperftools-libs-2.6.1-1.el7.x86_64 50/57 Verifying : libX11-common-1.6.5-2.el7.noarch 51/57 Verifying : perl-Filter-1.49-3.el7.x86_64 52/57 Verifying : freetype-2.8-12.el7_6.1.x86_64 53/57 Verifying : 1:nginx-mod-http-perl-1.12.2-2.el7.x86_64 54/57 Verifying : perl-Socket-2.010-4.el7.x86_64 55/57 Verifying : 1:make-3.82-23.el7.x86_64 56/57 Verifying : 1:openssl-libs-1.0.2k-16.el7.x86_64 57/57 Installed: nginx.x86_64 1:1.12.2-2.el7 Dependency Installed: GeoIP.x86_64 0:1.5.0-13.el7 dejavu-fonts-common.noarch 0:2.33-6.el7 dejavu-sans-fonts.noarch 0:2.33-6.el7 fontconfig.x86_64 0:2.13.0-4.3.el7 fontpackages-filesystem.noarch 0:1.44-8.el7 freetype.x86_64 0:2.8-12.el7_6.1 gd.x86_64 0:2.0.35-26.el7 gperftools-libs.x86_64 0:2.6.1-1.el7 groff-base.x86_64 0:1.22.2-8.el7 libX11.x86_64 0:1.6.5-2.el7 libX11-common.noarch 0:1.6.5-2.el7 libXau.x86_64 0:1.0.8-2.1.el7 libXpm.x86_64 0:3.5.12-1.el7 libjpeg-turbo.x86_64 0:1.2.90-6.el7 libpng.x86_64 2:1.5.13-7.el7_2 libxcb.x86_64 0:1.13-1.el7 libxslt.x86_64 0:1.1.28-5.el7 make.x86_64 1:3.82-23.el7 nginx-all-modules.noarch 1:1.12.2-2.el7 nginx-filesystem.noarch 1:1.12.2-2.el7 nginx-mod-http-geoip.x86_64 1:1.12.2-2.el7 nginx-mod-http-image-filter.x86_64 1:1.12.2-2.el7 nginx-mod-http-perl.x86_64 1:1.12.2-2.el7 nginx-mod-http-xslt-filter.x86_64 1:1.12.2-2.el7 nginx-mod-mail.x86_64 1:1.12.2-2.el7 nginx-mod-stream.x86_64 1:1.12.2-2.el7 openssl.x86_64 1:1.0.2k-16.el7_6.1 perl.x86_64 4:5.16.3-294.el7_6 perl-Carp.noarch 0:1.26-244.el7 perl-Encode.x86_64 0:2.51-7.el7 perl-Exporter.noarch 0:5.68-3.el7 perl-File-Path.noarch 0:2.09-2.el7 perl-File-Temp.noarch 0:0.23.01-3.el7 perl-Filter.x86_64 0:1.49-3.el7 perl-Getopt-Long.noarch 0:2.40-3.el7 perl-HTTP-Tiny.noarch 0:0.033-3.el7 perl-PathTools.x86_64 0:3.40-5.el7 perl-Pod-Escapes.noarch 1:1.04-294.el7_6 perl-Pod-Perldoc.noarch 0:3.20-4.el7 perl-Pod-Simple.noarch 1:3.28-4.el7 perl-Pod-Usage.noarch 0:1.63-3.el7 perl-Scalar-List-Utils.x86_64 0:1.27-248.el7 perl-Socket.x86_64 0:2.010-4.el7 perl-Storable.x86_64 0:2.45-3.el7 perl-Text-ParseWords.noarch 0:3.29-4.el7 perl-Time-HiRes.x86_64 4:1.9725-3.el7 perl-Time-Local.noarch 0:1.2300-2.el7 perl-constant.noarch 0:1.27-2.el7 perl-libs.x86_64 4:5.16.3-294.el7_6 perl-macros.x86_64 4:5.16.3-294.el7_6 perl-parent.noarch 1:0.225-244.el7 perl-podlators.noarch 0:2.5.1-3.el7 perl-threads.x86_64 0:1.87-4.el7 perl-threads-shared.x86_64 0:1.43-6.el7 Dependency Updated: openssl-libs.x86_64 1:1.0.2k-16.el7_6.1 Complete! Loaded plugins: fastestmirror, ovl Cleaning repos: base epel extras updates Cleaning up list of fastest mirrors Removing intermediate container 3e228aab6696 ---> d31beb8cce1e Step 5/8 : RUN echo "daemon off;" >> /etc/nginx/nginx.conf ---> Running in e2770ee72af0 Removing intermediate container e2770ee72af0 ---> 56382e656884 Step 6/8 : ADD index.html /usr/share/nginx/html/index.html ---> 9a268246ca18 Step 7/8 : EXPOSE 80 ---> Running in 92412b2bb046 Removing intermediate container 92412b2bb046 ---> 05ce68ba1519 Step 8/8 : CMD ["nginx"] ---> Running in fa9037b49675 Removing intermediate container fa9037b49675 ---> 5aee9f4c1ada Successfully built 5aee9f4c1ada Successfully tagged mynginx:v2 [root@localhost nginx]# docker image Usage: docker image COMMAND Manage images Commands: 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 Run 'docker image COMMAND --help' for more information on a command. [root@localhost nginx]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx v2 5aee9f4c1ada 14 seconds ago 307MB centos latest 9f38484d220f 10 days ago 202MB nginx latest 881bd08c0b08 2 weeks ago 109MB [root@localhost nginx]#
启动镜像
[root@localhost nginx]# cat index.html <html> <body> <h1>首页!!!!</h1> </body> </html> [root@localhost nginx]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mynginx v2 5aee9f4c1ada 4 minutes ago 307MB centos latest 9f38484d220f 10 days ago 202MB nginx latest 881bd08c0b08 2 weeks ago 109MB [root@localhost nginx]# docker run --name mynginxv2 -d -p 81:80 mynginx:v2 nginx 8e269403c1b4181dd187eb20c74eb465f5f165ce0bfbc9b444d57164b1621e24 [root@localhost nginx]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8e269403c1b4 mynginx:v2 "nginx" 4 seconds ago Up 3 seconds 0.0.0.0:81->80/tcp mynginxv2 [root@localhost nginx]# ip a s 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:86:32:27 brd ff:ff:ff:ff:ff:ff inet 192.168.226.159/24 brd 192.168.226.255 scope global dynamic ens33 valid_lft 1636sec preferred_lft 1636sec inet6 fe80::6f1c:2b48:af8b:a03a/64 scope link valid_lft forever preferred_lft forever 3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000 link/ether 52:54:00:31:bf:a8 brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 valid_lft forever preferred_lft forever 4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 1000 link/ether 52:54:00:31:bf:a8 brd ff:ff:ff:ff:ff:ff 5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP link/ether 02:42:b4:4c:77:45 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:b4ff:fe4c:7745/64 scope link valid_lft forever preferred_lft forever 79: veth3778ee4@if78: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP link/ether d2:b8:51:47:0d:1d brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::d0b8:51ff:fe47:d1d/64 scope link valid_lft forever preferred_lft forever [root@localhost nginx]# curl 192.168.226.159:81 <html> <body> <h1>首页!!!!</h1> </body> </html> [root@localhost nginx]# docker run --name mynginxv2 -d -p 81:80 mynginx:v2 nginx
构建Uwsgi+Python开发环境
FROM python:3.7.6 AS pure_python_env MAINTAINER franplk LABEL version=1.0 description=HunanModelSystem FROM pure_python_env AS python_site_package WORKDIR /root COPY requirements.txt requirements.txt RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple FROM python_site_package AS uwsgi_builder WORKDIR /root COPY uwsgi/uwsgi-2.0.19.1 uwsgi-2.0.19.1 RUN mv uwsgi-2.0.19.1 uwsgi WORKDIR /root/uwsgi RUN make && ln -s /root/uwsgi/uwsgi /usr/bin/uwsgi EXPOSE 8099 WORKDIR /root CMD uwsgi --ini /${PROJECT_NAME}/devops/docker/uwsgi/uwsgi.ini
CMD执行
CMD用来设置docker run 容器启动之后,执行的命令。它通常是在操作系统前台启动1个进程。
注意一定要保证docker容器内有1个前台进行一直运行,否则容器会马上退出。Dockerfile中启动服务不需要nohup。
#!/bin/bash #load variables from uwsgi.ini projectConfig=$(grep ^chdir= /root/uwsgi.ini) projectPath=$(echo | awk '{split("'${projectConfig}'", array, "=");print array[2]}') projectName=$(echo | awk '{split("'${projectPath}'", array, "/");print array[5]}') #Create a directory to store cureent project cd /usr/src/app/ mv /root/code/${projectName} /usr/src/app/ echo $projectName is being started by Docker. #Launch the project with python #cd $projectPath #python manager.py #Launch the project with uwsgi uwsgi --ini /root/uwsgi.ini
uwsgi配置文件
wsgi] master=true processes=8 http=0.0.0.0:8099 module=manager callable=app buffer-size=65535 chmod-socket=777 logfile-chmod=644 # 源码目录 chdir=/usr/src/app/HunanModel/code # python 虚拟环境 socket=/root/app/uwsgi.sock pidfile=/root/app/uwsgi.pid #如果在docker容纳其里,一定让uwsgi在前台启动 #daemonize=/root/app/uwsgi.log
build镜像
./docker/docker build -t modelsystem:2.0 .
run容器
[root@localhost mingde]# ./docker/docker run -d -p 8099:8099 --name modelsystem -e PROJECT="HunanModel" modelsystem:2.0 06f162a4301f3174a0a655428e2cbd0c973920190de4bb21e951540121886f04 [root@localhost mingde]# ./docker/docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 06f162a4301f modelsystem:2.0 "/bin/sh -c 'sh /r..." 7 seconds ago Up 7 seconds 0.0.0.0:8099->8099/tcp modelsystem [root@localhost mingde]#
让docker容器中的目录挂载到宿主机目录,可以让dockerFile制作的镜像显地更加通用。
也就是说我的docker容器中只是打包了Python环境,而这个Python环境,需要运行的Python代码却是可以随时更的。
[root@localhost mingde]# ./docker/docker run -d -p 8099:8099 -v /mingde:/mingde --name modelsystem modelsystem:2.0
五、docker file生产实践
docker file go live
1.目录环境准备
[root@localhost docker_image]# ls apps runtime system [root@localhost docker_image]# tree . ├── apps │ └── work_order_api ├── runtime │ ├── java │ ├── php │ └── python └── system ├── centos └── centos-ssh
在架构设计里面有个分层设计的理念,我们也可把生产环境分为:系统层、运行环境层、业务层,这也符合docker镜像分层思想;
Linux系统: centos、Ubuntu....
运行环境: Java 、Python 、PHP.....
App:API、WebAPP、BackGroundManagement ...
Docker file最大的亮点在于FROM,有了它就可以基于不同的镜像,衍生出多种镜像,就和搭积木类似,分好层 可以灵活组装就好。
2.系统环境层docker file (centos7)
下载epel.repo源文件
[root@localhost centos]# pwd /docker_image/system/centos [root@localhost centos]# wget -O ./epel.repo http://mirrors.aliyun.com/repo/epel-7.repo --2019-03-26 09:34:20-- http://mirrors.aliyun.com/repo/epel-7.repo Resolving mirrors.aliyun.com (mirrors.aliyun.com)... 175.6.29.211, 175.6.29.218, 175.6.29.213, ... Connecting to mirrors.aliyun.com (mirrors.aliyun.com)|175.6.29.211|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 664 [application/octet-stream] Saving to: ‘./epel.repo’ 100%[==================================================================================================>] 664 --.-K/s in 0s 2019-03-26 09:34:20 (138 MB/s) - ‘./epel.repo’ saved [664/664] [root@localhost centos]# ls epel.repo
FROM centos MAINTAINER zhanggen ADD epel.repo /etc/yum.repos.d/ run yum install -y wget mysql-devel supervisor git redis tree net-toos sudo psmisc && yum clean all
[root@localhost centos]# ls Dockerfile epel.repo [root@localhost centos]# docker build -t zhanggen/centos:v1 .
3.开发环境层docker file (Python3.6.1)
[root@localhost python]# pwd /docker_image/runtime/python [root@localhost python]# ls Dockerfile Python-3.6.1.tgz [root@localhost python]#
FROM zhanggen/centos:v1 MAINTAINER Gen.Zhang RUN yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel gcc automake autoconf libtool make db4-devel libpcap-devel xz-devel RUN yum clean all ADD Python-3.6.1.tgz /python_packages/ RUN mkdir -p /zhanggen/python3.6.1 RUN cd /python_packages/Python-3.6.1 && ./configure --prefix=/zhanggen/python3.6.1 && make && make install RUN echo -e "PATH=$PATH:$HOME/bin:/zhanggen/python3.6.1/bin \n export PATH" > /etc/profile.d/python3.6.1.sh && source /etc/profile.d/python3.6.1.sh
构建python开发环境镜像
[root@localhost runtime]# cd python/ [root@localhost python]# ls Dockerfile Python-3.6.1.tgz [root@localhost python]# docker build -t zhanggen/python3.6.1:v1 . Sending build context to Docker daemon 22.54MB Step 1/8 : FROM zhanggen/centos:v1 ---> 9c10a3b17a66 Step 2/8 : MAINTAINER Gen.Zhang ---> Using cache ---> 4c630636d1f9 Step 3/8 : RUN yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel gcc automake autoconf libtool make db4-devel libpcap-devel xz-devel ---> Using cache ---> ff12b7d7dbd3 Step 4/8 : RUN yum clean all ---> Using cache ---> 32c615445b0a Step 5/8 : ADD Python-3.6.1.tgz /python_packages/ ---> Using cache ---> ac70242e584b Step 6/8 : RUN mkdir -p /zhanggen/python3.6.1 ---> Using cache ---> 426627a6cb1f Step 7/8 : RUN cd /python_packages/Python-3.6.1 && ./configure --prefix=/zhanggen/python3.6.1 && make && make install ---> Using cache ---> d15daa242a06 Step 8/8 : RUN echo -e "PATH=$PATH:$HOME/bin:/zhanggen/python3.6.1/bin \n export PATH" > /etc/profile.d/python3.6.1.sh && source /etc/profile.d/python3.6.1.sh ---> Using cache ---> 20e32f2fde08 Successfully built 20e32f2fde08 Successfully tagged zhanggen/python3.6.1:v1 [root@localhost python]# docker build -t zhanggen/python3.6.1:v1 . Sending build context to Docker daemon 22.54MB Step 1/8 : FROM zhanggen/centos:v1 ---> 9c10a3b17a66 Step 2/8 : MAINTAINER Gen.Zhang ---> Using cache ---> 4c630636d1f9 Step 3/8 : RUN yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel gcc automake autoconf libtool make db4-devel libpcap-devel xz-devel ---> Using cache ---> ff12b7d7dbd3 Step 4/8 : RUN yum clean all ---> Using cache ---> 32c615445b0a Step 5/8 : ADD Python-3.6.1.tgz /python_packages/ ---> Using cache ---> ac70242e584b Step 6/8 : RUN mkdir -p /zhanggen/python3.6.1 ---> Using cache ---> 426627a6cb1f Step 7/8 : RUN cd /python_packages/Python-3.6.1 && ./configure --prefix=/zhanggen/python3.6.1 && make && make install ---> Using cache ---> d15daa242a06 Step 8/8 : RUN echo -e "PATH=$PATH:$HOME/bin:/zhanggen/python3.6.1/bin \n export PATH" > /etc/profile.d/python3.6.1.sh && source /etc/profile.d/python3.6.1.sh ---> Using cache ---> 20e32f2fde08 Successfully built 20e32f2fde08 Successfully tagged zhanggen/python3.6.1:v1 [root@localhost python]# pwd /docker_image/runtime/python
4.APP层 docker file(Django web app)
Docker容器只允许在前台 运行1个进程,我们如何破解?
Supervisor是Python开发的进程管理工具,可以同时开启、重启、关闭多个进程,可以启动1个Supervisor进程使用Supercisor启动、管理N个进程;
我发现Supervisor不仅可以统一管理进程,还可以规范进程的日志路径,规范了日志路径之后,就可以很方便得找得这些日志,进行数据分析;
[root@localhost web_application]# pwd /docker_image/apps/web_application [root@localhost web_application]# ls django_app Dockerfile requirements.txt supervisord.conf supervisor.ini [root@localhost web_application]#
构建web app镜像所需要的文件
APP项目---自己写
ADD django_app/ /root/django_app/ ADD requirements.txt /root/django_app/ ADD supervisord.conf /etc/supervisord.conf ADD supervisor.ini /etc/supervisord.d/ RUN /zhanggen/python3.6.1/bin/pip3 install -r /root/django_app/requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.com EXPOSE 22 8008 CMD ["/usr/bin/supervisord","-c","/etc/supervisord.conf"]
Django==1.11.4
nodaemon=true ; (start in foreground if true;default false)
配置supervisor需要启动的启动的 程序
ps:一定记得让supervisord进程 在前台运行(修改配置中件 nodaemon=true)
[program:django_project] command=/zhanggen/python3.6.1/bin/python3 /root/django_app/manage.py runserver 0.0.0.0:8008 process_name=%(program_name)s autostart=true user=root stdout_logfile=/tmp/app.log stderr_logfile=/tmp/app.error [program:sshd] command=/usr/sbin/sshd -D process_name=%(program_name)s autostart=true user=root stdout_logfile=/tmp/sshd.log stderr_logfile=/tmp/sshd.error
构建 web app镜像
Successfully built 73fbd9076308 Successfully tagged zhanggen/django_app:v1 [root@localhost web_application]# pwd /docker_image/apps/web_application [root@localhost web_application]# docker build -t zhanggen/django_app:v1 .
启动web app
[root@localhost web_application]# docker run --name my_django_app -d -p 8008:8008 -p 8022:22 zhanggen/django_app:v1 185c311d6a951e33fa01d64a332127cf9ad6d45b0ee60d018ab25be68c0a86bf [root@localhost web_application]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 185c311d6a95 zhanggen/django_app:v1 "/usr/bin/supervisor…" 7 seconds ago Up 5 seconds 0.0.0.0:8008->8008/tcp, 0.0.0.0:8022->22/tcp my_django_app [root@localhost web_application]#
最后的最后
[root@localhost web_application]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE zhanggen/django_app v1 a25dd5479dd9 8 minutes ago 905MB zhanggen/python3.6.1 v1 20e32f2fde08 19 hours ago 882MB zhanggen/centos v1 9c10a3b17a66 20 hours ago 300MB [root@localhost web_application]# docker run --name my_django_app -d -p 8008:8008 -p 8022:22 zhanggen/django_app:v1
5.Dockerfile中cmd和entrypoint指令联系和区别
每1个Dockerfile只能生效1条CMD指令。如果指定了多条CMD指令,只有最后1条生效。
如果用户启动容器(docker run image)时候指定了运行的命令,则会覆盖掉CMD指定的命令。
每1个Dockerfile中只能生效一个ENTRYPOINT指令,当有多个ENTRYPOINT指令时,只有最后1条生效。
如果用户启动容器(docker run image)时指定了运行的命令,不会被docker run输入
的命令参数覆盖。(追加效果:docker run
命令之后的参数,会被当做参数传递给ENTRYPOINT,之后形成新的命令组合)
六、Docker仓库(Docker Registry)
docker镜像做好了,这些镜像怎么分享给其他同事,其他同事的镜像 How to share with me?
于是私有Docker Hub-----Harbor闪亮登场了!
我们可以把这些镜像 push / pull 到Docker仓库里面,通过Docker仓库 使镜像 得以分享、传播;
1.Harbor私有仓库搭建
2.Docker 添加--insecure-registry信任关系
ExecStart=/usr/bin/dockerd --insecure-registry=192.168.226.159:80
3.首次使用Harbor需要先登录做一下认证 (Authenticating)
[root@localhost /]# docker login 192.168.226.159:80 Authenticating with existing credentials... WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
4.在提交到Harbor之前 要先对本地镜像进行 docker tag
[root@localhost /]# docker tag 192.168.226.159/zhanggen/django_app:v1 192.168.226.159:80/zhanggen/django_app:v1 [root@localhost /]# docker push 192.168.226.159:80/zhanggen/django_app:v1 The push refers to repository [192.168.226.159:80/zhanggen/django_app] 1adfc5932576: Pushed f35015fe99dc: Pushed 130d88c10146: Pushed af1537967ae6: Pushed 8bc7239a5750: Pushed 4044728999b8: Pushed 7393a01b80a0: Pushed 8682a21900da: Pushed 4b12cdc82a32: Pushed 325cddbb1805: Pushed 5e3f3498e333: Pushed 9b0549f1a2e2: Pushed 5d14ce4c4502: Pushed d7180aa9852e: Pushed d69483a6face: Mounted from zhanggen/mycentos v1: digest: sha256:9b4aaeb6d37466a92d3705b68b20c5bf27db1a21ef75456dd2433822b0bf5b60 size: 3457
5.docker push ---->Harbor仓库
[root@localhost harbor]# docker login http://192.168.226.159:80 Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@localhost harbor]# docker push 192.168.226.159:80/zhanggen/mycentos:v1 The push refers to repository [192.168.226.159:80/zhanggen/mycentos] d69483a6face: Pushed v1: digest: sha256:ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66 size: 529 [root@localhost harbor]#
6.docker pull 本地 <--------Harbor仓库
[root@localhost /]# docker rmi 192.168.226.159:80/zhanggen/mycentos:v1 Untagged: 192.168.226.159:80/zhanggen/mycentos:v1 Untagged: 192.168.226.159:80/zhanggen/mycentos@sha256:ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66 [root@localhost /]# docker pull 192.168.226.159:80/zhanggen/mycentos:v1 v1: Pulling from zhanggen/mycentos Digest: sha256:ca58fe458b8d94bc6e3072f1cfbd334855858e05e1fd633aa07cf7f82b048e66 Status: Downloaded newer image for 192.168.226.159:80/zhanggen/mycentos:v1 [root@localhost /]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.226.159/zhanggen/django_app v1 a25dd5479dd9 29 hours ago 905MB 192.168.226.159:80/zhanggen/django_app v1 a25dd5479dd9 29 hours ago 905MB zhanggen/django_app v1 a25dd5479dd9 29 hours ago 905MB zhanggen/python3.6.1 v1 20e32f2fde08 2 days ago 882MB zhanggen/centos v1 9c10a3b17a66 2 days ago 300MB 192.168.226.159/zhanggen/mycentos v1 9f38484d220f 13 days ago 202MB 192.168.226.159:80/zhanggen/mycentos v1 9f38484d220f 13 days ago 202MB centos latest 9f38484d220f 13 days ago 202MB goharbor/chartmuseum-photon v0.8.1-v1.7.4 7e2272c02339 3 weeks ago 113MB goharbor/harbor-migrator v1.7.4 968c31d07d2f 3 weeks ago 678MB goharbor/redis-photon v1.7.4 611d1ead0a28 3 weeks ago 99.7MB goharbor/clair-photon v2.0.7-v1.7.4 01090529ab14 3 weeks ago 165MB goharbor/notary-server-photon v0.6.1-v1.7.4 737518b1b943 3 weeks ago 135MB goharbor/notary-signer-photon v0.6.1-v1.7.4 495dc3326120 3 weeks ago 132MB goharbor/harbor-registryctl v1.7.4 723aed7bbf8d 3 weeks ago 102MB goharbor/registry-photon v2.6.2-v1.7.4 f4743bd7b0d9 3 weeks ago 86.7MB goharbor/nginx-photon v1.7.4 dda34e6afafe 3 weeks ago 35.9MB goharbor/harbor-log v1.7.4 bf4916eef530 3 weeks ago 81.4MB goharbor/harbor-jobservice v1.7.4 1b6a0445ae9c 3 weeks ago 84.1MB goharbor/harbor-core v1.7.4 e603b8750d26 3 weeks ago 95.6MB goharbor/harbor-portal v1.7.4 2ca1d845cafa 3 weeks ago 40.6MB goharbor/harbor-adminserver v1.7.4 5706c65d65dc 3 weeks ago 72.3MB goharbor/harbor-db v1.7.4 08d163f732f3 3 weeks ago 136MB [root@localhost /]#
7.Harbor的 后台管理页面
默认登录密码:Harbor12345
8.Harbor之间的镜像数据同步
我们不仅可以使用docker push把本地的镜像推送到Harbor这些镜像仓库。在2个Harbor镜像仓库直接也可以基于事件/手动进行镜像数据复制和同步。
9.复制规则
设置复制的目录和规则
七.docker实践总结
虽然结果只是build了3个镜像,但是我发现docker 的优势在于它可以通过镜像的方式 把Linux系统、开发环境、代码 进行了分层, 我们可以把这些镜像 想象成一个个的积木,有了这些小积木,我们就可以在 实体机、甚至虚拟机里面 灵活、搭建出 各式各样的房子,分给不同需求的人,而且构建速度 快,构建的房子还可以轻易的搬到其他地方;
docker是1种可以 灵活、快速得 构建出 多种不同得 开发、测试 环境的容器技术,Buddy.... 如果你的公司需要构建大量、不同的系统环境用docker 吧!
如果你的代码需要在很多地方快速运行起来用docker吧!
Build-----> Ship---->Run
1.Python调用Docker的API
介绍1个可用于调用Docker引擎 API 的 Python 库,它允许您执行docker命令所做的任何事情。
可以在 Python 应用程序中执行——打包镜像、管理镜像、运行容器、管理容器、管理 Swarm 等操作。
from public import RecordLoggre from docker.errors import NotFound import docker import os class DockerApi: def __init__(self, harbor_domain, username, password): # self.Client = docker.DockerClient(base_url='tcp://127.0.0.1:2375') self.Client = docker.from_env() self.username = username self.password = password self.registry_domain = harbor_domain self.registry_url = f'https://{self.registry_domain}' self.record_log = RecordLoggre() login_sigin = 0 while True: try: self.Client.login(username=self.username, password=self.password, registry=self.registry_url) except Exception as Error: self.record_log.error(str(Error), exc_info=True) login_sigin += 1 if login_sigin >= 3: raise Exception('docker auth error') else: break def build_image(self, work_space, image_url): """构建镜像并上传镜像""" os.chdir(work_space) try: build_result = self.Client.images.build(path=work_space, dockerfile='Dockerfile', tag=image_url, rm=True, nocache=True, forcerm=True, use_config_proxy=True) except Exception: self.record_log.error('创建镜像失败') raise Exception('Build image error!') else: self.record_log.info('构建镜像成功' + str(build_result)) self.push_image(image_url) self.remove_image(image_url) def get_image(self, image_url): """获取远端镜像""" image_data = None try: image_data = self.Client.images.get_registry_data(image_url) except NotFound: self.record_log.warning(f'获取镜像{image_url}失败') except Exception as Error: self.record_log.error(f'{Error}', exc_info=True) return image_data def remove_image(self, image_url): """删除本地镜像""" try: self.Client.images.remove(image_url) except Exception as Error: self.record_log.error(f'{str(Error)}删除本地镜像{image_url}失败') else: self.record_log.info(f'删除本地镜像{image_url}成功') def pull_image(self, image_url): """下载镜像""" pull_count = 1 while True: try: self.Client.images.pull(image_url) except Exception as Error: self.record_log.error(f'{str(Error)},下载镜像失败,次数{pull_count}', exc_info=True) if pull_count >= 3: raise Exception('Pull image error') else: self.record_log.info('下载镜像成功') break pull_count += 1 def push_image(self, image_url): """推送镜像""" push_count = 1 while True: try: self.Client.images.push(image_url) except Exception as Error: self.record_log.error(f'{str(Error)},推送镜像失败,次数{push_count}', exc_info=True) if push_count >= 3: raise Exception('Push image error') else: self.record_log.info('推送镜像成功') break push_count += 1 def rename(self, image_url, repository, tag): """更改存存储库""" retry_count = 1 while True: try: image_obj = self.Client.images.get(image_url) image_obj.tag(repository, tag) except Exception as Error: self.record_log.error(f'{str(Error)},更改存储库失败,次数{retry_count}', exc_info=True) if retry_count >= 3: raise Exception('更改存储库失败') else: self.record_log.info('更改存储库成功') break retry_count += 1 if __name__ == '__main__': pass
2.Python调用Harbor的API
from public import RecordLoggre from public.DockerApi import DockerApi from datetime import datetime import requests class HarborApi: def __init__(self, harbor_domain, username, password): self.harbor_domain = harbor_domain self.harbor_api = f'https://{harbor_domain}/api/v2.0' self.username = username self.password = password self.req = requests.Session() self.req.auth = (self.username, self.password) # 记录日志 self.record_log = RecordLoggre() def requests(self, url, method, **kwargs): """处理具体请求,获取错误""" req_result = {} req_func = getattr(self.req, method, 'get') try: response = req_func(url, **kwargs) status_code = response.status_code except Exception as Error: self.record_log.error(f'{str(Error)},url:{url},method:{method},kwargs:{str(kwargs)}', exc_info=True) else: if 200 <= status_code < 300: if status_code == 204: req_result = response.text else: try: req_result = response.json() except Exception: pass else: self.record_log.error(f'状态码:{status_code},url:{url},返回结果:{str(req_result)},请求参数:{str(kwargs)}') req_result = {} finally: return req_result @staticmethod def change_repo(repo): return repo.replace('/', '%252F') class HarborApiV233(HarborApi): def __init__(self, harbor_domain, username, password): super(HarborApiV233, self).__init__(harbor_domain, username, password) def list_repos(self, project, repo): """列出存储库的所有tags""" repo = self.change_repo(repo) page, page_size = 1, 20 while True: url = f'{self.harbor_api}/projects/{project}/repositories/{repo}/artifacts' req_result = self.requests(url, 'get', params={'page': page, 'page_size': page_size}) if len(req_result) > 0: for item in req_result: yield item page += 1 else: break def get_tag_list(self, project, repo): """获取镜像的tag列表""" tags_list = [] for item in self.list_repos(project, repo): for tag in item.get('tags', []): name = tag.get('name') push_time = tag.get('push_time') if name and push_time: tags_list.append((name, datetime.strptime(push_time, '%Y-%m-%dT%H:%M:%S.%fZ').timestamp())) sorted_list = sorted(tags_list, key=lambda x: x[1]) return sorted_list def get_repo_list(self, project, repo): """获取镜像的artifacts列表""" tags_list = [] for item in self.list_repos(project, repo): digest = item.get('digest') push_time = item.get('push_time') tags_list.append((digest, datetime.strptime(push_time, '%Y-%m-%dT%H:%M:%S.%fZ').timestamp())) sorted_list = sorted(tags_list, key=lambda x: x[1]) return sorted_list def tag_exist(self, project, repo, tag): """获取单个tag是否存在""" repo = self.change_repo(repo) url = f'{self.harbor_api}/projects/{project}/repositories/{repo}/artifacts/{tag}/tags' req_result = self.requests(url, 'get') if len(req_result) == 1: return True else: return False def find_last_tag(self, project, repo): """获取最新的tag""" sorted_list = self.get_tag_list(project, repo) if len(sorted_list) == 0: raise Exception(f'从{project}/{repo}没找到镜像') else: return sorted_list[-1] def del_repo_tags(self, project, repo, tag): """删除对应tag的镜像""" repo = self.change_repo(repo) url = f'{self.harbor_api}/projects/{project}/repositories/{repo}/artifacts/{tag}' self.requests(url, 'delete') def clear_image(self, project, repo): """清理镜像保留最新10个,接口调不通,使用harbor自带的清理策略""" # sorted_list = self.get_repo_list(project, repo) # for item in sorted_list[:-10]: # self.del_repo_tags(project, repo, item[0]) ... class HarborApiV122(HarborApi): """接口文档:https://github.com/goharbor/harbor/blob/release-1.2.0/docs/swagger.yaml""" def __init__(self, harbor_domain, username, password): super(HarborApiV122, self).__init__(harbor_domain, username, password) def get_tag_list(self, project, repo): """获取镜像的tag列表""" url = f'{self.harbor_api}/repositories/{project}/{repo}/tags' req_result = self.requests(url, 'get') tags_list = [] if req_result: for item in req_result: name = item.get('name') push_time = item.get('created') if name and push_time: tags_list.append((name, datetime.strptime(push_time[:19], '%Y-%m-%dT%H:%M:%S').timestamp())) sorted_list = sorted(tags_list, key=lambda x: x[1]) return sorted_list def tag_exist(self, project, repo, tag): """获取单个tag是否存在""" url = f'{self.harbor_api}/repositories/{project}/{repo}/tags/{tag}' req_result = self.requests(url, 'get') return True if req_result else False def find_last_tag(self, project, repo): """获取最新的tag""" sorted_list = self.get_tag_list(project, repo) if len(sorted_list) == 0: raise Exception(f'从{project}/{repo}没找到镜像') else: return sorted_list[-1] def del_repo_tags(self, project, repo, tag): """删除对应tag的镜像""" url = f'{self.harbor_api}/repositories/{project}/{repo}/tags/{tag}' self.requests(url, 'delete') def clear_image(self, project, repo): """清理镜像保留最新10个""" sorted_list = self.get_tag_list(project, repo) for item in sorted_list[:-10]: self.del_repo_tags(project, repo, item[0]) def local_harbor(): """本地镜像仓库""" harbor_domain, username, password = 'qa-roc.apuscn.com', 'admin', 'Harbor12345' harbor_api = HarborApiV233(harbor_domain, username, password) docker_api = DockerApi(harbor_domain, username, password) return harbor_api, docker_api def sg_harbor(): """新加坡镜像仓库""" harbor_domain, username, password = 'roc.apuscn.com', 'admin', 'Harbor12345' harbor_api = HarborApiV122(harbor_domain, username, password) harbor_api.harbor_api = f'https://{harbor_domain}/api' docker_api = DockerApi(harbor_domain, username, password) return harbor_api, docker_api if __name__ == "__main__": pass
3.Python调用Minio的API
from public import RecordLoggre from minio.commonconfig import CopySource from minio import Minio from datetime import timedelta import time import os class MinioApi: def __init__(self, minio_server, access_key, secret_key, bucket): self.minio_client = Minio( minio_server, access_key=access_key, secret_key=secret_key, secure=False ) self.bucket = bucket self.record_log = RecordLoggre() def list_objects(self, prefix): """ 获取存储对象 """ retry_count, result, object_list = 1, False, None while True: try: objects = self.minio_client.list_objects(self.bucket, prefix=prefix, recursive=True) except Exception as error: self.record_log.error(error, exc_info=True) else: if objects: result = True object_list = objects finally: retry_count += 1 if result or retry_count > 3: break if object_list: return object_list else: raise Exception('获取Minio存储对象失败!') def object_exists(self, object_key): """检测对象是否存在""" object_list = [item for item in self.list_objects(object_key)] if object_list: return True else: return False def upload_object(self, local_file, object_key): """ 上传文件,并检查是否上传成功 """ retry_count, result = 1, False while True: try: with open(local_file, 'rb') as file_data: file_stat = os.stat(local_file) etag = self.minio_client.put_object( bucket_name=self.bucket, object_name=object_key, data=file_data, length=file_stat.st_size ) except Exception as error: self.record_log.error(error, exc_info=True) else: if etag: self.record_log.info('{0} -> {1}/{2} 上传到本地minio对象存储成功'.format(local_file, self.bucket, object_key)) result = True finally: retry_count += 1 if result or retry_count > 3: break return result def download_object(self, object_key): """下载存储库对象""" if self.object_exists(object_key): try: data = self.minio_client.get_object( bucket_name=self.bucket, object_name=object_key ) file_name = object_key.split('/')[-1] with open(file_name, 'wb') as file_data: for d in data.stream(32 * 1024): file_data.write(d) except Exception as Error: raise Exception(f'下载{object_key}文件出错,{Error}') else: raise Exception(f'下载{object_key}出错,存储对象不存在') def find_last_pack(self, app_path): """获取最新的包""" object_list = self.list_objects(app_path) pack_list = \ [ { 'upload_date': int(item.object_name.split('/')[-2]), 'object_key': item.object_name } for item in object_list ] last_pack = sorted(pack_list, key=lambda x: x['upload_date'])[-1] return last_pack def copy_pack(self, target_key, source_key): """拷贝包,对应包晋级动作""" copy_result = self.minio_client.copy_object( bucket_name=self.bucket, object_name=target_key, source=CopySource(self.bucket, source_key), ) self.record_log.info(copy_result) def del_pack(self, object_key): """删除包""" try: self.minio_client.remove_object( bucket_name=self.bucket, object_name=object_key ) except Exception as Error: self.record_log.error(f'{str(Error)}', exc_info=True) def clear_pack(self, object_key): """清理包,保留最新10个""" object_list = self.list_objects(object_key) key_list = [] for item in object_list: key = item.object_name last_modified = item.last_modified timestamp = time.mktime(last_modified.timetuple()) key_list.append((key, timestamp)) sorted_list = sorted(key_list, key=lambda x: x[1]) for item in sorted_list[:-10]: self.del_pack(item[0]) def get_presigned_url(self, object_name): """获取临时下载url,1小时过期""" if self.object_exists(object_name): down_url = self.minio_client.presigned_get_object(self.bucket, object_name, expires=timedelta(hours=1)) return down_url else: raise Exception(f'生成临时下载url失败,{object_name}不存在') def zz_minio(): """郑州本地monio""" minio_server, access_key, secret_key, bucket = 'minio-registry.internalapus.com:9000', \ 'heimdall', '04919f7edbc4107b61fe6c2dfac6d7d6', 'publish-pack' return MinioApi(minio_server, access_key, secret_key, bucket) def sg_minio(): """新加坡本地monio""" minio_server, access_key, secret_key, bucket = '10.11.14.47:9000', 'heimdall', \ '04919f7edbc4107b61fe6c2dfac6d7d6', 'publish-pack' return MinioApi(minio_server, access_key, secret_key, bucket) if __name__ == '__main__': sg_minio().del_pack('deploy_prod/common-service/libra_finance/v1.0.1_d554ff18.tgz')
4.Python调用S3的API
Amazon (aws S3) 是一个公开的对象存储服务;
Web 应用程序开发人员可以使用对象存储服务,存储数字资产,包括图片、视频、音乐和文档;
S3 提供一个 RESTful API 以编程方式实现与S3对象存储服务的交互;
#!/usr/bin/python3 # -*- coding: utf-8 -*- # @file : awss3.py # @author : 基础网络-张根 # @date : 2018/05/30 # @version: 1.0 # @desc : Aws的S3对象存储服务API,依赖第三方包boto3==1.18.29 from boto3.session import Session import boto3 import time, os, logging from datetime import datetime, timedelta aws_access_key_id = "" aws_secret_access_key = "" bucket_name = "" log_path = "/var/log/awss3.log" base_data_key = f"fab-browser/mobile-web" base_data_dir = f"/home/changzhiwei/log/fab_web" # Crontab每小时执行1次去志伟的目录下查找logfile上传到客户的s3上 class AwsS3API(object): def __init__(self): auth_dict = { 'aws_access_key_id': aws_access_key_id, 'aws_secret_access_key': aws_secret_access_key } session = Session(**auth_dict) self.s3 = session.resource('s3', **auth_dict) self.client = boto3.client('s3', **auth_dict) self.bucket_name = bucket_name self.log_path = log_path # 记录日志 def record_log(self, level, message): print(message) # Creating and Configuring Logger log_format = "%(levelname)s %(asctime)s - %(message)s" logging.basicConfig(filename=self.log_path, filemode="a", # filemode有w和a,w就是写模式,a是追加模式 format=log_format, level=getattr(logging, level)) # DEBUG WARNING ERROR logger = logging.getLogger() # Testing our Logger getattr(logger, level.lower())(message) # 列出查询到的所有对象存储 def list_object(self, prefix): """ :param prefix: s3对象的key名称开头 :return: """ retry_count, result, object_list = 1, False, None while True: try: object_list = [file for file in self.s3.Bucket(self.bucket_name).objects.filter(Prefix=prefix)] except Exception as error: self.record_log("ERROR", error.__str__()) else: if object_list: result = True finally: retry_count += 1 if result or retry_count > 3: break if object_list is None: self.record_log("ERROR", "获取aws s3存储对象失败") raise Exception('获取aws s3存储对象失败') else: return object_list # 检测对象是否存在 def object_exists(self, object_key): if self.list_object(object_key): return True else: return False # 尝试3次上传文件,并检查是否上传成功 def upload_object(self, local_file, object_key): retry_count, result = 1, False while True: try: self.s3.Object(self.bucket_name, object_key).upload_file(local_file, ExtraArgs={'ACL': 'bucket-owner-full-control'}) except Exception as error: self.record_log("ERROR", "upload_object错误" + error.__str__()) else: self.record_log("DEBUG", '{0} -> {1}/{2} 上传aws s3成功'.format(local_file, self.bucket_name, object_key)) result = True finally: retry_count += 1 if result or retry_count > 3: break return result # 下载存储库对象 def download_object(self, object_key): if self.object_exists(object_key): try: self.s3.meta.client.download_file(self.bucket_name, object_key, object_key.split('/')[-1]) except Exception as Error: raise Exception(f'下载{object_key}文件出错,{Error}') else: self.record_log("DEBUG", f'下载{object_key}成功') else: raise Exception(f'下载{object_key}出错,存储对象不存在') # 删除包 def del_pack(self, object_key): try: self.client.delete_object( Bucket=self.bucket_name, Key=object_key, ) except Exception as Error: self.record_log("ERROR", f'删除包错误{str(Error)}') # 清理包,保留最新10个 def clear_pack(self, object_key): object_list = self.list_object(object_key) key_list = [] for item in object_list: key, last_modified = item.key, item.get().get('LastModified') last_stamp = time.mktime(last_modified.timetuple()) key_list.append((key, last_stamp)) sorted_list = sorted(key_list, key=lambda x: x[1]) for item in sorted_list[:-10]: self.del_pack(item[0]) # 上传browser_mobile的数据至客户的aws s3对象存 def upload_browser_mobile_data(self): two_hour_ago = datetime.now() + timedelta(hours=-2) two_hour_ago_year, two_hour_ago_month, two_hour_ago_day, two_hour_ago_hour = (two_hour_ago.year, two_hour_ago.month if two_hour_ago.month > 9 else f"0{two_hour_ago.month}", two_hour_ago.day if two_hour_ago.day > 9 else f"0{two_hour_ago.day}", two_hour_ago.hour if two_hour_ago.hour > 9 else f"0{two_hour_ago.hour}" ) time_flag = f"year={two_hour_ago_year}/month={two_hour_ago_month}/day={two_hour_ago_day}/hour={two_hour_ago_hour}" log_data_dir, log_data_key = f"{base_data_dir}/{time_flag}", f"{base_data_key}/{time_flag}" [self.upload_object(os.path.join(log_data_dir, lf), os.path.join(log_data_key, lf)) for lf in os.listdir(log_data_dir)] if os.listdir(log_data_dir) else self.record_log("ERROR", f"{log_data_dir}目录下下不存在日志文件") if __name__ == '__main__': s3_obj = AwsS3API() s3_obj.upload_browser_mobile_data()
Docker Compose
虽然可以通过Dockerfile文件很方便的定义1个单独的容器。
然而,在日常工作中我们的项目架构会设计MySQL、Nginx、Redis等各种组件搭配在一起工作。
这时我就是需要使用Docker Compose容器编排工具,对多个容器进行编排。
Docker compose和Docker swarm 都是Docker官方容器编排工具,
单不同的是Docker Compose是一个在单个服务器或主机上创建多个容器的工具。
Compose 项目是Docker官方开源的项目,负责实现对多个Docker 容器进行快速编排。
Docker Compose的使用简单基本上分为3个步骤:
- 使用Dockerfile定义单个容器的运行环境
- 使用docker-compose.yml文件定义构建当前项目所依赖的容器,这样这些容器就可以在不同的隔离环境中被运行分别运行。=
docker-compose up 开启一组容器
docker-compose down 关闭一组容器
服务(service):一个应用的容器。服务可以存着多个。
项目(project):由一组相互之间关联的容器,组成的一个完整业务单元。 项目在docker-compose.yml中进行定义。
[root@VM-0-5-centos ~]# curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:06 --:--:-- [root@VM-0-5-centos ~]# ls -l /usr/local/bin/docker-compose -rw-r--r-- 1 root root 16168192 Jun 9 10:31 /usr/local/bin/docker-compose [root@VM-0-5-centos ~]# chmod +x /usr/local/bin/docker-compose [root@VM-0-5-centos ~]# docker- docker-compose docker-init docker-proxy [root@VM-0-5-centos ~]# docker- docker-compose docker-init docker-proxy [root@VM-0-5-centos ~]# docker-compose -v docker-compose version 1.24.1, build 4667896b [root@VM-0-5-centos ~]#
Docker-compose.yml
Docker-compose.yml是来定义当前项目的文件,它遵循一些语法格式。
version: "3.0" #docker-compose的版本号
services: #一组相互之间有业务联系的服务组
protainer:
image: :portainer/portainer
container_name: protainer_container
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /protainer:protainer
networks:
- api
ports:
- "8000:8000"
- "9000:9000"
buget-api:
build: #直接把Dockerfile打包成镜像并运行
context: ./ #指定Dockerfile所在的目录
dockerfile: Dockerfile #Dockerfile的文件名称
container_name: buget-apicontainer #容器名称
ports:
- 8090:8090""
networks:
- apai-network
depends_on:
- nginx
nginx: #服务
image: nginx #使用的镜像
ports: #使用的端口
- "80:80"
volumes: #完成宿主机和容器目录卷的映射
- zhanggen:/zhanggen #宿主机的目录
volumes:
zhanggen:
external:
flase
在docker-compose.yml引用环境变量
[root@VM-0-5-centos docker]# cat .env nginx=nginx
[root@VM-0-5-centos docker]# cat docker-compose.yml version: "3.0" #docker-compose的版本号 services: #一组相互之间有业务联系的服务组 nginx: #服务 image: ${nginx} #使用的镜像 ports: #使用的端口 - "80:80" volumes: #完成宿主机和容器目录卷的映射 - zhanggen:/zhanggen #宿主机的目录 volumes: zhanggen: [root@VM-0-5-centos docker]#
Docker-compose
我使用Dockerfile的mutistage-build语法定义了1个可以被多个web项目重复FROM的,web开发环境。
FROM python:3.7.6 AS pure_python_env MAINTAINER franplk LABEL version=1.0 description=HunanModelSystem FROM pure_python_env AS python_site_package WORKDIR /root COPY requirements.txt requirements.txt RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple FROM python_site_package AS uwsgi_builder WORKDIR /root COPY uwsgi/uwsgi-2.0.19.1 uwsgi-2.0.19.1 RUN mv uwsgi-2.0.19.1 uwsgi WORKDIR /root/uwsgi RUN make && ln -s /root/uwsgi/uwsgi /usr/bin/uwsgi EXPOSE 8099 WORKDIR /root CMD uwsgi --ini /${PROJECT_NAME}/devops/docker/uwsgi/uwsgi.ini
我使用Docker-compose定义了1个L+N+M+P(Python)的web运行环境。
version: "3.0" #docker-compose的版本号 services: #一组相互之间有业务联系的服务组 mysql: #MySQL服务 environment: TZ: "Asia/Shanghai" MYSQL_ROOT_PASSWORD: "weike@2020" MYSQL_USER: 'zhanggen' MYSQL_PASS: 'weike@2020' image: mysql:5.7 container_name: BudgetAPIMySQLContainer #容器名称 restart: always volumes: #MySQL数据存储目录 - "./mysql/data:/var/lib/mysql" #MySQL配置文件 - "./mysql/conf/my.cnf:/etc/my.cnf" #MySQL初始化执行 - "./mysql/init:/docker-entrypoint-initdb.d/" ports: - "3304:3303" networks: - budget_api nginx: #nginx服务 container_name: BudgetAPINginxContainer #容器名称 image: nginx:1.21.0 #使用的镜像 environment: - TZ=Asia/Shanghai ports: #使用的端口 - "8088:8080" - "444:443" extra_hosts: - "uwsgi_host:115.159.55.242" volumes: #完成宿主机和容器目录卷的映射 - ./nginx/config/nginx.conf:/etc/nginx/nginx.conf #配置 - ./nginx/log:/var/log/nginx #日志 - ../../code/resources/static:/static #静态文件 networks: - budget_api budget_api: #flask进程 build: #直接把Dockerfile打包成镜像并运行 context: "./" #指定Dockerfile所在的目录 dockerfile: Dockerfile #Dockerfile的文件名称 image: budget_api:v1 extra_hosts: - "mysql_host:115.159.55.242" container_name: BudgetAPIProjectContainer #容器名称 environment: #设置容器的运行模式 - PROJECT_NAME=budget-api #Dockerfile中使用的环境变量 - RUN_ENV=release #项目启动时选择的运行环境 volumes: - ../../../budget-api:/budget-api/ - /mingde/projects/models/model_similarity.bin:/root/model_similarity.bin ports: - "8091:8099" networks: - budget_api depends_on: - mysql - nginx networks: budget_api: driver: bridge
Mysql在容器中的备份和恢复
[root@VM-0-5-centos backup]# pwd /mingde/projects/HunanModel/devops/docker/mysql/backup [root@VM-0-5-centos backup]# docker exec MySQLContainer /usr/bin/mysqldump -u root --password=Password db_hunan_model > ./db_hunan_model.sql mysqldump: [Warning] Using a password on the command line interface can be insecure. [root@VM-0-5-centos backup]# cat ./db_hunan_model.sql | docker exec -i MySQLContainer /usr/bin/mysql -u root --password=Password db_hunan_model mysql: [Warning] Using a password on the command line interface can be insecure. [root@VM-0-5-centos backup]#
Docker问题汇总
1.宿主机无法访问Docker网络
增加sudo权限
vim /etc/sudoers
root ALL=(ALL) ALL
appuser ALL=(ALL) NOPASSWD: ALL
先关闭docker引擎
service docker stop
关闭docker0的网卡
ip link set dev docker0 down
删除docker0网桥
brctl delbr docker0
重建docker0网桥
brctl addbr docker0
设置IP段
ip addr add 172.17.42.2/24 dev docker0
启动docker0网桥
ip link set dev docker0 up
重启docker引擎
service docker start
测试
"Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "c2be63b76bb888ec4bcddfe9c7c7ff9267b721c31cd92c8f114beab390082b84", "EndpointID": "8ae0707da7f4f5d575e60d0d2cd0be8a39334e1b68f83fbde1621317cc9d51f7", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ] [root@zhanggen mingde]# ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.061 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.058 ms 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.057 ms