Docker基本技能之程序开发基本够用系列
-
Docker能做什么
简化配置,代码流水线管理,提高开发效率,隔离应用,整合服务器,调试能力,多租户,快速部署涉及技术:
发布计划,持续集成,持续发布,持续测试,持续监控,持续改进版本管理,自动化,部署,监控 -
Docker
容器解决开发人员与运维之间的沟通,矛盾
是devops的最佳解决方案。
安装:
https://yq.aliyun.com/articles/701709
centos 下卸载docker:
yum list installed | grep docker
yum remove docker-ce.x86_64 d docker-ce-cli.x86_64 -y
rm -rf /var/lib/docker //删除镜像
容器:对软件和其依赖的标准化打包,应用之间相互隔离,共享同一个os kernel,可以运行在很多主流的操作系统上
容器是app层面的隔离,虚拟化是物理资源层面的隔离
-
docker-machine
快速创建docker容器环境 -
docker架构
三个核心:镜像(Image),容器(Container),仓库(Repository)
client(build pull run) – docker host(containers, images) --registry
底层技术支持:
Namespaces:做隔离pid,net,ipc,mnt,uts
Control group:做资源限制
Union file systems:Container和image的分层
- docker image
文件和meta data的集合(root filesystem)
分层的,并且每一层都可以添加改变删除文件,成为一个新的image
不同的image可以共享相同的layer
image本身是read-only的
命令:
docker search [mysql] 搜索如mysql镜像文件
docker image ls
docker pull ubuntu:14.04
docker pull bitnami/wordpress
- DIY docker image
附:
useradd -m username // -p 密码
passwd 密码
userdel -r username //vipw 命令可以在文件中直接删除某一用户,也要把群删掉 groupdel
groupadd docker
gpasswd -a username groupname //username添加到组groupname, -d 是删除
新的用户下
mkdir hello-world
vim hello.c
gcc -static hello.c -o hello
./hello.c
vim Dockerfile 编写文件
内容如下:
FROM scratch # scratch 是内置关键词,并不是一个真实存在的镜像。 FROM scratch 会使用一个完全干净的文件系统,不包含任何文件。
ADD hello / # 执行的是将当前目录下的 hello 添加到 容器镜像的 / 路径下。
CMD ["/hello"]
docker build -t rose/hello-world . #其中 . 指当前路径下的文件
docker image ls
docker run rose/hello-world
- Container
通过Image创建(copy)
在Image layer之上建立一个container layer(可读写)
类别面向对象:类和实例
Image负责的app的存储和分发,container负责运行app
命令:
docker container ls -a
docker run -it centos //-it 交互式运行
docker run -d redis //-d 后台运行
docker ps //查看运行的容器
docker container stop 容器名 //停止容器
删除所有容器:
docker rm $(docker container ls -aq)
批量停止在运行中的容器
docker ps -a | grep 'Up' | awk '{print $1}'| xargs docker container stop
批量删除Exited状态的容器
docker ps -a | grep 'Exited' | awk '{print $1}'| xargs docker container rm
批量删除name为none的image
docker image ls | grep none | awk '{print $3}' | xargs docker image rm
-
Dockerfile语法
FROM centos # 使用base image 尽量使用官方imageLABEL maintainer=“rose@gmail.com”
LABEL version=“1.0”
LABEL description=“this is description”
这个LABEL Metadata不可少RUN yum update && yum install -y vim
python-dev # 反斜线换行,为了避免无用分层,尽量合并多条命令WORKDIR /root # 相当于linux cd 到某一目录,尽量使用绝对目录
ADD hello / # 将hello 加到/下
ADD test.tar.gz / # 添加到根目录并解压
WORKDIR /root
ADD hello test/ # /root/test/hello
WORKDIR /root
COPY hello test/
大部分COPY优先于ADD,ADD还有解压功能,添加运程文件/目录请使用curl或者wget\
ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}"
&& rm -rf /var/lib/apt/lists/* #引用常量
VOLUME and EXPOSE 用于存储和网络
CMD and ENTRYPOINT
RUN vs CMD and ENTRYPOINT
RUN :执行命令并创建新的ImageLayer,创建镜像的时执行
CMD:设置容器启动后默认执行的命令和参数,每次容器启动都会执行
ENTRYPOINT:设置容器启动时运行的命令
shell格式:
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
Exec格式:
RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"] # "/bin/bash" 可以执行$之类的变量
CMD:
容器启动时默认执行的命令
若docker run制定了其他命令,CMD命令被忽略
若定义了多个CMD, 只有最后一个会执行
ENTRYPOINT:
让容器以应用程序或服务的形式运行
不会被忽略,一定会执行
-
push到docker hub
⚠️先注册hub账户 https://hub.docker.com/
1.创建Dockerfile
2.构建Image, docker build -t hh .
3.打标签Image, docker tag 53427d838b8a cc/hh:1.10 # cc为docker hub id
4.登录hub.docker, docker login
5.上传Image, docker push cc/hh # 若仓库已存在push的名字要与此一致 -
项目容器化
python3安装
链接:https://blog.csdn.net/u013214212/article/details/81540840
容器起到隔离作用,代替在主机中多个venv或虚拟机
Dockerfile
FROM qzkc/python2.7:v1
LABEL maintainer="ccbp"
RUN pip install flask
COPY app.py /app/ # 这里app.py 和Dockerfile 同一路径下
WORKDIR /app
EXPOSE 5000
CMD ["python","app.py"]
-
Docker Network
单机:Bridge Network,Host Network,None Network
多机:Overlay Network网络:ping网络连通性,telnet验证服务的可用性
Network space:
docker run -d --name test1 busybox /bin/sh -c "while true;do sleep 3600;done"
docker run -d --name test2 busybox /bin/sh -c "while true;do sleep 3600;done"
查看容器ip
docker exec 065c141a1fe5 ip a
进入到容器,并ping操作
docker exec -it 065c141a1fe5 /bin/bash
ping x.x.x.x
可以发现两个容器网络互通vepath
连接两个容器命名空间容器运行时报错,WARNING: IPv4 forwarding is disabled. Networking will not work.
/usr/lib/sysctl.d/00-system.conf 文件添加 net.ipv4.ip_forward=1Bridge:
docker network ls
//查看当前docker有哪些网络docker network inspect 9bb20d27fa23
//bridge的网络idyum install bridge-utils
brctl show 命令查看桥接网可以看到容器连接到这个bridge网络接口docker0
容器访问网络(外网)路径:
Internet – eth0 – NAT – docker0 --[container1, container2…]NAT 使用iptables 实现技术
自定义网桥:
brctl addbr br0
//定义br0网桥容器之间link:
场景:web应用容器 与 数据库容器的连接,怎么方便找到并访问docker run -d --name test2 --link test1 busybox /bin/sh -c "while true;do sleep 3600;done"
进入到容器中:
docker exec -it test2 /bin/sh
可以ping test1 直接写容器名字,就可以找到这个容器(这样可以不知道容器的ip,通过名字也可访问)
–link 是单向的,这个方式却用的不多新建bridge:
docker network create -d bridge my-bridge
//新建my-bridge
docker network ls
查看
brctl show
创建test3 链接到my-bridge 网络接口
docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true;do sleep 3600;done"
docker network ls
docker network inspect [NETWORK ID]
//查看docker network connect my-bridge test2
//可以将my-bridge连接到test2容器上那么这时 my-bridge 上的test3 test2 之间可以通过ping 容器名的方式 相互之间可以连通。
容器端口映射:-p
docker run --name web -d nginx docker ps docker network ls docker network inspect 9bb20d27fa23 //默认连接到bridge上 telnet 172.17.0.4 80 curl http://172.17.0.4:80 //访问nginx网页的内容 把这个80端口映射到本地上, docker rm web docker run --name web -d -p 80:80 nginx //按顺序是容器80映射到本地80端口
host和none
docker run -d --name test1 --network none busybox /bin/sh -c "while true;do sleep 3600;done"
docker network inspect none
//创建这样的容器看到只有本地ip, 使用场景 比如是存密码 不希望外界访问。docker run -d --name test1 --network host busybox /bin/sh -c "while true;do sleep 3600;done"
//这个容器和主机共享网络命名空间,可能发生端口冲突
复杂案例:
Q: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by ‘NewConnectionError(’<pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x7fe388ab2550>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution’,)’: /simple/redis/
A: 重启 service docker restart --!
先启动redis
docker run -d --name redis redis
docker run -d --link redis --name flask-redis -e REDIS_HOST=redis flask-redis
docker exec -it flask-redis /bin/sh # 命令行访问
env # 查看变量
curl 127.0.0.1:5000 容器内访问
docker run -d --link redis -p 5000:5000 --name flask-redis -e REDIS_HOST=redis flask-redis
curl 127.0.0.1:80 本地访问
多机通信:
vxlan协议 虚拟可扩展的局域网。它是一种 overlay 技术,通过三层的网络来搭建虚拟的二层网络。
链接:https://cizixs.com/2017/09/25/vxlan-protocol-introduction/
需要依赖一个etcd 工具
运维之美etcd 链接:https://draveness.me/etcd-introduction
了解overlay 网络的技术在docker的通信:
链接:https://github.com/docker/labs/blob/master/networking/concepts/06-overlay-networks.md
-
Docker持久化部署与存储
在容器中的创建的数据 文件,需要保存,需要Volume。
docker解决方案:
1. 基于本地文件系统的Volume,可以执行Docker create或Docker run时,-v 参数将主机目录作为容器的数据卷。
2. 基于plugin的Volume, 支持第三方的存储方案,如NAS, awsVolume的类型:
1.受管理的data Volume,由docker后台自动创建
2.绑定挂载的Volume, 具体挂在位置可以由用户指定。数据持久化:Data Volume
docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
附:通过docker logs [mysql_image_name|container_name]
查看日志,找到密码,以及相关错误日志信息等
docker volume ls
docker volume inspectvolume 起别名:
docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql # -v mysql:/var/lib/mysql 分别是volume别名和映射到本地路径数据持久化:Bind Mouting
docker run -v /home/aaa:/root/aaa
# 指定本地目录与容器目录关联docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web nginx
#当前路径下文件与容器路径下映射 并文件同步
附:有些场景非常方便文件查看 程序调试场景:wordpress网站
docker run -d --name mysql -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress mysql
docker run -d -e WORDPRESS_DB_HOST=mysql:3306 --link mysql -p 8080:80 wordpress
附:将配置文件复制到 docker容器,docker cp IMAGE_ID:/etc/mysql/my.cnf /etc/mysql/conf/
-
docker-compose
场景:
要从Dockerfile build image 或者Dockerhub 拉取image
要创建多个container
要管理这些container(启动停止删除)Docker Compose “批处理”
Docker Compose 是一个工具
可以通过yml文件定义多容器的docker应用
通过一条命令就可以根据yml文件的定义去创建或管理这么多的容器centos中安装docker-compose:
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
>
docker-compose version 1.22.0, build f46880fedocker-compse.yml
三大概念:Services、Networks、VolumesServices:
一个service代表一个container,这个container可以从dockerhub的image来创建,或者本地的Dockerfile build出来的image来创建
service的启动类似docker run,可以给其指定network和volume, 所以可以给service指定network和Volume的引用services: worker: build: ./worke links: - db - redis networks: - back-iter # 相当于 docker network create -d bridge back-iter volumes: - "db-data:/var/lib/postgresql/data" # 相当于 docker volume create db-data
使用:
docker-compose.yml 文件
docker-compose up
启用当前的docker-compose.yml文件案例:
flask-hello-world/ 文件下创建 app.py docker-compose.yml Dockerfile 三个文件docker-compose.yml内容:
version: "3" services: redis: image: redis web: build: context: . dockerfile: Dockerfile ports: - 8080:5000 environment: REDIS_HOST: redis
Dockerfile内容:
FROM qzkc/python2.7:v1 LABEL maintainer="ccbp" RUN pip install flask redis COPY . /app/ WORKDIR /app EXPOSE 5000 CMD ["python","app.py"] ```
flask app.py 内容如下:
from flask import Flask
import redis
import os
import socket
app = Flask(__name__)
redis = redis.Redis(host=os.environ.get('REDIS_HOST','127.0.0.1'),port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return "hello docker I have been seen %s times and my hostname is %s.\n" % (redis.get('hits'),socket.gethostname())
if __name__ == '__main__':
app.run(host="0.0.0.0",port=5000,debug=True)
负载和扩展规模:
去掉docker-compose.yml 的 ports: ,docker-compose up , docker-compose up --scale web=3 -d ,发现有三个app.py 实现水平扩展web
docker-compose.yml 文件添加:
version: “3”
services:
redis:
image: redis
web:
build:
context: .
dockerfile: Dockerfile
environment:
REDIS_HOST: redis
lb:
image: dockercloud/haproxy
links:
- web
ports:
- 8080:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
增加高可用负载均衡代理,再docker-compose ps 查看,web实现了水平扩展。
curl 127.0.0.1:8080 来访问,发现调用了不同的web容器应用。实现了负载均衡